From e1c85ce94dc5a757a643bba076c7f5ea193f7e3f Mon Sep 17 00:00:00 2001
From: fuyongxin <110568259@qq.com>
Date: Wed, 03 Jun 2026 16:22:39 +0800
Subject: [PATCH] 初始化
---
sgd-ui/.env.development | 11
sgd-ui/src/views/system/post/index.vue | 309
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm | 0
sgd-ui/src/assets/icons/svg/eye-open.svg | 0
sgd-ui/src/assets/images/login-background.jpg | 0
sgd-ui/src/utils/generator/drawingDefault.js | 37
sgd-ui/src/views/system/dept/index.vue | 392
sgd-modules/sgd-job/src/main/resources/logback.xml | 74
sgd-ui/src/assets/icons/svg/number.svg | 0
sgd-modules/sgd-gen/src/main/resources/vm/vue/index-tree.vue.vm | 565 +
sgd-ui/src/views/system/role/selectUser.vue | 136
sgd-ui/src/views/system/user/profile/resetPwd.vue | 70
sgd-ui/src/layout/components/Sidebar/index.vue | 57
sgd-ui/src/assets/icons/svg/guide.svg | 0
sgd-ui/src/utils/index.js | 390
sgd-ui/src/assets/icons/svg/monitor.svg | 2
sgd-ui/src/directive/index.js | 0
sgd-ui/src/components/Crontab/second.vue | 0
sgd-ui/package.json | 71
sgd-ui/src/assets/icons/svg/password.svg | 0
sgd-ui/src/directive/permission/hasRole.js | 28
sgd-ui/src/api/tool/gen.js | 76
sgd-ui/src/views/redirect.vue | 12
sgd-ui/src/api/menu.js | 9
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm | 0
sgd-ui/src/plugins/auth.js | 60
sgd-ui/src/views/system/role/index.vue | 605 +
sgd-ui/src/assets/icons/svg/money.svg | 0
sgd-ui/src/assets/icons/svg/validCode.svg | 0
sgd-ui/src/layout/components/Sidebar/Logo.vue | 95
sgd-ui/src/api/monitor/jobLog.js | 26
sgd-ui/src/assets/icons/svg/chart.svg | 0
sgd-ui/src/assets/icons/svg/size.svg | 0
sgd-ui/public/robots.txt | 2
sgd-ui/src/api/login.js | 71
sgd-ui/src/assets/icons/svg/search.svg | 0
sgd-ui/src/assets/icons/svg/druid.svg | 0
sgd-ui/src/layout/components/TopBar/index.vue | 0
sgd-ui/src/store/modules/settings.js | 52
sgd-ui/public/index.html | 208
sgd-ui/src/assets/icons/svg/example.svg | 0
sgd-ui/src/components/Pagination/index.vue | 113
sgd-ui/bin/build.bat | 12
sgd-ui/src/assets/icons/svg/drag.svg | 0
sgd-ui/src/assets/icons/svg/input.svg | 0
sgd-ui/src/assets/icons/svg/nested.svg | 0
sgd-ui/src/utils/passwordRule.js | 0
sgd-ui/src/assets/icons/svg/github.svg | 0
sgd-ui/src/utils/dict/index.js | 33
sgd-ui/src/api/system/menu.js | 69
sgd-ui/src/assets/icons/svg/log.svg | 0
sgd-ui/src/layout/components/index.js | 5
sgd-ui/src/components/Crontab/hour.vue | 0
sgd-ui/src/assets/icons/svg/switch.svg | 0
sgd-ui/src/views/system/menu/index.vue | 533 +
sgd-ui/src/layout/components/Sidebar/SidebarItem.vue | 99
sgd-ui/src/views/monitor/job/detail.vue | 0
sgd-ui/src/components/Editor/index.vue | 297
sgd-ui/src/assets/icons/svg/message.svg | 0
sgd-ui/src/assets/icons/svg/job.svg | 0
sgd-ui/src/components/TreePanel/index.vue | 0
sgd-ui/src/assets/icons/svg/textarea.svg | 0
sgd-ui/src/assets/icons/svg/people.svg | 0
sgd-ui/src/plugins/tab.js | 75
sgd-ui/src/assets/icons/svg/excel.svg | 0
sgd-ui/src/assets/icons/svg/logininfor.svg | 0
sgd-ui/src/assets/styles/sidebar.scss | 321
sgd-modules/sgd-gen/src/main/resources/logback.xml | 74
sgd-ui/src/assets/icons/svg/swagger.svg | 0
sgd-ui/src/store/index.js | 27
sgd-ui/src/components/Hamburger/index.vue | 44
sgd-ui/src/assets/images/pay.png | 0
sgd-ui/.editorconfig | 22
sgd-modules/sgd-system/src/main/resources/logback.xml | 74
sgd-ui/src/assets/404_images/404_cloud.png | 0
sgd-ui/src/assets/icons/svg/radio.svg | 0
sgd-ui/src/views/system/user/index.vue | 467 +
sgd-ui/src/assets/styles/ruoyi.scss | 484 +
sgd-ui/src/views/system/operlog/detail.vue | 0
sgd-ui/src/assets/icons/svg/checkbox.svg | 0
sgd-ui/src/assets/icons/svg/online.svg | 0
sgd-ui/src/assets/styles/variables.scss | 39
sgd-ui/.env.staging | 12
sgd-ui/src/assets/styles/transition.scss | 49
sgd-ui/src/components/DictTag/index.vue | 93
sgd-ui/src/utils/jsencrypt.js | 30
sgd-ui/src/assets/icons/svg/edit.svg | 0
sgd-ui/src/api/monitor/job.js | 71
sgd-ui/src/assets/styles/index.scss | 178
sgd-ui/src/assets/icons/svg/qq.svg | 0
sgd-ui/src/views/tool/gen/genInfoForm.vue | 336
sgd-ui/src/assets/icons/svg/international.svg | 0
sgd-ui/public/styles/theme-chalk/index.css | 0
sgd-ui/src/assets/images/dark.svg | 39
sgd-ui/build/index.js | 35
sgd-ui/src/views/tool/build/TreeNodeDialog.vue | 148
sgd-ui/src/views/tool/gen/index.vue | 0
sgd-ui/src/assets/icons/svg/server.svg | 0
sgd-ui/src/assets/icons/svg/exit-fullscreen.svg | 0
sgd-ui/src/directive/dialog/dragHeight.js | 34
sgd-ui/src/assets/icons/svg/form.svg | 0
sgd-ui/src/assets/icons/svg/zip.svg | 0
sgd-ui/src/api/system/logininfor.js | 33
sgd-ui/src/assets/icons/svg/education.svg | 0
sgd-ui/src/store/modules/tagsView.js | 275
sgd-ui/src/assets/icons/svg/skill.svg | 0
sgd-ui/src/directive/permission/hasPermi.js | 28
sgd-ui/src/layout/components/Navbar.vue | 254
sgd-ui/src/views/tool/build/IconsDialog.vue | 123
sgd-ui/src/utils/scroll-to.js | 58
sgd-modules/sgd-gen/src/main/resources/vm/js/api.js.vm | 44
sgd-ui/babel.config.js | 13
sgd-ui/src/api/system/dept.js | 61
sgd-ui/src/components/Crontab/year.vue | 0
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/view.vue.vm | 0
sgd-ui/src/assets/404_images/404.png | 0
sgd-ui/src/layout/components/Sidebar/FixiOSBug.js | 25
sgd-ui/src/router/index.js | 189
sgd-ui/src/assets/icons/svg/bug.svg | 0
sgd-modules/sgd-gen/src/main/resources/banner.txt | 10
sgd-ui/src/views/monitor/job/index.vue | 471 +
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index.vue.vm | 0
sgd-ui/src/assets/icons/svg/upload.svg | 0
sgd-ui/src/assets/icons/svg/date-range.svg | 0
sgd-ui/src/components/SizeSelect/index.vue | 55
sgd-modules/sgd-system/src/main/resources/banner.txt | 10
sgd-ui/src/components/ParentView/index.vue | 0
sgd-ui/src/layout/components/AppMain.vue | 140
sgd-ui/src/components/Crontab/day.vue | 0
sgd-ui/src/assets/icons/svg/shopping.svg | 0
sgd-ui/src/utils/dict/DictData.js | 13
sgd-ui/src/assets/icons/svg/system.svg | 2
sgd-ui/src/store/modules/dict.js | 50
sgd-ui/src/assets/icons/svg/dict.svg | 0
sgd-ui/src/components/ImagePreview/index.vue | 0
sgd-ui/src/permission.js | 70
sgd-ui/src/components/FileUpload/index.vue | 261
sgd-ui/src/views/monitor/online/index.vue | 118
sgd-modules/sgd-gen/src/main/resources/vm/vue/view.vue.vm | 0
sgd-ui/src/components/DictData/index.js | 49
sgd-ui/src/utils/generator/render.js | 126
sgd-ui/src/views/system/dict/index.vue | 375
sgd-ui/src/assets/icons/index.js | 9
sgd-ui/src/components/IconSelect/index.vue | 104
sgd-ui/vue.config.js | 129
sgd-ui/src/App.vue | 20
sgd-modules/sgd-job/src/main/resources/banner.txt | 10
sgd-ui/src/utils/dict/Dict.js | 82
sgd-ui/src/utils/ruoyi.js | 0
sgd-ui/src/store/modules/app.js | 66
sgd-ui/src/components/ThemePicker/index.vue | 0
sgd-ui/src/layout/mixin/ResizeHandler.js | 45
sgd-ui/src/views/dashboard/PanelGroup.vue | 181
sgd-ui/src/components/Breadcrumb/index.vue | 102
sgd-ui/src/plugins/cache.js | 79
sgd-ui/src/utils/permission.js | 47
sgd-modules/sgd-gen/src/main/resources/vm/java/mapper.java.vm | 91
sgd-ui/src/assets/images/light.svg | 39
sgd-ui/src/plugins/download.js | 45
sgd-ui/src/assets/icons/svg/time.svg | 0
sgd-ui/src/utils/dict/DictConverter.js | 17
sgd-ui/src/components/SvgIcon/index.vue | 61
sgd-ui/src/assets/icons/svg/dashboard.svg | 0
sgd-ui/src/assets/icons/svg/phone.svg | 0
sgd-ui/src/store/modules/user.js | 145
sgd-ui/src/views/tool/build/index.vue | 775 +
sgd-ui/src/layout/components/HeaderNotice/DetailView.vue | 0
sgd-ui/src/layout/components/IframeToggle/index.vue | 33
sgd-ui/src/assets/icons/svg/color.svg | 0
sgd-ui/src/views/dashboard/LineChart.vue | 135
sgd-ui/bin/run-web.bat | 12
sgd-ui/src/views/system/notice/ReadUsers.vue | 0
sgd-ui/src/components/Crontab/week.vue | 0
sgd-ui/src/utils/generator/css.js | 18
sgd-ui/src/assets/icons/svg/wechat.svg | 0
sgd-ui/src/assets/icons/svg/tool.svg | 0
sgd-ui/src/api/system/config.js | 60
sgd-ui/src/utils/errorCode.js | 6
sgd-ui/src/views/login.vue | 223
sgd-ui/src/assets/icons/svgo.yml | 22
sgd-ui/src/assets/icons/svg/icon.svg | 0
sgd-ui/src/plugins/modal.js | 83
sgd-ui/src/components/RuoYi/Doc/index.vue | 0
sgd-ui/src/components/RightToolbar/index.vue | 0
sgd-ui/src/assets/icons/svg/user.svg | 0
sgd-ui/src/views/dashboard/mixins/resize.js | 56
sgd-ui/src/views/system/role/authUser.vue | 199
sgd-ui/src/views/system/user/view.vue | 0
sgd-ui/src/components/PanThumb/index.vue | 141
sgd-ui/src/assets/icons/svg/bell.svg | 0
sgd-ui/src/plugins/index.js | 20
sgd-ui/src/views/error/404.vue | 233
sgd-ui/src/assets/styles/element-variables.scss | 31
sgd-gateway/src/main/resources/logback.xml | 0
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/view.vue.vm | 0
sgd-ui/src/views/tool/build/CodeTypeDialog.vue | 106
sgd-ui/src/directive/dialog/drag.js | 0
sgd-ui/src/utils/generator/js.js | 235
sgd-ui/src/components/ExcelImportDialog/index.vue | 0
sgd-ui/src/store/getters.js | 23
sgd-ui/src/views/tool/gen/basicInfoForm.vue | 60
sgd-ui/README.md | 30
sgd-ui/src/assets/icons/svg/tree-table.svg | 0
sgd-ui/src/store/modules/lock.js | 0
sgd-ui/src/utils/request.js | 153
sgd-ui/src/views/tool/gen/importTable.vue | 120
sgd-ui/src/utils/generator/config.js | 438 +
sgd-ui/src/layout/components/InnerLink/index.vue | 47
sgd-ui/src/components/RuoYi/Git/index.vue | 0
sgd-ui/src/views/index_v1.vue | 98
sgd-ui/src/views/lock.vue | 0
sgd-ui/src/api/system/dict/data.js | 52
sgd-ui/src/assets/icons/svg/cascader.svg | 0
sgd-ui/src/settings.js | 66
sgd-ui/src/assets/icons/svg/tab.svg | 0
sgd-ui/src/assets/401_images/401.gif | 0
sgd-ui/src/views/error/401.vue | 88
sgd-ui/src/assets/icons/svg/button.svg | 0
sgd-ui/src/assets/icons/svg/row.svg | 0
sgd-ui/src/layout/components/Sidebar/Link.vue | 43
sgd-ui/src/assets/icons/svg/tree.svg | 0
sgd-ui/.env.production | 8
sgd-modules/sgd-gen/src/main/resources/vm/sql/sql.vm | 22
sgd-ui/src/assets/icons/svg/link.svg | 0
sgd-ui/src/assets/icons/svg/table.svg | 0
sgd-ui/src/utils/dict/DictMeta.js | 38
sgd-modules/sgd-file/src/main/resources/logback.xml | 74
sgd-ui/.gitignore | 23
sgd-ui/src/assets/styles/mixin.scss | 66
sgd-modules/sgd-gen/src/main/resources/vm/java/controller.java.vm | 115
sgd-modules/sgd-gen/src/main/resources/vm/java/domain.java.vm | 105
sgd-ui/src/assets/icons/svg/theme.svg | 0
sgd-ui/src/api/system/post.js | 44
sgd-ui/src/utils/generator/icon.json | 0
sgd-ui/src/layout/components/Copyright/index.vue | 0
sgd-modules/sgd-gen/src/main/resources/vm/ts/api.ts.vm | 0
sgd-modules/sgd-gen/src/main/resources/vm/java/service.java.vm | 61
sgd-ui/src/assets/icons/svg/nacos.svg | 0
sgd-ui/src/utils/validate.js | 119
sgd-ui/src/api/monitor/online.js | 18
sgd-ui/src/assets/icons/svg/time-range.svg | 0
sgd-ui/src/components/Crontab/index.vue | 0
sgd-ui/src/assets/logo/logo.png | 0
sgd-ui/src/views/dashboard/RaddarChart.vue | 116
sgd-ui/src/assets/styles/element-ui.scss | 92
sgd-ui/src/layout/components/TagsView/ScrollPane.vue | 149
sgd-ui/src/assets/icons/svg/sentinel.svg | 0
sgd-modules/sgd-gen/src/main/resources/vm/xml/mapper.xml.vm | 140
sgd-ui/src/assets/icons/svg/select.svg | 0
sgd-ui/src/assets/icons/svg/email.svg | 0
sgd-ui/src/store/modules/permission.js | 122
sgd-ui/src/views/system/notice/index.vue | 332
sgd-ui/src/views/index.vue | 1099 ++
sgd-ui/src/views/system/user/profile/userInfo.vue | 88
sgd-ui/src/assets/icons/svg/component.svg | 0
sgd-ui/src/assets/icons/svg/documentation.svg | 0
sgd-modules/sgd-gen/src/main/resources/vm/java/serviceImpl.java.vm | 169
sgd-ui/src/views/system/user/profile/index.vue | 0
sgd-modules/sgd-gen/src/main/resources/vm/ts/type.ts.vm | 0
sgd-ui/src/assets/icons/svg/404.svg | 0
sgd-ui/src/assets/icons/svg/rate.svg | 0
sgd-ui/src/utils/auth.js | 29
sgd-ui/src/api/system/dict/type.js | 60
sgd-ui/src/views/register.vue | 214
sgd-ui/bin/package.bat | 12
sgd-ui/src/components/Screenfull/index.vue | 57
sgd-ui/src/views/system/user/profile/userAvatar.vue | 184
sgd-ui/src/views/tool/gen/editTable.vue | 230
sgd-ui/public/favicon.ico | 0
sgd-ui/src/assets/icons/svg/eye.svg | 0
sgd-ui/src/utils/dict/DictOptions.js | 51
sgd-ui/src/assets/styles/btn.scss | 99
sgd-modules/sgd-file/src/main/resources/banner.txt | 10
sgd-ui/src/components/iFrame/index.vue | 0
sgd-ui/src/assets/icons/svg/more-up.svg | 0
sgd-ui/src/api/system/role.js | 119
sgd-ui/src/views/tool/build/RightPanel.vue | 946 ++
sgd-ui/src/views/dashboard/BarChart.vue | 102
sgd-ui/src/views/system/dict/detail.vue | 0
sgd-ui/src/views/system/dict/data.vue | 402
sgd-ui/src/views/system/user/authRole.vue | 123
sgd-modules/sgd-gen/src/main/resources/vm/ts/index.ts.vm | 0
sgd-ui/src/layout/components/Settings/index.vue | 430 +
sgd-ui/src/components/Crontab/month.vue | 114
sgd-ui/src/main.js | 83
sgd-ui/src/assets/icons/svg/fullscreen.svg | 0
sgd-ui/src/views/system/config/index.vue | 343
sgd-gateway/src/main/resources/banner.txt | 10
sgd-ui/src/assets/icons/svg/lock.svg | 0
sgd-ui/src/assets/icons/svg/slider.svg | 0
sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index.vue.vm | 0
sgd-ui/src/layout/components/TopNav/index.vue | 0
sgd-ui/src/assets/icons/svg/pdf.svg | 0
sgd-ui/src/assets/icons/svg/star.svg | 0
sgd-ui/src/api/system/operlog.js | 26
sgd-ui/src/assets/icons/svg/date.svg | 0
sgd-ui/src/views/monitor/job/log.vue | 265
sgd-ui/src/assets/icons/svg/download.svg | 0
sgd-ui/src/assets/icons/svg/list.svg | 0
sgd-ui/src/directive/module/clipboard.js | 54
sgd-ui/src/components/ImageUpload/index.vue | 266
sgd-ui/src/assets/icons/svg/build.svg | 0
sgd-ui/src/assets/icons/svg/enter.svg | 0
sgd-ui/src/assets/icons/svg/language.svg | 0
sgd-ui/src/layout/index.vue | 115
sgd-modules/sgd-gen/src/main/resources/vm/vue/index.vue.vm | 660 +
sgd-ui/src/assets/icons/svg/post.svg | 0
sgd-ui/src/api/system/notice.js | 79
sgd-ui/src/assets/icons/svg/question.svg | 0
sgd-ui/src/layout/components/HeaderNotice/index.vue | 0
sgd-ui/src/assets/images/profile.jpg | 0
sgd-ui/src/assets/icons/svg/client.svg | 0
sgd-ui/src/assets/icons/svg/peoples.svg | 0
sgd-ui/src/components/Crontab/result.vue | 0
sgd-ui/src/directive/dialog/dragWidth.js | 30
sgd-ui/src/layout/components/TagsView/index.vue | 760 +
sgd-ui/src/views/system/logininfor/index.vue | 243
sgd-ui/src/views/system/operlog/index.vue | 279
/dev/null | 74
sgd-ui/src/views/dashboard/PieChart.vue | 79
sgd-ui/src/views/tool/build/DraggableItem.vue | 100
sgd-modules/sgd-gen/src/main/resources/vm/java/sub-domain.java.vm | 0
sgd-ui/src/assets/icons/svg/clipboard.svg | 0
sgd-ui/src/utils/dynamicTitle.js | 0
sgd-ui/src/layout/components/Sidebar/Item.vue | 33
sgd-ui/src/api/system/user.js | 0
sgd-ui/public/html/ie.html | 46
sgd-ui/src/components/HeaderSearch/index.vue | 397
sgd-ui/src/components/IconSelect/requireIcons.js | 11
sgd-ui/src/assets/icons/svg/code.svg | 0
sgd-ui/src/utils/generator/html.js | 358
sgd-ui/src/components/Crontab/min.vue | 0
332 files changed, 25,321 insertions(+), 74 deletions(-)
diff --git a/ruoyi-api/ruoyi-api-system/pom.xml b/ruoyi-api/ruoyi-api-system/pom.xml
deleted file mode 100644
index 10deddc..0000000
--- a/ruoyi-api/ruoyi-api-system/pom.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://maven.apache.org/POM/4.0.0"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>com.ruoyi</groupId>
- <artifactId>ruoyi-api</artifactId>
- <version>3.6.8</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>ruoyi-api-system</artifactId>
-
- <description>
- ruoyi-api-system系统接口模块
- </description>
-
- <dependencies>
-
- <!-- RuoYi Common Core-->
- <dependency>
- <groupId>com.ruoyi</groupId>
- <artifactId>ruoyi-common-core</artifactId>
- </dependency>
-
- </dependencies>
-
-</project>
\ No newline at end of file
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java
deleted file mode 100644
index 688bb46..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteFileService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.ruoyi.system.api;
-
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.constant.ServiceNameConstants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.domain.SysFile;
-import com.ruoyi.system.api.factory.RemoteFileFallbackFactory;
-
-/**
- * 文件服务
- *
- * @author ruoyi
- */
-@FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
-public interface RemoteFileService
-{
- /**
- * 上传文件
- *
- * @param file 文件信息
- * @return 结果
- */
- @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
- public R<SysFile> upload(@RequestPart(value = "file") MultipartFile file);
-
- /**
- * 删除文件
- *
- * @param fileUrl 文件地址
- * @return 结果
- */
- @DeleteMapping(value = "/delete", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public R<Boolean> delete(@RequestParam("fileUrl") String fileUrl);
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteLogService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteLogService.java
deleted file mode 100644
index 3402afa..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteLogService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.system.api;
-
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.constant.ServiceNameConstants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.domain.SysLogininfor;
-import com.ruoyi.system.api.domain.SysOperLog;
-import com.ruoyi.system.api.factory.RemoteLogFallbackFactory;
-
-/**
- * 日志服务
- *
- * @author ruoyi
- */
-@FeignClient(contextId = "remoteLogService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteLogFallbackFactory.class)
-public interface RemoteLogService
-{
- /**
- * 保存系统日志
- *
- * @param sysOperLog 日志实体
- * @param source 请求来源
- * @return 结果
- */
- @PostMapping("/operlog")
- public R<Boolean> saveLog(@RequestBody SysOperLog sysOperLog, @RequestHeader(SecurityConstants.FROM_SOURCE) String source) throws Exception;
-
- /**
- * 保存访问记录
- *
- * @param sysLogininfor 访问实体
- * @param source 请求来源
- * @return 结果
- */
- @PostMapping("/logininfor")
- public R<Boolean> saveLogininfor(@RequestBody SysLogininfor sysLogininfor, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java
deleted file mode 100644
index c1a94b3..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.ruoyi.system.api;
-
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.constant.ServiceNameConstants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.factory.RemoteUserFallbackFactory;
-import com.ruoyi.system.api.model.LoginUser;
-
-/**
- * 用户服务
- *
- * @author ruoyi
- */
-@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
-public interface RemoteUserService
-{
- /**
- * 通过用户名查询用户信息
- *
- * @param username 用户名
- * @param source 请求来源
- * @return 结果
- */
- @GetMapping("/user/info/{username}")
- public R<LoginUser> getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
-
- /**
- * 注册用户信息
- *
- * @param sysUser 用户信息
- * @param source 请求来源
- * @return 结果
- */
- @PostMapping("/user/register")
- public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
-
- /**
- * 记录用户登录IP地址和登录时间
- *
- * @param sysUser 用户信息
- * @param source 请求来源
- * @return 结果
- */
- @PutMapping("/user/recordlogin")
- public R<Boolean> recordUserLogin(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDept.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDept.java
deleted file mode 100644
index 043dfef..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDept.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import java.util.ArrayList;
-import java.util.List;
-import jakarta.validation.constraints.Email;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 部门表 sys_dept
- *
- * @author ruoyi
- */
-public class SysDept extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 部门ID */
- private Long deptId;
-
- /** 父部门ID */
- private Long parentId;
-
- /** 祖级列表 */
- private String ancestors;
-
- /** 部门名称 */
- private String deptName;
-
- /** 显示顺序 */
- private Integer orderNum;
-
- /** 负责人 */
- private String leader;
-
- /** 联系电话 */
- private String phone;
-
- /** 邮箱 */
- private String email;
-
- /** 部门状态:0正常,1停用 */
- private String status;
-
- /** 删除标志(0代表存在 2代表删除) */
- private String delFlag;
-
- /** 父部门名称 */
- private String parentName;
-
- /** 子部门 */
- private List<SysDept> children = new ArrayList<SysDept>();
-
- public Long getDeptId()
- {
- return deptId;
- }
-
- public void setDeptId(Long deptId)
- {
- this.deptId = deptId;
- }
-
- public Long getParentId()
- {
- return parentId;
- }
-
- public void setParentId(Long parentId)
- {
- this.parentId = parentId;
- }
-
- public String getAncestors()
- {
- return ancestors;
- }
-
- public void setAncestors(String ancestors)
- {
- this.ancestors = ancestors;
- }
-
- @NotBlank(message = "部门名称不能为空")
- @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
- public String getDeptName()
- {
- return deptName;
- }
-
- public void setDeptName(String deptName)
- {
- this.deptName = deptName;
- }
-
- @NotNull(message = "显示顺序不能为空")
- public Integer getOrderNum()
- {
- return orderNum;
- }
-
- public void setOrderNum(Integer orderNum)
- {
- this.orderNum = orderNum;
- }
-
- public String getLeader()
- {
- return leader;
- }
-
- public void setLeader(String leader)
- {
- this.leader = leader;
- }
-
- @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
- public String getPhone()
- {
- return phone;
- }
-
- public void setPhone(String phone)
- {
- this.phone = phone;
- }
-
- @Email(message = "邮箱格式不正确")
- @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
- public String getEmail()
- {
- return email;
- }
-
- public void setEmail(String email)
- {
- this.email = email;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getDelFlag()
- {
- return delFlag;
- }
-
- public void setDelFlag(String delFlag)
- {
- this.delFlag = delFlag;
- }
-
- public String getParentName()
- {
- return parentName;
- }
-
- public void setParentName(String parentName)
- {
- this.parentName = parentName;
- }
-
- public List<SysDept> getChildren()
- {
- return children;
- }
-
- public void setChildren(List<SysDept> children)
- {
- this.children = children;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("deptId", getDeptId())
- .append("parentId", getParentId())
- .append("ancestors", getAncestors())
- .append("deptName", getDeptName())
- .append("orderNum", getOrderNum())
- .append("leader", getLeader())
- .append("phone", getPhone())
- .append("email", getEmail())
- .append("status", getStatus())
- .append("delFlag", getDelFlag())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictData.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictData.java
deleted file mode 100644
index 1f88597..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictData.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 字典数据表 sys_dict_data
- *
- * @author ruoyi
- */
-public class SysDictData extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 字典编码 */
- @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
- private Long dictCode;
-
- /** 字典排序 */
- @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
- private Long dictSort;
-
- /** 字典标签 */
- @Excel(name = "字典标签")
- private String dictLabel;
-
- /** 字典键值 */
- @Excel(name = "字典键值")
- private String dictValue;
-
- /** 字典类型 */
- @Excel(name = "字典类型")
- private String dictType;
-
- /** 样式属性(其他样式扩展) */
- private String cssClass;
-
- /** 表格字典样式 */
- private String listClass;
-
- /** 是否默认(Y是 N否) */
- @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
- private String isDefault;
-
- /** 状态(0正常 1停用) */
- @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
- private String status;
-
- public Long getDictCode()
- {
- return dictCode;
- }
-
- public void setDictCode(Long dictCode)
- {
- this.dictCode = dictCode;
- }
-
- public Long getDictSort()
- {
- return dictSort;
- }
-
- public void setDictSort(Long dictSort)
- {
- this.dictSort = dictSort;
- }
-
- @NotBlank(message = "字典标签不能为空")
- @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
- public String getDictLabel()
- {
- return dictLabel;
- }
-
- public void setDictLabel(String dictLabel)
- {
- this.dictLabel = dictLabel;
- }
-
- @NotBlank(message = "字典键值不能为空")
- @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
- public String getDictValue()
- {
- return dictValue;
- }
-
- public void setDictValue(String dictValue)
- {
- this.dictValue = dictValue;
- }
-
- @NotBlank(message = "字典类型不能为空")
- @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
- public String getDictType()
- {
- return dictType;
- }
-
- public void setDictType(String dictType)
- {
- this.dictType = dictType;
- }
-
- @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
- public String getCssClass()
- {
- return cssClass;
- }
-
- public void setCssClass(String cssClass)
- {
- this.cssClass = cssClass;
- }
-
- public String getListClass()
- {
- return listClass;
- }
-
- public void setListClass(String listClass)
- {
- this.listClass = listClass;
- }
-
- public boolean getDefault()
- {
- return UserConstants.YES.equals(this.isDefault);
- }
-
- public String getIsDefault()
- {
- return isDefault;
- }
-
- public void setIsDefault(String isDefault)
- {
- this.isDefault = isDefault;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("dictCode", getDictCode())
- .append("dictSort", getDictSort())
- .append("dictLabel", getDictLabel())
- .append("dictValue", getDictValue())
- .append("dictType", getDictType())
- .append("cssClass", getCssClass())
- .append("listClass", getListClass())
- .append("isDefault", getIsDefault())
- .append("status", getStatus())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictType.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictType.java
deleted file mode 100644
index 94d90c3..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysDictType.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Pattern;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 字典类型表 sys_dict_type
- *
- * @author ruoyi
- */
-public class SysDictType extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 字典主键 */
- @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
- private Long dictId;
-
- /** 字典名称 */
- @Excel(name = "字典名称")
- private String dictName;
-
- /** 字典类型 */
- @Excel(name = "字典类型")
- private String dictType;
-
- /** 状态(0正常 1停用) */
- @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
- private String status;
-
- public Long getDictId()
- {
- return dictId;
- }
-
- public void setDictId(Long dictId)
- {
- this.dictId = dictId;
- }
-
- @NotBlank(message = "字典名称不能为空")
- @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
- public String getDictName()
- {
- return dictName;
- }
-
- public void setDictName(String dictName)
- {
- this.dictName = dictName;
- }
-
- @NotBlank(message = "字典类型不能为空")
- @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
- @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
- public String getDictType()
- {
- return dictType;
- }
-
- public void setDictType(String dictType)
- {
- this.dictType = dictType;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("dictId", getDictId())
- .append("dictName", getDictName())
- .append("dictType", getDictType())
- .append("status", getStatus())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysFile.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysFile.java
deleted file mode 100644
index 440df49..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysFile.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 文件信息
- *
- * @author ruoyi
- */
-public class SysFile
-{
- /**
- * 文件名称
- */
- private String name;
-
- /**
- * 文件地址
- */
- private String url;
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public String getUrl()
- {
- return url;
- }
-
- public void setUrl(String url)
- {
- this.url = url;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("name", getName())
- .append("url", getUrl())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysLogininfor.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysLogininfor.java
deleted file mode 100644
index e586c93..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysLogininfor.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 系统访问记录表 sys_logininfor
- *
- * @author ruoyi
- */
-public class SysLogininfor extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** ID */
- @Excel(name = "序号", cellType = ColumnType.NUMERIC)
- private Long infoId;
-
- /** 用户账号 */
- @Excel(name = "用户账号")
- private String userName;
-
- /** 状态 0成功 1失败 */
- @Excel(name = "状态", readConverterExp = "0=成功,1=失败")
- private String status;
-
- /** 地址 */
- @Excel(name = "地址")
- private String ipaddr;
-
- /** 描述 */
- @Excel(name = "描述")
- private String msg;
-
- /** 访问时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
- private Date accessTime;
-
- public Long getInfoId()
- {
- return infoId;
- }
-
- public void setInfoId(Long infoId)
- {
- this.infoId = infoId;
- }
-
- public String getUserName()
- {
- return userName;
- }
-
- public void setUserName(String userName)
- {
- this.userName = userName;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getIpaddr()
- {
- return ipaddr;
- }
-
- public void setIpaddr(String ipaddr)
- {
- this.ipaddr = ipaddr;
- }
-
- public String getMsg()
- {
- return msg;
- }
-
- public void setMsg(String msg)
- {
- this.msg = msg;
- }
-
- public Date getAccessTime()
- {
- return accessTime;
- }
-
- public void setAccessTime(Date accessTime)
- {
- this.accessTime = accessTime;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysOperLog.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysOperLog.java
deleted file mode 100644
index d815cb0..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysOperLog.java
+++ /dev/null
@@ -1,255 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 操作日志记录表 oper_log
- *
- * @author ruoyi
- */
-public class SysOperLog extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 日志主键 */
- @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
- private Long operId;
-
- /** 操作模块 */
- @Excel(name = "操作模块")
- private String title;
-
- /** 业务类型(0其它 1新增 2修改 3删除) */
- @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
- private Integer businessType;
-
- /** 业务类型数组 */
- private Integer[] businessTypes;
-
- /** 请求方法 */
- @Excel(name = "请求方法")
- private String method;
-
- /** 请求方式 */
- @Excel(name = "请求方式")
- private String requestMethod;
-
- /** 操作类别(0其它 1后台用户 2手机端用户) */
- @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
- private Integer operatorType;
-
- /** 操作人员 */
- @Excel(name = "操作人员")
- private String operName;
-
- /** 部门名称 */
- @Excel(name = "部门名称")
- private String deptName;
-
- /** 请求url */
- @Excel(name = "请求地址")
- private String operUrl;
-
- /** 操作地址 */
- @Excel(name = "操作地址")
- private String operIp;
-
- /** 请求参数 */
- @Excel(name = "请求参数")
- private String operParam;
-
- /** 返回参数 */
- @Excel(name = "返回参数")
- private String jsonResult;
-
- /** 操作状态(0正常 1异常) */
- @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
- private Integer status;
-
- /** 错误消息 */
- @Excel(name = "错误消息")
- private String errorMsg;
-
- /** 操作时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
- private Date operTime;
-
- /** 消耗时间 */
- @Excel(name = "消耗时间", suffix = "毫秒")
- private Long costTime;
-
- public Long getOperId()
- {
- return operId;
- }
-
- public void setOperId(Long operId)
- {
- this.operId = operId;
- }
-
- public String getTitle()
- {
- return title;
- }
-
- public void setTitle(String title)
- {
- this.title = title;
- }
-
- public Integer getBusinessType()
- {
- return businessType;
- }
-
- public void setBusinessType(Integer businessType)
- {
- this.businessType = businessType;
- }
-
- public Integer[] getBusinessTypes()
- {
- return businessTypes;
- }
-
- public void setBusinessTypes(Integer[] businessTypes)
- {
- this.businessTypes = businessTypes;
- }
-
- public String getMethod()
- {
- return method;
- }
-
- public void setMethod(String method)
- {
- this.method = method;
- }
-
- public String getRequestMethod()
- {
- return requestMethod;
- }
-
- public void setRequestMethod(String requestMethod)
- {
- this.requestMethod = requestMethod;
- }
-
- public Integer getOperatorType()
- {
- return operatorType;
- }
-
- public void setOperatorType(Integer operatorType)
- {
- this.operatorType = operatorType;
- }
-
- public String getOperName()
- {
- return operName;
- }
-
- public void setOperName(String operName)
- {
- this.operName = operName;
- }
-
- public String getDeptName()
- {
- return deptName;
- }
-
- public void setDeptName(String deptName)
- {
- this.deptName = deptName;
- }
-
- public String getOperUrl()
- {
- return operUrl;
- }
-
- public void setOperUrl(String operUrl)
- {
- this.operUrl = operUrl;
- }
-
- public String getOperIp()
- {
- return operIp;
- }
-
- public void setOperIp(String operIp)
- {
- this.operIp = operIp;
- }
-
- public String getOperParam()
- {
- return operParam;
- }
-
- public void setOperParam(String operParam)
- {
- this.operParam = operParam;
- }
-
- public String getJsonResult()
- {
- return jsonResult;
- }
-
- public void setJsonResult(String jsonResult)
- {
- this.jsonResult = jsonResult;
- }
-
- public Integer getStatus()
- {
- return status;
- }
-
- public void setStatus(Integer status)
- {
- this.status = status;
- }
-
- public String getErrorMsg()
- {
- return errorMsg;
- }
-
- public void setErrorMsg(String errorMsg)
- {
- this.errorMsg = errorMsg;
- }
-
- public Date getOperTime()
- {
- return operTime;
- }
-
- public void setOperTime(Date operTime)
- {
- this.operTime = operTime;
- }
-
- public Long getCostTime()
- {
- return costTime;
- }
-
- public void setCostTime(Long costTime)
- {
- this.costTime = costTime;
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysRole.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysRole.java
deleted file mode 100644
index 34d0990..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysRole.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import java.util.Set;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 角色表 sys_role
- *
- * @author ruoyi
- */
-public class SysRole extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 角色ID */
- @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
- private Long roleId;
-
- /** 角色名称 */
- @Excel(name = "角色名称")
- private String roleName;
-
- /** 角色权限 */
- @Excel(name = "角色权限")
- private String roleKey;
-
- /** 角色排序 */
- @Excel(name = "角色排序")
- private Integer roleSort;
-
- /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */
- @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
- private String dataScope;
-
- /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */
- private boolean menuCheckStrictly;
-
- /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */
- private boolean deptCheckStrictly;
-
- /** 角色状态(0正常 1停用) */
- @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
- private String status;
-
- /** 删除标志(0代表存在 2代表删除) */
- private String delFlag;
-
- /** 用户是否存在此角色标识 默认不存在 */
- private boolean flag = false;
-
- /** 菜单组 */
- private Long[] menuIds;
-
- /** 部门组(数据权限) */
- private Long[] deptIds;
-
- /** 角色菜单权限 */
- private Set<String> permissions;
-
- public SysRole()
- {
-
- }
-
- public SysRole(Long roleId)
- {
- this.roleId = roleId;
- }
-
- public Long getRoleId()
- {
- return roleId;
- }
-
- public void setRoleId(Long roleId)
- {
- this.roleId = roleId;
- }
-
- public boolean isAdmin()
- {
- return isAdmin(this.roleId);
- }
-
- public static boolean isAdmin(Long roleId)
- {
- return roleId != null && 1L == roleId;
- }
-
- @NotBlank(message = "角色名称不能为空")
- @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
- public String getRoleName()
- {
- return roleName;
- }
-
- public void setRoleName(String roleName)
- {
- this.roleName = roleName;
- }
-
- @NotBlank(message = "权限字符不能为空")
- @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
- public String getRoleKey()
- {
- return roleKey;
- }
-
- public void setRoleKey(String roleKey)
- {
- this.roleKey = roleKey;
- }
-
- @NotNull(message = "显示顺序不能为空")
- public Integer getRoleSort()
- {
- return roleSort;
- }
-
- public void setRoleSort(Integer roleSort)
- {
- this.roleSort = roleSort;
- }
-
- public String getDataScope()
- {
- return dataScope;
- }
-
- public void setDataScope(String dataScope)
- {
- this.dataScope = dataScope;
- }
-
- public boolean isMenuCheckStrictly()
- {
- return menuCheckStrictly;
- }
-
- public void setMenuCheckStrictly(boolean menuCheckStrictly)
- {
- this.menuCheckStrictly = menuCheckStrictly;
- }
-
- public boolean isDeptCheckStrictly()
- {
- return deptCheckStrictly;
- }
-
- public void setDeptCheckStrictly(boolean deptCheckStrictly)
- {
- this.deptCheckStrictly = deptCheckStrictly;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getDelFlag()
- {
- return delFlag;
- }
-
- public void setDelFlag(String delFlag)
- {
- this.delFlag = delFlag;
- }
-
- public boolean isFlag()
- {
- return flag;
- }
-
- public void setFlag(boolean flag)
- {
- this.flag = flag;
- }
-
- public Long[] getMenuIds()
- {
- return menuIds;
- }
-
- public void setMenuIds(Long[] menuIds)
- {
- this.menuIds = menuIds;
- }
-
- public Long[] getDeptIds()
- {
- return deptIds;
- }
-
- public void setDeptIds(Long[] deptIds)
- {
- this.deptIds = deptIds;
- }
-
- public Set<String> getPermissions()
- {
- return permissions;
- }
-
- public void setPermissions(Set<String> permissions)
- {
- this.permissions = permissions;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("roleId", getRoleId())
- .append("roleName", getRoleName())
- .append("roleKey", getRoleKey())
- .append("roleSort", getRoleSort())
- .append("dataScope", getDataScope())
- .append("menuCheckStrictly", isMenuCheckStrictly())
- .append("deptCheckStrictly", isDeptCheckStrictly())
- .append("status", getStatus())
- .append("delFlag", getDelFlag())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java
deleted file mode 100644
index 5c1e9ba..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java
+++ /dev/null
@@ -1,336 +0,0 @@
-package com.ruoyi.system.api.domain;
-
-import java.util.Date;
-import java.util.List;
-import jakarta.validation.constraints.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.annotation.Excel.Type;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.annotation.Excels;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-import com.ruoyi.common.core.xss.Xss;
-
-/**
- * 用户对象 sys_user
- *
- * @author ruoyi
- */
-public class SysUser extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 用户ID */
- @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
- private Long userId;
-
- /** 部门ID */
- @Excel(name = "部门编号", type = Type.IMPORT)
- private Long deptId;
-
- /** 用户账号 */
- @Excel(name = "登录名称")
- private String userName;
-
- /** 用户昵称 */
- @Excel(name = "用户名称")
- private String nickName;
-
- /** 用户邮箱 */
- @Excel(name = "用户邮箱")
- private String email;
-
- /** 手机号码 */
- @Excel(name = "手机号码", cellType = ColumnType.TEXT)
- private String phonenumber;
-
- /** 用户性别 */
- @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
- private String sex;
-
- /** 用户头像 */
- private String avatar;
-
- /** 密码 */
- private String password;
-
- /** 账号状态(0正常 1停用) */
- @Excel(name = "账号状态", readConverterExp = "0=正常,1=停用")
- private String status;
-
- /** 删除标志(0代表存在 2代表删除) */
- private String delFlag;
-
- /** 最后登录IP */
- @Excel(name = "最后登录IP", type = Type.EXPORT)
- private String loginIp;
-
- /** 最后登录时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
- private Date loginDate;
-
- /** 密码最后更新时间 */
- private Date pwdUpdateDate;
-
- /** 部门对象 */
- @Excels({
- @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
- @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
- })
- private SysDept dept;
-
- /** 角色对象 */
- private List<SysRole> roles;
-
- /** 角色组 */
- private Long[] roleIds;
-
- /** 岗位组 */
- private Long[] postIds;
-
- /** 角色ID */
- private Long roleId;
-
- public SysUser()
- {
-
- }
-
- public SysUser(Long userId)
- {
- this.userId = userId;
- }
-
- public Long getUserId()
- {
- return userId;
- }
-
- public void setUserId(Long userId)
- {
- this.userId = userId;
- }
-
- public boolean isAdmin()
- {
- return UserConstants.isAdmin(userId);
- }
-
- public Long getDeptId()
- {
- return deptId;
- }
-
- public void setDeptId(Long deptId)
- {
- this.deptId = deptId;
- }
-
- @Xss(message = "用户昵称不能包含脚本字符")
- @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
- public String getNickName()
- {
- return nickName;
- }
-
- public void setNickName(String nickName)
- {
- this.nickName = nickName;
- }
-
- @Xss(message = "用户账号不能包含脚本字符")
- @NotBlank(message = "用户账号不能为空")
- @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
- public String getUserName()
- {
- return userName;
- }
-
- public void setUserName(String userName)
- {
- this.userName = userName;
- }
-
- @Email(message = "邮箱格式不正确")
- @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
- public String getEmail()
- {
- return email;
- }
-
- public void setEmail(String email)
- {
- this.email = email;
- }
-
- @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
- public String getPhonenumber()
- {
- return phonenumber;
- }
-
- public void setPhonenumber(String phonenumber)
- {
- this.phonenumber = phonenumber;
- }
-
- public String getSex()
- {
- return sex;
- }
-
- public void setSex(String sex)
- {
- this.sex = sex;
- }
-
- public String getAvatar()
- {
- return avatar;
- }
-
- public void setAvatar(String avatar)
- {
- this.avatar = avatar;
- }
-
- public String getPassword()
- {
- return password;
- }
-
- public void setPassword(String password)
- {
- this.password = password;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getDelFlag()
- {
- return delFlag;
- }
-
- public void setDelFlag(String delFlag)
- {
- this.delFlag = delFlag;
- }
-
- public String getLoginIp()
- {
- return loginIp;
- }
-
- public void setLoginIp(String loginIp)
- {
- this.loginIp = loginIp;
- }
-
- public Date getLoginDate()
- {
- return loginDate;
- }
-
- public void setLoginDate(Date loginDate)
- {
- this.loginDate = loginDate;
- }
-
- public Date getPwdUpdateDate()
- {
- return pwdUpdateDate;
- }
-
- public void setPwdUpdateDate(Date pwdUpdateDate)
- {
- this.pwdUpdateDate = pwdUpdateDate;
- }
-
- public SysDept getDept()
- {
- return dept;
- }
-
- public void setDept(SysDept dept)
- {
- this.dept = dept;
- }
-
- public List<SysRole> getRoles()
- {
- return roles;
- }
-
- public void setRoles(List<SysRole> roles)
- {
- this.roles = roles;
- }
-
- public Long[] getRoleIds()
- {
- return roleIds;
- }
-
- public void setRoleIds(Long[] roleIds)
- {
- this.roleIds = roleIds;
- }
-
- public Long[] getPostIds()
- {
- return postIds;
- }
-
- public void setPostIds(Long[] postIds)
- {
- this.postIds = postIds;
- }
-
- public Long getRoleId()
- {
- return roleId;
- }
-
- public void setRoleId(Long roleId)
- {
- this.roleId = roleId;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("userId", getUserId())
- .append("deptId", getDeptId())
- .append("userName", getUserName())
- .append("nickName", getNickName())
- .append("email", getEmail())
- .append("phonenumber", getPhonenumber())
- .append("sex", getSex())
- .append("avatar", getAvatar())
- .append("password", getPassword())
- .append("status", getStatus())
- .append("delFlag", getDelFlag())
- .append("loginIp", getLoginIp())
- .append("loginDate", getLoginDate())
- .append("pwdUpdateDate", getPwdUpdateDate())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .append("dept", getDept())
- .toString();
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java
deleted file mode 100644
index 421eb94..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteFileFallbackFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.system.api.factory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.cloud.openfeign.FallbackFactory;
-import org.springframework.stereotype.Component;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.RemoteFileService;
-import com.ruoyi.system.api.domain.SysFile;
-
-/**
- * 文件服务降级处理
- *
- * @author ruoyi
- */
-@Component
-public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService>
-{
- private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);
-
- @Override
- public RemoteFileService create(Throwable throwable)
- {
- log.error("文件服务调用失败:{}", throwable.getMessage());
- return new RemoteFileService()
- {
- @Override
- public R<SysFile> upload(MultipartFile file)
- {
- return R.fail("上传文件失败:" + throwable.getMessage());
- }
-
- @Override
- public R<Boolean> delete(String fileUrl)
- {
- return R.fail("删除文件失败:" + throwable.getMessage());
- }
- };
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteLogFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteLogFallbackFactory.java
deleted file mode 100644
index 7126b5b..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteLogFallbackFactory.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.ruoyi.system.api.factory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.cloud.openfeign.FallbackFactory;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.RemoteLogService;
-import com.ruoyi.system.api.domain.SysLogininfor;
-import com.ruoyi.system.api.domain.SysOperLog;
-
-/**
- * 日志服务降级处理
- *
- * @author ruoyi
- */
-@Component
-public class RemoteLogFallbackFactory implements FallbackFactory<RemoteLogService>
-{
- private static final Logger log = LoggerFactory.getLogger(RemoteLogFallbackFactory.class);
-
- @Override
- public RemoteLogService create(Throwable throwable)
- {
- log.error("日志服务调用失败:{}", throwable.getMessage());
- return new RemoteLogService()
- {
- @Override
- public R<Boolean> saveLog(SysOperLog sysOperLog, String source)
- {
- return R.fail("保存操作日志失败:" + throwable.getMessage());
- }
-
- @Override
- public R<Boolean> saveLogininfor(SysLogininfor sysLogininfor, String source)
- {
- return R.fail("保存登录日志失败:" + throwable.getMessage());
- }
- };
-
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java
deleted file mode 100644
index d0ae76a..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/factory/RemoteUserFallbackFactory.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.ruoyi.system.api.factory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.cloud.openfeign.FallbackFactory;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.system.api.RemoteUserService;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.model.LoginUser;
-
-/**
- * 用户服务降级处理
- *
- * @author ruoyi
- */
-@Component
-public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserService>
-{
- private static final Logger log = LoggerFactory.getLogger(RemoteUserFallbackFactory.class);
-
- @Override
- public RemoteUserService create(Throwable throwable)
- {
- log.error("用户服务调用失败:{}", throwable.getMessage());
- return new RemoteUserService()
- {
- @Override
- public R<LoginUser> getUserInfo(String username, String source)
- {
- return R.fail("获取用户失败:" + throwable.getMessage());
- }
-
- @Override
- public R<Boolean> registerUserInfo(SysUser sysUser, String source)
- {
- return R.fail("注册用户失败:" + throwable.getMessage());
- }
-
- @Override
- public R<Boolean> recordUserLogin(SysUser sysUser, String source)
- {
- return R.fail("记录用户登录信息失败:" + throwable.getMessage());
- }
- };
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/model/LoginUser.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/model/LoginUser.java
deleted file mode 100644
index 2f00e10..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/model/LoginUser.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.ruoyi.system.api.model;
-
-import java.io.Serializable;
-import java.util.Set;
-import com.ruoyi.system.api.domain.SysUser;
-
-/**
- * 用户信息
- *
- * @author ruoyi
- */
-public class LoginUser implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * 用户唯一标识
- */
- private String token;
-
- /**
- * 用户名id
- */
- private Long userid;
-
- /**
- * 用户名
- */
- private String username;
-
- /**
- * 登录时间
- */
- private Long loginTime;
-
- /**
- * 过期时间
- */
- private Long expireTime;
-
- /**
- * 登录IP地址
- */
- private String ipaddr;
-
- /**
- * 权限列表
- */
- private Set<String> permissions;
-
- /**
- * 角色列表
- */
- private Set<String> roles;
-
- /**
- * 用户信息
- */
- private SysUser sysUser;
-
- public String getToken()
- {
- return token;
- }
-
- public void setToken(String token)
- {
- this.token = token;
- }
-
- public Long getUserid()
- {
- return userid;
- }
-
- public void setUserid(Long userid)
- {
- this.userid = userid;
- }
-
- public String getUsername()
- {
- return username;
- }
-
- public void setUsername(String username)
- {
- this.username = username;
- }
-
- public Long getLoginTime()
- {
- return loginTime;
- }
-
- public void setLoginTime(Long loginTime)
- {
- this.loginTime = loginTime;
- }
-
- public Long getExpireTime()
- {
- return expireTime;
- }
-
- public void setExpireTime(Long expireTime)
- {
- this.expireTime = expireTime;
- }
-
- public String getIpaddr()
- {
- return ipaddr;
- }
-
- public void setIpaddr(String ipaddr)
- {
- this.ipaddr = ipaddr;
- }
-
- public Set<String> getPermissions()
- {
- return permissions;
- }
-
- public void setPermissions(Set<String> permissions)
- {
- this.permissions = permissions;
- }
-
- public Set<String> getRoles()
- {
- return roles;
- }
-
- public void setRoles(Set<String> roles)
- {
- this.roles = roles;
- }
-
- public SysUser getSysUser()
- {
- return sysUser;
- }
-
- public void setSysUser(SysUser sysUser)
- {
- this.sysUser = sysUser;
- }
-}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
deleted file mode 100644
index 9212ec0..0000000
--- a/ruoyi-api/ruoyi-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ /dev/null
@@ -1,3 +0,0 @@
-com.ruoyi.system.api.factory.RemoteUserFallbackFactory
-com.ruoyi.system.api.factory.RemoteLogFallbackFactory
-com.ruoyi.system.api.factory.RemoteFileFallbackFactory
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java
deleted file mode 100644
index 5fa9ed9..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/RuoYiAuthApplication.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.ruoyi.auth;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
-import com.ruoyi.common.security.annotation.EnableRyFeignClients;
-
-/**
- * 认证授权中心
- *
- * @author ruoyi
- */
-@EnableRyFeignClients
-@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
-public class RuoYiAuthApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiAuthApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 认证授权中心启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java
deleted file mode 100644
index beb8615..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.ruoyi.auth.controller;
-
-import jakarta.servlet.http.HttpServletRequest;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.auth.form.LoginBody;
-import com.ruoyi.auth.form.RegisterBody;
-import com.ruoyi.auth.form.UnLockBody;
-import com.ruoyi.auth.service.SysLoginService;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.utils.JwtUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.security.auth.AuthUtil;
-import com.ruoyi.common.security.service.TokenService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.model.LoginUser;
-
-/**
- * token 控制
- *
- * @author ruoyi
- */
-@RestController
-public class TokenController
-{
- @Autowired
- private TokenService tokenService;
-
- @Autowired
- private SysLoginService sysLoginService;
-
- @PostMapping("login")
- public R<?> login(@RequestBody LoginBody form)
- {
- // 用户登录
- LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
- // 获取登录token
- return R.ok(tokenService.createToken(userInfo));
- }
-
- @DeleteMapping("logout")
- public R<?> logout(HttpServletRequest request)
- {
- String token = SecurityUtils.getToken(request);
- if (StringUtils.isNotEmpty(token))
- {
- String username = JwtUtils.getUserName(token);
- // 删除用户缓存记录
- AuthUtil.logoutByToken(token);
- // 记录用户退出日志
- sysLoginService.logout(username);
- }
- return R.ok();
- }
-
- @PostMapping("refresh")
- public R<?> refresh(HttpServletRequest request)
- {
- LoginUser loginUser = tokenService.getLoginUser(request);
- if (StringUtils.isNotNull(loginUser))
- {
- // 刷新令牌有效期
- tokenService.refreshToken(loginUser);
- return R.ok();
- }
- return R.ok();
- }
-
- @PostMapping("register")
- public R<?> register(@RequestBody RegisterBody registerBody)
- {
- // 用户注册
- sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
- return R.ok();
- }
-
- /**
- * 解锁屏幕
- */
- @PostMapping("/unlockscreen")
- public R<?> unlockScreen(@RequestBody UnLockBody unLockBody)
- {
- sysLoginService.unlock(unLockBody.getPassword());
- return R.ok();
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java
deleted file mode 100644
index b12fb31..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.ruoyi.auth.form;
-
-/**
- * 用户登录对象
- *
- * @author ruoyi
- */
-public class LoginBody
-{
- /**
- * 用户名
- */
- private String username;
-
- /**
- * 用户密码
- */
- private String password;
-
- public String getUsername()
- {
- return username;
- }
-
- public void setUsername(String username)
- {
- this.username = username;
- }
-
- public String getPassword()
- {
- return password;
- }
-
- public void setPassword(String password)
- {
- this.password = password;
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/RegisterBody.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/form/RegisterBody.java
deleted file mode 100644
index a8e16ee..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/RegisterBody.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.ruoyi.auth.form;
-
-/**
- * 用户注册对象
- *
- * @author ruoyi
- */
-public class RegisterBody extends LoginBody
-{
-
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/UnLockBody.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/form/UnLockBody.java
deleted file mode 100644
index 7421e77..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/UnLockBody.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.auth.form;
-
-/**
- * 系统解锁对象
- *
- * @author ruoyi
- */
-public class UnLockBody
-{
- /**
- * 用户密码
- */
- private String password;
-
- public String getPassword()
- {
- return password;
- }
-
- public void setPassword(String password)
- {
- this.password = password;
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java
deleted file mode 100644
index 907ffdf..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package com.ruoyi.auth.service;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.enums.UserStatus;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.ip.IpUtils;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.RemoteUserService;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.model.LoginUser;
-
-/**
- * 登录校验方法
- *
- * @author ruoyi
- */
-@Component
-public class SysLoginService
-{
- @Autowired
- private RemoteUserService remoteUserService;
-
- @Autowired
- private SysPasswordService passwordService;
-
- @Autowired
- private SysRecordLogService recordLogService;
-
- @Autowired
- private RedisService redisService;
-
- /**
- * 登录
- */
- public LoginUser login(String username, String password)
- {
- // 用户名或密码为空 错误
- if (StringUtils.isAnyBlank(username, password))
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
- throw new ServiceException("用户/密码必须填写");
- }
- // 密码如果不在指定范围内 错误
- if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
- || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
- throw new ServiceException("用户密码不在指定范围");
- }
- // 用户名不在指定范围内 错误
- if (username.length() < UserConstants.USERNAME_MIN_LENGTH
- || username.length() > UserConstants.USERNAME_MAX_LENGTH)
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
- throw new ServiceException("用户名不在指定范围");
- }
- // IP黑名单校验
- String blackStr = Convert.toStr(redisService.getCacheObject(CacheConstants.SYS_LOGIN_BLACKIPLIST));
- if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "很遗憾,访问IP已被列入系统黑名单");
- throw new ServiceException("很遗憾,访问IP已被列入系统黑名单");
- }
- // 查询用户信息
- R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
-
- if (R.FAIL == userResult.getCode())
- {
- throw new ServiceException(userResult.getMsg());
- }
-
- LoginUser userInfo = userResult.getData();
- SysUser user = userResult.getData().getSysUser();
- if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除");
- throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
- }
- if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
- {
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员");
- throw new ServiceException("对不起,您的账号:" + username + " 已停用");
- }
- passwordService.validate(user, password);
- recordLogService.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
- recordLoginInfo(user.getUserId());
- return userInfo;
- }
-
- /**
- * 记录登录信息
- *
- * @param userId 用户ID
- */
- public void recordLoginInfo(Long userId)
- {
- SysUser sysUser = new SysUser();
- sysUser.setUserId(userId);
- // 更新用户登录IP
- sysUser.setLoginIp(IpUtils.getIpAddr());
- // 更新用户登录时间
- sysUser.setLoginDate(DateUtils.getNowDate());
- remoteUserService.recordUserLogin(sysUser, SecurityConstants.INNER);
- }
-
- /**
- * 退出
- */
- public void logout(String loginName)
- {
- recordLogService.recordLogininfor(loginName, Constants.LOGOUT, "退出成功");
- }
-
- /**
- * 解锁
- */
- public void unlock(String password)
- {
- String username = SecurityUtils.getUsername();
- // 或密码为空 错误
- if (StringUtils.isEmpty(password))
- {
- throw new ServiceException("密码不能为空");
- }
- // 查询用户信息
- R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
-
- if (R.FAIL == userResult.getCode())
- {
- throw new ServiceException(userResult.getMsg());
- }
-
- SysUser user = userResult.getData().getSysUser();
- if (!SecurityUtils.matchesPassword(password, user.getPassword()))
- {
- throw new ServiceException("密码错误,请重新输入");
- }
- }
-
- /**
- * 注册
- */
- public void register(String username, String password)
- {
- // 用户名或密码为空 错误
- if (StringUtils.isAnyBlank(username, password))
- {
- throw new ServiceException("用户/密码必须填写");
- }
- if (username.length() < UserConstants.USERNAME_MIN_LENGTH
- || username.length() > UserConstants.USERNAME_MAX_LENGTH)
- {
- throw new ServiceException("账户长度必须在2到20个字符之间");
- }
- if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
- || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
- {
- throw new ServiceException("密码长度必须在5到20个字符之间");
- }
-
- // 注册用户信息
- SysUser sysUser = new SysUser();
- sysUser.setUserName(username);
- sysUser.setNickName(username);
- sysUser.setPwdUpdateDate(DateUtils.getNowDate());
- sysUser.setPassword(SecurityUtils.encryptPassword(password));
- R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
-
- if (R.FAIL == registerResult.getCode())
- {
- throw new ServiceException(registerResult.getMsg());
- }
- recordLogService.recordLogininfor(username, Constants.REGISTER, "注册成功");
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysPasswordService.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysPasswordService.java
deleted file mode 100644
index eb18ea8..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysPasswordService.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.ruoyi.auth.service;
-
-import java.util.concurrent.TimeUnit;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysUser;
-
-/**
- * 登录密码方法
- *
- * @author ruoyi
- */
-@Component
-public class SysPasswordService
-{
- @Autowired
- private RedisService redisService;
-
- private int maxRetryCount = CacheConstants.PASSWORD_MAX_RETRY_COUNT;
-
- private Long lockTime = CacheConstants.PASSWORD_LOCK_TIME;
-
- @Autowired
- private SysRecordLogService recordLogService;
-
- /**
- * 登录账户密码错误次数缓存键名
- *
- * @param username 用户名
- * @return 缓存键key
- */
- private String getCacheKey(String username)
- {
- return CacheConstants.PWD_ERR_CNT_KEY + username;
- }
-
- public void validate(SysUser user, String password)
- {
- String username = user.getUserName();
-
- Integer retryCount = redisService.getCacheObject(getCacheKey(username));
-
- if (retryCount == null)
- {
- retryCount = 0;
- }
-
- if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
- {
- String errMsg = String.format("密码输入错误%s次,帐户锁定%s分钟", maxRetryCount, lockTime);
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL,errMsg);
- throw new ServiceException(errMsg);
- }
-
- if (!matches(user, password))
- {
- retryCount = retryCount + 1;
- recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, String.format("密码输入错误%s次", retryCount));
- redisService.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
- throw new ServiceException("用户不存在/密码错误");
- }
- else
- {
- clearLoginRecordCache(username);
- }
- }
-
- public boolean matches(SysUser user, String rawPassword)
- {
- return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
- }
-
- public void clearLoginRecordCache(String loginName)
- {
- if (redisService.hasKey(getCacheKey(loginName)))
- {
- redisService.deleteObject(getCacheKey(loginName));
- }
- }
-}
diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysRecordLogService.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysRecordLogService.java
deleted file mode 100644
index 7ca0f00..0000000
--- a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysRecordLogService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.ruoyi.auth.service;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.ip.IpUtils;
-import com.ruoyi.system.api.RemoteLogService;
-import com.ruoyi.system.api.domain.SysLogininfor;
-
-/**
- * 记录日志方法
- *
- * @author ruoyi
- */
-@Component
-public class SysRecordLogService
-{
- @Autowired
- private RemoteLogService remoteLogService;
-
- /**
- * 记录登录信息
- *
- * @param username 用户名
- * @param status 状态
- * @param message 消息内容
- * @return
- */
- public void recordLogininfor(String username, String status, String message)
- {
- SysLogininfor logininfor = new SysLogininfor();
- logininfor.setUserName(username);
- logininfor.setIpaddr(IpUtils.getIpAddr());
- logininfor.setMsg(message);
- // 日志状态
- if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
- {
- logininfor.setStatus(Constants.LOGIN_SUCCESS_STATUS);
- }
- else if (Constants.LOGIN_FAIL.equals(status))
- {
- logininfor.setStatus(Constants.LOGIN_FAIL_STATUS);
- }
- remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excel.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excel.java
deleted file mode 100644
index d3e1e1f..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excel.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package com.ruoyi.common.core.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.math.BigDecimal;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import com.ruoyi.common.core.utils.poi.ExcelHandlerAdapter;
-
-/**
- * 自定义导出Excel数据注解
- *
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Excel
-{
- /**
- * 导出时在excel中排序
- */
- public int sort() default Integer.MAX_VALUE;
-
- /**
- * 导出到Excel中的名字.
- */
- public String name() default "";
-
- /**
- * 日期格式, 如: yyyy-MM-dd
- */
- public String dateFormat() default "";
-
- /**
- * 读取内容转表达式 (如: 0=男,1=女,2=未知)
- */
- public String readConverterExp() default "";
-
- /**
- * 分隔符,读取字符串组内容
- */
- public String separator() default ",";
-
- /**
- * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
- */
- public int scale() default -1;
-
- /**
- * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
- */
- @SuppressWarnings("deprecation")
- public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
-
- /**
- * 导出时在excel中每个列的高度
- */
- public double height() default 14;
-
- /**
- * 导出时在excel中每个列的宽度
- */
- public double width() default 16;
-
- /**
- * 文字后缀,如% 90 变成90%
- */
- public String suffix() default "";
-
- /**
- * 当值为空时,字段的默认值
- */
- public String defaultValue() default "";
-
- /**
- * 提示信息
- */
- public String prompt() default "";
-
- /**
- * 是否允许内容换行
- */
- public boolean wrapText() default false;
-
- /**
- * 设置只能选择不能输入的列内容.
- */
- public String[] combo() default {};
-
- /**
- * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
- */
- public boolean needMerge() default false;
-
- /**
- * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
- */
- public boolean isExport() default true;
-
- /**
- * 另一个类中的属性名称,支持多级获取,以小数点隔开
- */
- public String targetAttr() default "";
-
- /**
- * 是否自动统计数据,在最后追加一行统计数据总和
- */
- public boolean isStatistics() default false;
-
- /**
- * 导出类型(0数字 1字符串)
- */
- public ColumnType cellType() default ColumnType.STRING;
-
- /**
- * 导出列头背景颜色
- */
- public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
-
- /**
- * 导出列头字体颜色
- */
- public IndexedColors headerColor() default IndexedColors.WHITE;
-
- /**
- * 导出单元格背景颜色
- */
- public IndexedColors backgroundColor() default IndexedColors.WHITE;
-
- /**
- * 导出单元格字体颜色
- */
- public IndexedColors color() default IndexedColors.BLACK;
-
- /**
- * 导出字段对齐方式
- */
- public HorizontalAlignment align() default HorizontalAlignment.CENTER;
-
- /**
- * 自定义数据处理器
- */
- public Class<?> handler() default ExcelHandlerAdapter.class;
-
- /**
- * 自定义数据处理器参数
- */
- public String[] args() default {};
-
- /**
- * 字段类型(0:导出导入;1:仅导出;2:仅导入)
- */
- Type type() default Type.ALL;
-
- public enum Type
- {
- ALL(0), EXPORT(1), IMPORT(2);
- private final int value;
-
- Type(int value)
- {
- this.value = value;
- }
-
- public int value()
- {
- return this.value;
- }
- }
-
- public enum ColumnType
- {
- NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
- private final int value;
-
- ColumnType(int value)
- {
- this.value = value;
- }
-
- public int value()
- {
- return this.value;
- }
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excels.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excels.java
deleted file mode 100644
index af2d950..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Excels.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.common.core.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Excel注解集
- *
- * @author ruoyi
- */
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Excels
-{
- Excel[] value();
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
deleted file mode 100644
index e2df52b..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 缓存常量信息
- *
- * @author ruoyi
- */
-public class CacheConstants
-{
- /**
- * 缓存有效期,默认720(分钟)
- */
- public final static long EXPIRATION = 720;
-
- /**
- * 缓存刷新时间,默认120(分钟)
- */
- public final static long REFRESH_TIME = 120;
-
- /**
- * 密码最大错误次数
- */
- public final static int PASSWORD_MAX_RETRY_COUNT = 5;
-
- /**
- * 密码锁定时间,默认10(分钟)
- */
- public final static long PASSWORD_LOCK_TIME = 10;
-
- /**
- * 权限缓存前缀
- */
- public final static String LOGIN_TOKEN_KEY = "login_tokens:";
-
- /**
- * 验证码 redis key
- */
- public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
-
- /**
- * 参数管理 cache key
- */
- public static final String SYS_CONFIG_KEY = "sys_config:";
-
- /**
- * 字典管理 cache key
- */
- public static final String SYS_DICT_KEY = "sys_dict:";
-
- /**
- * 登录账户密码错误次数 redis key
- */
- public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
-
- /**
- * 登录IP黑名单 cache key
- */
- public static final String SYS_LOGIN_BLACKIPLIST = SYS_CONFIG_KEY + "sys.login.blackIPList";
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
deleted file mode 100644
index c191ebb..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 通用常量信息
- *
- * @author ruoyi
- */
-public class Constants
-{
- /**
- * UTF-8 字符集
- */
- public static final String UTF8 = "UTF-8";
-
- /**
- * GBK 字符集
- */
- public static final String GBK = "GBK";
-
- /**
- * www主域
- */
- public static final String WWW = "www.";
-
- /**
- * RMI 远程方法调用
- */
- public static final String LOOKUP_RMI = "rmi:";
-
- /**
- * LDAP 远程方法调用
- */
- public static final String LOOKUP_LDAP = "ldap:";
-
- /**
- * LDAPS 远程方法调用
- */
- public static final String LOOKUP_LDAPS = "ldaps:";
-
- /**
- * http请求
- */
- public static final String HTTP = "http://";
-
- /**
- * https请求
- */
- public static final String HTTPS = "https://";
-
- /**
- * 成功标记
- */
- public static final Integer SUCCESS = 200;
-
- /**
- * 失败标记
- */
- public static final Integer FAIL = 500;
-
- /**
- * 登录成功状态
- */
- public static final String LOGIN_SUCCESS_STATUS = "0";
-
- /**
- * 登录失败状态
- */
- public static final String LOGIN_FAIL_STATUS = "1";
-
- /**
- * 登录成功
- */
- public static final String LOGIN_SUCCESS = "Success";
-
- /**
- * 注销
- */
- public static final String LOGOUT = "Logout";
-
- /**
- * 注册
- */
- public static final String REGISTER = "Register";
-
- /**
- * 登录失败
- */
- public static final String LOGIN_FAIL = "Error";
-
- /**
- * 所有权限标识
- */
- public static final String ALL_PERMISSION = "*:*:*";
-
- /**
- * 管理员角色权限标识
- */
- public static final String SUPER_ADMIN = "admin";
-
- /**
- * 当前记录起始索引
- */
- public static final String PAGE_NUM = "pageNum";
-
- /**
- * 每页显示记录数
- */
- public static final String PAGE_SIZE = "pageSize";
-
- /**
- * 排序列
- */
- public static final String ORDER_BY_COLUMN = "orderByColumn";
-
- /**
- * 排序的方向 "desc" 或者 "asc".
- */
- public static final String IS_ASC = "isAsc";
-
- /**
- * 验证码有效期(分钟)
- */
- public static final long CAPTCHA_EXPIRATION = 2;
-
- /**
- * 资源映射路径 前缀
- */
- public static final String RESOURCE_PREFIX = "/profile";
-
- /**
- * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
- */
- public static final String[] JSON_WHITELIST_STR = { "com.ruoyi" };
-
- /**
- * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
- */
- public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.job.task" };
-
- /**
- * 定时任务违规的字符
- */
- public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
- "org.springframework", "org.apache", "com.ruoyi.common.core.utils.file" };
-
- /**
- * 部门相关常量
- */
- public static class Dept
- {
- /**
- * 全部数据权限
- */
- public static final String DATA_SCOPE_ALL = "1";
-
- /**
- * 自定数据权限
- */
- public static final String DATA_SCOPE_CUSTOM = "2";
-
- /**
- * 部门数据权限
- */
- public static final String DATA_SCOPE_DEPT = "3";
-
- /**
- * 部门及以下数据权限
- */
- public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
-
- /**
- * 仅本人数据权限
- */
- public static final String DATA_SCOPE_SELF = "5";
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java
deleted file mode 100644
index e867dfc..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 代码生成通用常量
- *
- * @author ruoyi
- */
-public class GenConstants
-{
- /** 单表(增删改查) */
- public static final String TPL_CRUD = "crud";
-
- /** 树表(增删改查) */
- public static final String TPL_TREE = "tree";
-
- /** 主子表(增删改查) */
- public static final String TPL_SUB = "sub";
-
- /** 树编码字段 */
- public static final String TREE_CODE = "treeCode";
-
- /** 树父编码字段 */
- public static final String TREE_PARENT_CODE = "treeParentCode";
-
- /** 树名称字段 */
- public static final String TREE_NAME = "treeName";
-
- /** 上级菜单ID字段 */
- public static final String PARENT_MENU_ID = "parentMenuId";
-
- /** 上级菜单名称字段 */
- public static final String PARENT_MENU_NAME = "parentMenuName";
-
- /** 生成详情页开关 */
- public static final String GEN_VIEW = "genView";
-
- /** 数据库字符串类型 */
- public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
-
- /** 数据库文本类型 */
- public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
-
- /** 数据库时间类型 */
- public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
-
- /** 数据库数字类型 */
- public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
- "bit", "bigint", "float", "double", "decimal" };
-
- /** 页面不需要编辑字段 */
- public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
-
- /** 页面不需要显示的列表字段 */
- public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time" };
-
- /** 页面不需要查询字段 */
- public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time", "remark" };
-
- /** Entity基类字段 */
- public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
-
- /** Tree基类字段 */
- public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors" };
-
- /** 文本框 */
- public static final String HTML_INPUT = "input";
-
- /** 文本域 */
- public static final String HTML_TEXTAREA = "textarea";
-
- /** 下拉框 */
- public static final String HTML_SELECT = "select";
-
- /** 单选框 */
- public static final String HTML_RADIO = "radio";
-
- /** 复选框 */
- public static final String HTML_CHECKBOX = "checkbox";
-
- /** 日期控件 */
- public static final String HTML_DATETIME = "datetime";
-
- /** 图片上传控件 */
- public static final String HTML_IMAGE_UPLOAD = "imageUpload";
-
- /** 文件上传控件 */
- public static final String HTML_FILE_UPLOAD = "fileUpload";
-
- /** 富文本控件 */
- public static final String HTML_EDITOR = "editor";
-
- /** 字符串类型 */
- public static final String TYPE_STRING = "String";
-
- /** 整型 */
- public static final String TYPE_INTEGER = "Integer";
-
- /** 长整型 */
- public static final String TYPE_LONG = "Long";
-
- /** 浮点型 */
- public static final String TYPE_DOUBLE = "Double";
-
- /** 高精度计算类型 */
- public static final String TYPE_BIGDECIMAL = "BigDecimal";
-
- /** 时间类型 */
- public static final String TYPE_DATE = "Date";
-
- /** 模糊查询 */
- public static final String QUERY_LIKE = "LIKE";
-
- /** 相等查询 */
- public static final String QUERY_EQ = "EQ";
-
- /** 需要 */
- public static final String REQUIRE = "1";
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java
deleted file mode 100644
index 45b6160..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 返回状态码
- *
- * @author ruoyi
- */
-public class HttpStatus
-{
- /**
- * 操作成功
- */
- public static final int SUCCESS = 200;
-
- /**
- * 对象创建成功
- */
- public static final int CREATED = 201;
-
- /**
- * 请求已经被接受
- */
- public static final int ACCEPTED = 202;
-
- /**
- * 操作已经执行成功,但是没有返回数据
- */
- public static final int NO_CONTENT = 204;
-
- /**
- * 资源已被移除
- */
- public static final int MOVED_PERM = 301;
-
- /**
- * 重定向
- */
- public static final int SEE_OTHER = 303;
-
- /**
- * 资源没有被修改
- */
- public static final int NOT_MODIFIED = 304;
-
- /**
- * 参数列表错误(缺少,格式不匹配)
- */
- public static final int BAD_REQUEST = 400;
-
- /**
- * 未授权
- */
- public static final int UNAUTHORIZED = 401;
-
- /**
- * 访问受限,授权过期
- */
- public static final int FORBIDDEN = 403;
-
- /**
- * 资源,服务未找到
- */
- public static final int NOT_FOUND = 404;
-
- /**
- * 不允许的http方法
- */
- public static final int BAD_METHOD = 405;
-
- /**
- * 资源冲突,或者资源被锁
- */
- public static final int CONFLICT = 409;
-
- /**
- * 不支持的数据,媒体类型
- */
- public static final int UNSUPPORTED_TYPE = 415;
-
- /**
- * 系统内部错误
- */
- public static final int ERROR = 500;
-
- /**
- * 接口未实现
- */
- public static final int NOT_IMPLEMENTED = 501;
-
- /**
- * 系统警告消息
- */
- public static final int WARN = 601;
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ScheduleConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ScheduleConstants.java
deleted file mode 100644
index b562cff..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ScheduleConstants.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 任务调度通用常量
- *
- * @author ruoyi
- */
-public class ScheduleConstants
-{
- public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
-
- /** 执行目标key */
- public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
-
- /** 默认 */
- public static final String MISFIRE_DEFAULT = "0";
-
- /** 立即触发执行 */
- public static final String MISFIRE_IGNORE_MISFIRES = "1";
-
- /** 触发一次执行 */
- public static final String MISFIRE_FIRE_AND_PROCEED = "2";
-
- /** 不触发立即执行 */
- public static final String MISFIRE_DO_NOTHING = "3";
-
- public enum Status
- {
- /**
- * 正常
- */
- NORMAL("0"),
- /**
- * 暂停
- */
- PAUSE("1");
-
- private String value;
-
- private Status(String value)
- {
- this.value = value;
- }
-
- public String getValue()
- {
- return value;
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
deleted file mode 100644
index 7e790ff..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/SecurityConstants.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 权限相关通用常量
- *
- * @author ruoyi
- */
-public class SecurityConstants
-{
- /**
- * 用户ID字段
- */
- public static final String DETAILS_USER_ID = "user_id";
-
- /**
- * 用户名字段
- */
- public static final String DETAILS_USERNAME = "username";
-
- /**
- * 授权信息字段
- */
- public static final String AUTHORIZATION_HEADER = "Authorization";
-
- /**
- * 请求来源
- */
- public static final String FROM_SOURCE = "from-source";
-
- /**
- * 内部请求
- */
- public static final String INNER = "inner";
-
- /**
- * 用户标识
- */
- public static final String USER_KEY = "user_key";
-
- /**
- * 登录用户
- */
- public static final String LOGIN_USER = "login_user";
-
- /**
- * 角色权限
- */
- public static final String ROLE_PERMISSION = "role_permission";
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java
deleted file mode 100644
index a7dcfdd..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/ServiceNameConstants.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 服务名称
- *
- * @author ruoyi
- */
-public class ServiceNameConstants
-{
- /**
- * 认证服务的serviceid
- */
- public static final String AUTH_SERVICE = "ruoyi-auth";
-
- /**
- * 系统模块的serviceid
- */
- public static final String SYSTEM_SERVICE = "ruoyi-system";
-
- /**
- * 文件服务的serviceid
- */
- public static final String FILE_SERVICE = "ruoyi-file";
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TokenConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TokenConstants.java
deleted file mode 100644
index a373028..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TokenConstants.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * Token的Key常量
- *
- * @author ruoyi
- */
-public class TokenConstants
-{
- /**
- * 令牌前缀
- */
- public static final String PREFIX = "Bearer ";
-
- /**
- * 令牌秘钥
- */
- public final static String SECRET = "abcdefghijklmnopqrstuvwxyz";
-
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java
deleted file mode 100644
index 3335095..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.ruoyi.common.core.constant;
-
-/**
- * 用户常量信息
- *
- * @author ruoyi
- */
-public class UserConstants
-{
- /**
- * 平台内系统用户的唯一标志
- */
- public static final String SYS_USER = "SYS_USER";
-
- /** 正常状态 */
- public static final String NORMAL = "0";
-
- /** 异常状态 */
- public static final String EXCEPTION = "1";
-
- /** 用户封禁状态 */
- public static final String USER_DISABLE = "1";
-
- /** 角色正常状态 */
- public static final String ROLE_NORMAL = "0";
-
- /** 角色封禁状态 */
- public static final String ROLE_DISABLE = "1";
-
- /** 部门正常状态 */
- public static final String DEPT_NORMAL = "0";
-
- /** 部门停用状态 */
- public static final String DEPT_DISABLE = "1";
-
- /** 字典正常状态 */
- public static final String DICT_NORMAL = "0";
-
- /** 是否为系统默认(是) */
- public static final String YES = "Y";
-
- /** 是否菜单外链(是) */
- public static final String YES_FRAME = "0";
-
- /** 是否菜单外链(否) */
- public static final String NO_FRAME = "1";
-
- /** 菜单类型(目录) */
- public static final String TYPE_DIR = "M";
-
- /** 菜单类型(菜单) */
- public static final String TYPE_MENU = "C";
-
- /** 菜单类型(按钮) */
- public static final String TYPE_BUTTON = "F";
-
- /** Layout组件标识 */
- public final static String LAYOUT = "Layout";
-
- /** ParentView组件标识 */
- public final static String PARENT_VIEW = "ParentView";
-
- /** InnerLink组件标识 */
- public final static String INNER_LINK = "InnerLink";
-
- /** 校验是否唯一的返回标识 */
- public final static boolean UNIQUE = true;
- public final static boolean NOT_UNIQUE = false;
-
- /**
- * 用户名长度限制
- */
- public static final int USERNAME_MIN_LENGTH = 2;
-
- public static final int USERNAME_MAX_LENGTH = 20;
-
- /**
- * 密码长度限制
- */
- public static final int PASSWORD_MIN_LENGTH = 5;
-
- public static final int PASSWORD_MAX_LENGTH = 20;
-
- public static boolean isAdmin(Long userId)
- {
- return userId != null && 1L == userId;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/context/SecurityContextHolder.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/context/SecurityContextHolder.java
deleted file mode 100644
index 44dc58f..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/context/SecurityContextHolder.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.ruoyi.common.core.context;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import com.alibaba.ttl.TransmittableThreadLocal;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 获取当前线程变量中的 用户id、用户名称、Token等信息
- * 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取
- *
- * @author ruoyi
- */
-public class SecurityContextHolder
-{
- private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();
-
- public static void set(String key, Object value)
- {
- Map<String, Object> map = getLocalMap();
- map.put(key, value == null ? StringUtils.EMPTY : value);
- }
-
- public static String get(String key)
- {
- Map<String, Object> map = getLocalMap();
- return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY));
- }
-
- public static <T> T get(String key, Class<T> clazz)
- {
- Map<String, Object> map = getLocalMap();
- return StringUtils.cast(map.getOrDefault(key, null));
- }
-
- public static Map<String, Object> getLocalMap()
- {
- Map<String, Object> map = THREAD_LOCAL.get();
- if (map == null)
- {
- map = new ConcurrentHashMap<String, Object>();
- THREAD_LOCAL.set(map);
- }
- return map;
- }
-
- public static void setLocalMap(Map<String, Object> threadLocalMap)
- {
- THREAD_LOCAL.set(threadLocalMap);
- }
-
- public static Long getUserId()
- {
- return Convert.toLong(get(SecurityConstants.DETAILS_USER_ID), null);
- }
-
- public static void setUserId(String account)
- {
- set(SecurityConstants.DETAILS_USER_ID, account);
- }
-
- public static String getUserName()
- {
- return get(SecurityConstants.DETAILS_USERNAME);
- }
-
- public static void setUserName(String username)
- {
- set(SecurityConstants.DETAILS_USERNAME, username);
- }
-
- public static String getUserKey()
- {
- return get(SecurityConstants.USER_KEY);
- }
-
- public static void setUserKey(String userKey)
- {
- set(SecurityConstants.USER_KEY, userKey);
- }
-
- public static String getPermission()
- {
- return get(SecurityConstants.ROLE_PERMISSION);
- }
-
- public static void setPermission(String permissions)
- {
- set(SecurityConstants.ROLE_PERMISSION, permissions);
- }
-
- public static void remove()
- {
- THREAD_LOCAL.remove();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/R.java
deleted file mode 100644
index 1fe16e2..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/R.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package com.ruoyi.common.core.domain;
-
-import java.io.Serializable;
-import com.ruoyi.common.core.constant.Constants;
-
-/**
- * 响应信息主体
- *
- * @author ruoyi
- */
-public class R<T> implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /** 成功 */
- public static final int SUCCESS = Constants.SUCCESS;
-
- /** 失败 */
- public static final int FAIL = Constants.FAIL;
-
- private int code;
-
- private String msg;
-
- private T data;
-
- public static <T> R<T> ok()
- {
- return restResult(null, SUCCESS, null);
- }
-
- public static <T> R<T> ok(T data)
- {
- return restResult(data, SUCCESS, null);
- }
-
- public static <T> R<T> ok(T data, String msg)
- {
- return restResult(data, SUCCESS, msg);
- }
-
- public static <T> R<T> fail()
- {
- return restResult(null, FAIL, null);
- }
-
- public static <T> R<T> fail(String msg)
- {
- return restResult(null, FAIL, msg);
- }
-
- public static <T> R<T> fail(T data)
- {
- return restResult(data, FAIL, null);
- }
-
- public static <T> R<T> fail(T data, String msg)
- {
- return restResult(data, FAIL, msg);
- }
-
- public static <T> R<T> fail(int code, String msg)
- {
- return restResult(null, code, msg);
- }
-
- private static <T> R<T> restResult(T data, int code, String msg)
- {
- R<T> apiResult = new R<>();
- apiResult.setCode(code);
- apiResult.setData(data);
- apiResult.setMsg(msg);
- return apiResult;
- }
-
- public int getCode()
- {
- return code;
- }
-
- public void setCode(int code)
- {
- this.code = code;
- }
-
- public String getMsg()
- {
- return msg;
- }
-
- public void setMsg(String msg)
- {
- this.msg = msg;
- }
-
- public T getData()
- {
- return data;
- }
-
- public void setData(T data)
- {
- this.data = data;
- }
-
- public static <T> Boolean isError(R<T> ret)
- {
- return !isSuccess(ret);
- }
-
- public static <T> Boolean isSuccess(R<T> ret)
- {
- return R.SUCCESS == ret.getCode();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserStatus.java
deleted file mode 100644
index 9ff8496..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserStatus.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.ruoyi.common.core.enums;
-
-/**
- * 用户状态
- *
- * @author ruoyi
- */
-public enum UserStatus
-{
- OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
-
- private final String code;
- private final String info;
-
- UserStatus(String code, String info)
- {
- this.code = code;
- this.info = info;
- }
-
- public String getCode()
- {
- return code;
- }
-
- public String getInfo()
- {
- return info;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java
deleted file mode 100644
index 3e01851..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 验证码错误异常类
- *
- * @author ruoyi
- */
-public class CaptchaException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public CaptchaException(String msg)
- {
- super(msg);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CheckedException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CheckedException.java
deleted file mode 100644
index 862eefa..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CheckedException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 检查异常
- *
- * @author ruoyi
- */
-public class CheckedException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public CheckedException(String message)
- {
- super(message);
- }
-
- public CheckedException(Throwable cause)
- {
- super(cause);
- }
-
- public CheckedException(String message, Throwable cause)
- {
- super(message, cause);
- }
-
- public CheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
- {
- super(message, cause, enableSuppression, writableStackTrace);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/DemoModeException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/DemoModeException.java
deleted file mode 100644
index ac2a19e..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/DemoModeException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 演示模式异常
- *
- * @author ruoyi
- */
-public class DemoModeException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public DemoModeException()
- {
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java
deleted file mode 100644
index b55c7cd..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 全局异常
- *
- * @author ruoyi
- */
-public class GlobalException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误提示
- */
- private String message;
-
- /**
- * 错误明细,内部调试错误
- *
- * 和 {@link CommonResult#getDetailMessage()} 一致的设计
- */
- private String detailMessage;
-
- /**
- * 空构造方法,避免反序列化问题
- */
- public GlobalException()
- {
- }
-
- public GlobalException(String message)
- {
- this.message = message;
- }
-
- public String getDetailMessage()
- {
- return detailMessage;
- }
-
- public GlobalException setDetailMessage(String detailMessage)
- {
- this.detailMessage = detailMessage;
- return this;
- }
-
- @Override
- public String getMessage()
- {
- return message;
- }
-
- public GlobalException setMessage(String message)
- {
- this.message = message;
- return this;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/InnerAuthException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/InnerAuthException.java
deleted file mode 100644
index 8a7abe9..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/InnerAuthException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 内部认证异常
- *
- * @author ruoyi
- */
-public class InnerAuthException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public InnerAuthException(String message)
- {
- super(message);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/PreAuthorizeException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/PreAuthorizeException.java
deleted file mode 100644
index 3d420c4..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/PreAuthorizeException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 权限异常
- *
- * @author ruoyi
- */
-public class PreAuthorizeException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public PreAuthorizeException()
- {
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java
deleted file mode 100644
index 4983866..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 业务异常
- *
- * @author ruoyi
- */
-public final class ServiceException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * 错误码
- */
- private Integer code;
-
- /**
- * 错误提示
- */
- private String message;
-
- /**
- * 错误明细,内部调试错误
- *
- * 和 {@link CommonResult#getDetailMessage()} 一致的设计
- */
- private String detailMessage;
-
- /**
- * 空构造方法,避免反序列化问题
- */
- public ServiceException()
- {
- }
-
- public ServiceException(String message)
- {
- this.message = message;
- }
-
- public ServiceException(String message, Integer code)
- {
- this.message = message;
- this.code = code;
- }
-
- public String getDetailMessage()
- {
- return detailMessage;
- }
-
- @Override
- public String getMessage()
- {
- return message;
- }
-
- public Integer getCode()
- {
- return code;
- }
-
- public ServiceException setMessage(String message)
- {
- this.message = message;
- return this;
- }
-
- public ServiceException setDetailMessage(String detailMessage)
- {
- this.detailMessage = detailMessage;
- return this;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java
deleted file mode 100644
index a1c16b5..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.ruoyi.common.core.exception;
-
-/**
- * 工具类异常
- *
- * @author ruoyi
- */
-public class UtilException extends RuntimeException
-{
- private static final long serialVersionUID = 8247610319171014183L;
-
- public UtilException(Throwable e)
- {
- super(e.getMessage(), e);
- }
-
- public UtilException(String message)
- {
- super(message);
- }
-
- public UtilException(String message, Throwable throwable)
- {
- super(message, throwable);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotLoginException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotLoginException.java
deleted file mode 100644
index eb6c3ae..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotLoginException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception.auth;
-
-/**
- * 未能通过的登录认证异常
- *
- * @author ruoyi
- */
-public class NotLoginException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public NotLoginException(String message)
- {
- super(message);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotPermissionException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotPermissionException.java
deleted file mode 100644
index a578a42..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotPermissionException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.ruoyi.common.core.exception.auth;
-
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * 未能通过的权限认证异常
- *
- * @author ruoyi
- */
-public class NotPermissionException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public NotPermissionException(String permission)
- {
- super(permission);
- }
-
- public NotPermissionException(String[] permissions)
- {
- super(StringUtils.join(permissions, ","));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotRoleException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotRoleException.java
deleted file mode 100644
index d07118f..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/auth/NotRoleException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.ruoyi.common.core.exception.auth;
-
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * 未能通过的角色认证异常
- *
- * @author ruoyi
- */
-public class NotRoleException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- public NotRoleException(String role)
- {
- super(role);
- }
-
- public NotRoleException(String[] roles)
- {
- super(StringUtils.join(roles, ","));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java
deleted file mode 100644
index 3d2fa10..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.ruoyi.common.core.exception.base;
-
-/**
- * 基础异常
- *
- * @author ruoyi
- */
-public class BaseException extends RuntimeException
-{
- private static final long serialVersionUID = 1L;
-
- /**
- * 所属模块
- */
- private String module;
-
- /**
- * 错误码
- */
- private String code;
-
- /**
- * 错误码对应的参数
- */
- private Object[] args;
-
- /**
- * 错误消息
- */
- private String defaultMessage;
-
- public BaseException(String module, String code, Object[] args, String defaultMessage)
- {
- this.module = module;
- this.code = code;
- this.args = args;
- this.defaultMessage = defaultMessage;
- }
-
- public BaseException(String module, String code, Object[] args)
- {
- this(module, code, args, null);
- }
-
- public BaseException(String module, String defaultMessage)
- {
- this(module, null, null, defaultMessage);
- }
-
- public BaseException(String code, Object[] args)
- {
- this(null, code, args, null);
- }
-
- public BaseException(String defaultMessage)
- {
- this(null, null, null, defaultMessage);
- }
-
- public String getModule()
- {
- return module;
- }
-
- public String getCode()
- {
- return code;
- }
-
- public Object[] getArgs()
- {
- return args;
- }
-
- public String getDefaultMessage()
- {
- return defaultMessage;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java
deleted file mode 100644
index b19f2d8..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.ruoyi.common.core.exception.file;
-
-import com.ruoyi.common.core.exception.base.BaseException;
-
-/**
- * 文件信息异常类
- *
- * @author ruoyi
- */
-public class FileException extends BaseException
-{
- private static final long serialVersionUID = 1L;
-
- public FileException(String code, Object[] args, String msg)
- {
- super("file", code, args, msg);
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java
deleted file mode 100644
index 0962ca5..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception.file;
-
-/**
- * 文件名称超长限制异常类
- *
- * @author ruoyi
- */
-public class FileNameLengthLimitExceededException extends FileException
-{
- private static final long serialVersionUID = 1L;
-
- public FileNameLengthLimitExceededException(int defaultFileNameLength)
- {
- super("upload.filename.exceed.length", new Object[] { defaultFileNameLength }, "the filename is too long");
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java
deleted file mode 100644
index f9a66b7..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception.file;
-
-/**
- * 文件名大小限制异常类
- *
- * @author ruoyi
- */
-public class FileSizeLimitExceededException extends FileException
-{
- private static final long serialVersionUID = 1L;
-
- public FileSizeLimitExceededException(long defaultMaxSize)
- {
- super("upload.exceed.maxSize", new Object[] { defaultMaxSize }, "the filesize is too large");
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java
deleted file mode 100644
index c0f57cb..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ruoyi.common.core.exception.file;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-
-/**
- * 文件上传异常类
- *
- * @author ruoyi
- */
-public class FileUploadException extends Exception
-{
-
- private static final long serialVersionUID = 1L;
-
- private final Throwable cause;
-
- public FileUploadException()
- {
- this(null, null);
- }
-
- public FileUploadException(final String msg)
- {
- this(msg, null);
- }
-
- public FileUploadException(String msg, Throwable cause)
- {
- super(msg);
- this.cause = cause;
- }
-
- @Override
- public void printStackTrace(PrintStream stream)
- {
- super.printStackTrace(stream);
- if (cause != null)
- {
- stream.println("Caused by:");
- cause.printStackTrace(stream);
- }
- }
-
- @Override
- public void printStackTrace(PrintWriter writer)
- {
- super.printStackTrace(writer);
- if (cause != null)
- {
- writer.println("Caused by:");
- cause.printStackTrace(writer);
- }
- }
-
- @Override
- public Throwable getCause()
- {
- return cause;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java
deleted file mode 100644
index 7efee9d..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.ruoyi.common.core.exception.file;
-
-import java.util.Arrays;
-
-/**
- * 文件上传无效扩展名异常类
- *
- * @author ruoyi
- */
-public class InvalidExtensionException extends FileUploadException
-{
- private static final long serialVersionUID = 1L;
-
- private String[] allowedExtension;
- private String extension;
- private String filename;
-
- public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
- {
- super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
- this.allowedExtension = allowedExtension;
- this.extension = extension;
- this.filename = filename;
- }
-
- public String[] getAllowedExtension()
- {
- return allowedExtension;
- }
-
- public String getExtension()
- {
- return extension;
- }
-
- public String getFilename()
- {
- return filename;
- }
-
- public static class InvalidImageExtensionException extends InvalidExtensionException
- {
- private static final long serialVersionUID = 1L;
-
- public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
- {
- super(allowedExtension, extension, filename);
- }
- }
-
- public static class InvalidFlashExtensionException extends InvalidExtensionException
- {
- private static final long serialVersionUID = 1L;
-
- public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
- {
- super(allowedExtension, extension, filename);
- }
- }
-
- public static class InvalidMediaExtensionException extends InvalidExtensionException
- {
- private static final long serialVersionUID = 1L;
-
- public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
- {
- super(allowedExtension, extension, filename);
- }
- }
-
- public static class InvalidVideoExtensionException extends InvalidExtensionException
- {
- private static final long serialVersionUID = 1L;
-
- public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
- {
- super(allowedExtension, extension, filename);
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java
deleted file mode 100644
index c98397c..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.common.core.exception.job;
-
-/**
- * 计划策略异常
- *
- * @author ruoyi
- */
-public class TaskException extends Exception
-{
- private static final long serialVersionUID = 1L;
-
- private Code code;
-
- public TaskException(String msg, Code code)
- {
- this(msg, code, null);
- }
-
- public TaskException(String msg, Code code, Exception nestedEx)
- {
- super(msg, nestedEx);
- this.code = code;
- }
-
- public Code getCode()
- {
- return code;
- }
-
- public enum Code
- {
- TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java
deleted file mode 100644
index 6924d7e..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception.user;
-
-/**
- * 验证码失效异常类
- *
- * @author ruoyi
- */
-public class CaptchaExpireException extends UserException
-{
- private static final long serialVersionUID = 1L;
-
- public CaptchaExpireException()
- {
- super("user.jcaptcha.expire", null);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java
deleted file mode 100644
index 5493804..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.common.core.exception.user;
-
-import com.ruoyi.common.core.exception.base.BaseException;
-
-/**
- * 用户信息异常类
- *
- * @author ruoyi
- */
-public class UserException extends BaseException
-{
- private static final long serialVersionUID = 1L;
-
- public UserException(String code, Object[] args)
- {
- super("user", code, args, null);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java
deleted file mode 100644
index 7f514a6..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.ruoyi.common.core.exception.user;
-
-/**
- * 用户密码不正确或不符合规范异常类
- *
- * @author ruoyi
- */
-public class UserPasswordNotMatchException extends UserException
-{
- private static final long serialVersionUID = 1L;
-
- public UserPasswordNotMatchException()
- {
- super("user.password.not.match", null);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/CharsetKit.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
deleted file mode 100644
index 662f817..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.ruoyi.common.core.text;
-
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 字符集工具类
- *
- * @author ruoyi
- */
-public class CharsetKit
-{
- /** ISO-8859-1 */
- public static final String ISO_8859_1 = "ISO-8859-1";
- /** UTF-8 */
- public static final String UTF_8 = "UTF-8";
- /** GBK */
- public static final String GBK = "GBK";
-
- /** ISO-8859-1 */
- public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
- /** UTF-8 */
- public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
- /** GBK */
- public static final Charset CHARSET_GBK = Charset.forName(GBK);
-
- /**
- * 转换为Charset对象
- *
- * @param charset 字符集,为空则返回默认字符集
- * @return Charset
- */
- public static Charset charset(String charset)
- {
- return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
- }
-
- /**
- * 转换字符串的字符集编码
- *
- * @param source 字符串
- * @param srcCharset 源字符集,默认ISO-8859-1
- * @param destCharset 目标字符集,默认UTF-8
- * @return 转换后的字符集
- */
- public static String convert(String source, String srcCharset, String destCharset)
- {
- return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
- }
-
- /**
- * 转换字符串的字符集编码
- *
- * @param source 字符串
- * @param srcCharset 源字符集,默认ISO-8859-1
- * @param destCharset 目标字符集,默认UTF-8
- * @return 转换后的字符集
- */
- public static String convert(String source, Charset srcCharset, Charset destCharset)
- {
- if (null == srcCharset)
- {
- srcCharset = StandardCharsets.ISO_8859_1;
- }
-
- if (null == destCharset)
- {
- destCharset = StandardCharsets.UTF_8;
- }
-
- if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
- {
- return source;
- }
- return new String(source.getBytes(srcCharset), destCharset);
- }
-
- /**
- * @return 系统字符集编码
- */
- public static String systemCharset()
- {
- return Charset.defaultCharset().name();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/Convert.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/Convert.java
deleted file mode 100644
index 9ccdcf4..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/Convert.java
+++ /dev/null
@@ -1,1018 +0,0 @@
-package com.ruoyi.common.core.text;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.RoundingMode;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.text.NumberFormat;
-import java.util.Set;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 类型转换器
- *
- * @author ruoyi
- */
-public class Convert
-{
- /**
- * 转换为字符串<br>
- * 如果给定的值为null,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static String toStr(Object value, String defaultValue)
- {
- if (null == value)
- {
- return defaultValue;
- }
- if (value instanceof String)
- {
- return (String) value;
- }
- return value.toString();
- }
-
- /**
- * 转换为字符串<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static String toStr(Object value)
- {
- return toStr(value, null);
- }
-
- /**
- * 转换为字符<br>
- * 如果给定的值为null,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Character toChar(Object value, Character defaultValue)
- {
- if (null == value)
- {
- return defaultValue;
- }
- if (value instanceof Character)
- {
- return (Character) value;
- }
-
- final String valueStr = toStr(value, null);
- return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
- }
-
- /**
- * 转换为字符<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Character toChar(Object value)
- {
- return toChar(value, null);
- }
-
- /**
- * 转换为byte<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Byte toByte(Object value, Byte defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Byte)
- {
- return (Byte) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).byteValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return Byte.parseByte(valueStr);
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为byte<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Byte toByte(Object value)
- {
- return toByte(value, null);
- }
-
- /**
- * 转换为Short<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Short toShort(Object value, Short defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Short)
- {
- return (Short) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).shortValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return Short.parseShort(valueStr.trim());
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为Short<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Short toShort(Object value)
- {
- return toShort(value, null);
- }
-
- /**
- * 转换为Number<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Number toNumber(Object value, Number defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Number)
- {
- return (Number) value;
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return NumberFormat.getInstance().parse(valueStr);
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为Number<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Number toNumber(Object value)
- {
- return toNumber(value, null);
- }
-
- /**
- * 转换为int<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Integer toInt(Object value, Integer defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Integer)
- {
- return (Integer) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).intValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return Integer.parseInt(valueStr.trim());
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为int<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Integer toInt(Object value)
- {
- return toInt(value, null);
- }
-
- /**
- * 转换为Integer数组<br>
- *
- * @param str 被转换的值
- * @return 结果
- */
- public static Integer[] toIntArray(String str)
- {
- return toIntArray(",", str);
- }
-
- /**
- * 转换为Long数组<br>
- *
- * @param str 被转换的值
- * @return 结果
- */
- public static Long[] toLongArray(String str)
- {
- return toLongArray(",", str);
- }
-
- /**
- * 转换为Integer数组<br>
- *
- * @param split 分隔符
- * @param str 被转换的值
- * @return 结果
- */
- public static Integer[] toIntArray(String split, String str)
- {
- if (StringUtils.isEmpty(str))
- {
- return new Integer[] {};
- }
- String[] arr = str.split(split);
- final Integer[] ints = new Integer[arr.length];
- for (int i = 0; i < arr.length; i++)
- {
- final Integer v = toInt(arr[i], 0);
- ints[i] = v;
- }
- return ints;
- }
-
- /**
- * 转换为Long数组<br>
- *
- * @param split 分隔符
- * @param str 被转换的值
- * @return 结果
- */
- public static Long[] toLongArray(String split, String str)
- {
- if (StringUtils.isEmpty(str))
- {
- return new Long[] {};
- }
- String[] arr = str.split(split);
- final Long[] longs = new Long[arr.length];
- for (int i = 0; i < arr.length; i++)
- {
- final Long v = toLong(arr[i], null);
- longs[i] = v;
- }
- return longs;
- }
-
- /**
- * 转换为String数组<br>
- *
- * @param str 被转换的值
- * @return 结果
- */
- public static String[] toStrArray(String str)
- {
- if (StringUtils.isEmpty(str))
- {
- return new String[] {};
- }
- return toStrArray(",", str);
- }
-
- /**
- * 转换为String数组<br>
- *
- * @param split 分隔符
- * @param str 被转换的值
- * @return 结果
- */
- public static String[] toStrArray(String split, String str)
- {
- return str.split(split);
- }
-
- /**
- * 转换为long<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Long toLong(Object value, Long defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Long)
- {
- return (Long) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).longValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- // 支持科学计数法
- return new BigDecimal(valueStr.trim()).longValue();
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为long<br>
- * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Long toLong(Object value)
- {
- return toLong(value, null);
- }
-
- /**
- * 转换为double<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Double toDouble(Object value, Double defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Double)
- {
- return (Double) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).doubleValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- // 支持科学计数法
- return new BigDecimal(valueStr.trim()).doubleValue();
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为double<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Double toDouble(Object value)
- {
- return toDouble(value, null);
- }
-
- /**
- * 转换为Float<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Float toFloat(Object value, Float defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Float)
- {
- return (Float) value;
- }
- if (value instanceof Number)
- {
- return ((Number) value).floatValue();
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return Float.parseFloat(valueStr.trim());
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为Float<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Float toFloat(Object value)
- {
- return toFloat(value, null);
- }
-
- /**
- * 转换为boolean<br>
- * String支持的值为:true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static Boolean toBool(Object value, Boolean defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof Boolean)
- {
- return (Boolean) value;
- }
- String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- valueStr = valueStr.trim().toLowerCase();
- switch (valueStr)
- {
- case "true":
- case "yes":
- case "ok":
- case "1":
- case "是":
- return true;
- case "false":
- case "no":
- case "0":
- case "否":
- return false;
- default:
- return defaultValue;
- }
- }
-
- /**
- * 转换为boolean<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static Boolean toBool(Object value)
- {
- return toBool(value, null);
- }
-
- /**
- * 转换为Enum对象<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- *
- * @param clazz Enum的Class
- * @param value 值
- * @param defaultValue 默认值
- * @return Enum
- */
- public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (clazz.isAssignableFrom(value.getClass()))
- {
- @SuppressWarnings("unchecked")
- E myE = (E) value;
- return myE;
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return Enum.valueOf(clazz, valueStr);
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为Enum对象<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- *
- * @param clazz Enum的Class
- * @param value 值
- * @return Enum
- */
- public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
- {
- return toEnum(clazz, value, null);
- }
-
- /**
- * 转换为BigInteger<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof BigInteger)
- {
- return (BigInteger) value;
- }
- if (value instanceof Long)
- {
- return BigInteger.valueOf((Long) value);
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return new BigInteger(valueStr);
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为BigInteger<br>
- * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static BigInteger toBigInteger(Object value)
- {
- return toBigInteger(value, null);
- }
-
- /**
- * 转换为BigDecimal<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @param defaultValue 转换错误时的默认值
- * @return 结果
- */
- public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
- {
- if (value == null)
- {
- return defaultValue;
- }
- if (value instanceof BigDecimal)
- {
- return (BigDecimal) value;
- }
- if (value instanceof Long)
- {
- return new BigDecimal((Long) value);
- }
- if (value instanceof Double)
- {
- return BigDecimal.valueOf((Double) value);
- }
- if (value instanceof Integer)
- {
- return new BigDecimal((Integer) value);
- }
- final String valueStr = toStr(value, null);
- if (StringUtils.isEmpty(valueStr))
- {
- return defaultValue;
- }
- try
- {
- return new BigDecimal(valueStr);
- }
- catch (Exception e)
- {
- return defaultValue;
- }
- }
-
- /**
- * 转换为BigDecimal<br>
- * 如果给定的值为空,或者转换失败,返回默认值<br>
- * 转换失败不会报错
- *
- * @param value 被转换的值
- * @return 结果
- */
- public static BigDecimal toBigDecimal(Object value)
- {
- return toBigDecimal(value, null);
- }
-
- /**
- * 将对象转为字符串<br>
- * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
- * @param obj 对象
- * @return 字符串
- */
- public static String utf8Str(Object obj)
- {
- return str(obj, CharsetKit.CHARSET_UTF_8);
- }
-
- /**
- * 将对象转为字符串<br>
- * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
- * @param obj 对象
- * @param charsetName 字符集
- * @return 字符串
- */
- public static String str(Object obj, String charsetName)
- {
- return str(obj, Charset.forName(charsetName));
- }
-
- /**
- * 将对象转为字符串<br>
- * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
- *
- * @param obj 对象
- * @param charset 字符集
- * @return 字符串
- */
- public static String str(Object obj, Charset charset)
- {
- if (null == obj)
- {
- return null;
- }
-
- if (obj instanceof String)
- {
- return (String) obj;
- }
- else if (obj instanceof byte[] || obj instanceof Byte[])
- {
- if (obj instanceof byte[])
- {
- return str((byte[]) obj, charset);
- }
- else
- {
- Byte[] bytes = (Byte[]) obj;
- int length = bytes.length;
- byte[] dest = new byte[length];
- for (int i = 0; i < length; i++)
- {
- dest[i] = bytes[i];
- }
- return str(dest, charset);
- }
- }
- else if (obj instanceof ByteBuffer)
- {
- return str((ByteBuffer) obj, charset);
- }
- return obj.toString();
- }
-
- /**
- * 将byte数组转为字符串
- *
- * @param bytes byte数组
- * @param charset 字符集
- * @return 字符串
- */
- public static String str(byte[] bytes, String charset)
- {
- return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
- }
-
- /**
- * 解码字节码
- *
- * @param data 字符串
- * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
- * @return 解码后的字符串
- */
- public static String str(byte[] data, Charset charset)
- {
- if (data == null)
- {
- return null;
- }
-
- if (null == charset)
- {
- return new String(data);
- }
- return new String(data, charset);
- }
-
- /**
- * 将编码的byteBuffer数据转换为字符串
- *
- * @param data 数据
- * @param charset 字符集,如果为空使用当前系统字符集
- * @return 字符串
- */
- public static String str(ByteBuffer data, String charset)
- {
- if (data == null)
- {
- return null;
- }
-
- return str(data, Charset.forName(charset));
- }
-
- /**
- * 将编码的byteBuffer数据转换为字符串
- *
- * @param data 数据
- * @param charset 字符集,如果为空使用当前系统字符集
- * @return 字符串
- */
- public static String str(ByteBuffer data, Charset charset)
- {
- if (null == charset)
- {
- charset = Charset.defaultCharset();
- }
- return charset.decode(data).toString();
- }
-
- // ----------------------------------------------------------------------- 全角半角转换
- /**
- * 半角转全角
- *
- * @param input String.
- * @return 全角字符串.
- */
- public static String toSBC(String input)
- {
- return toSBC(input, null);
- }
-
- /**
- * 半角转全角
- *
- * @param input String
- * @param notConvertSet 不替换的字符集合
- * @return 全角字符串.
- */
- public static String toSBC(String input, Set<Character> notConvertSet)
- {
- char[] c = input.toCharArray();
- for (int i = 0; i < c.length; i++)
- {
- if (null != notConvertSet && notConvertSet.contains(c[i]))
- {
- // 跳过不替换的字符
- continue;
- }
-
- if (c[i] == ' ')
- {
- c[i] = '\u3000';
- }
- else if (c[i] < '\177')
- {
- c[i] = (char) (c[i] + 65248);
-
- }
- }
- return new String(c);
- }
-
- /**
- * 全角转半角
- *
- * @param input String.
- * @return 半角字符串
- */
- public static String toDBC(String input)
- {
- return toDBC(input, null);
- }
-
- /**
- * 替换全角为半角
- *
- * @param text 文本
- * @param notConvertSet 不替换的字符集合
- * @return 替换后的字符
- */
- public static String toDBC(String text, Set<Character> notConvertSet)
- {
- char[] c = text.toCharArray();
- for (int i = 0; i < c.length; i++)
- {
- if (null != notConvertSet && notConvertSet.contains(c[i]))
- {
- // 跳过不替换的字符
- continue;
- }
-
- if (c[i] == '\u3000')
- {
- c[i] = ' ';
- }
- else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
- {
- c[i] = (char) (c[i] - 65248);
- }
- }
- return new String(c);
- }
-
- /**
- * 数字金额大写转换 先写个完整的然后将如零拾替换成零
- *
- * @param n 数字
- * @return 中文大写数字
- */
- public static String digitUppercase(double n)
- {
- String[] fraction = { "角", "分" };
- String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
- String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
-
- String head = n < 0 ? "负" : "";
- n = Math.abs(n);
-
- String s = "";
- for (int i = 0; i < fraction.length; i++)
- {
- // 优化double计算精度丢失问题
- BigDecimal nNum = new BigDecimal(n);
- BigDecimal decimal = new BigDecimal(10);
- BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
- double d = scale.doubleValue();
- s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
- }
- if (s.length() < 1)
- {
- s = "整";
- }
- int integerPart = (int) Math.floor(n);
-
- for (int i = 0; i < unit[0].length && integerPart > 0; i++)
- {
- String p = "";
- for (int j = 0; j < unit[1].length && n > 0; j++)
- {
- p = digit[integerPart % 10] + unit[1][j] + p;
- integerPart = integerPart / 10;
- }
- s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
- }
- return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/StrFormatter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
deleted file mode 100644
index a7d4d84..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.ruoyi.common.core.text;
-
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 字符串格式化
- *
- * @author ruoyi
- */
-public class StrFormatter
-{
- public static final String EMPTY_JSON = "{}";
- public static final char C_BACKSLASH = '\\';
- public static final char C_DELIM_START = '{';
- public static final char C_DELIM_END = '}';
-
- /**
- * 格式化字符串<br>
- * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
- * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
- * 例:<br>
- * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
- * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
- * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
- *
- * @param strPattern 字符串模板
- * @param argArray 参数列表
- * @return 结果
- */
- public static String format(final String strPattern, final Object... argArray)
- {
- if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
- {
- return strPattern;
- }
- final int strPatternLength = strPattern.length();
-
- // 初始化定义好的长度以获得更好的性能
- StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
-
- int handledPosition = 0;
- int delimIndex;// 占位符所在位置
- for (int argIndex = 0; argIndex < argArray.length; argIndex++)
- {
- delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
- if (delimIndex == -1)
- {
- if (handledPosition == 0)
- {
- return strPattern;
- }
- else
- { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
- sbuf.append(strPattern, handledPosition, strPatternLength);
- return sbuf.toString();
- }
- }
- else
- {
- if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
- {
- if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
- {
- // 转义符之前还有一个转义符,占位符依旧有效
- sbuf.append(strPattern, handledPosition, delimIndex - 1);
- sbuf.append(Convert.utf8Str(argArray[argIndex]));
- handledPosition = delimIndex + 2;
- }
- else
- {
- // 占位符被转义
- argIndex--;
- sbuf.append(strPattern, handledPosition, delimIndex - 1);
- sbuf.append(C_DELIM_START);
- handledPosition = delimIndex + 1;
- }
- }
- else
- {
- // 正常占位符
- sbuf.append(strPattern, handledPosition, delimIndex);
- sbuf.append(Convert.utf8Str(argArray[argIndex]));
- handledPosition = delimIndex + 2;
- }
- }
- }
- // 加入最后一个占位符后所有的字符
- sbuf.append(strPattern, handledPosition, strPattern.length());
-
- return sbuf.toString();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java
deleted file mode 100644
index f16c3ed..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DateUtils.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.lang.management.ManagementFactory;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.Date;
-import org.apache.commons.lang3.time.DateFormatUtils;
-
-/**
- * 时间工具类
- *
- * @author ruoyi
- */
-@SuppressWarnings("deprecation")
-public class DateUtils extends org.apache.commons.lang3.time.DateUtils
-{
- public static String YYYY = "yyyy";
-
- public static String YYYY_MM = "yyyy-MM";
-
- public static String YYYY_MM_DD = "yyyy-MM-dd";
-
- public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
-
- public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
-
- private static String[] parsePatterns = {
- "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
- "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
- "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
-
- /**
- * 获取当前Date型日期
- *
- * @return Date() 当前日期
- */
- public static Date getNowDate()
- {
- return new Date();
- }
-
- /**
- * 获取当前日期, 默认格式为yyyy-MM-dd
- *
- * @return String
- */
- public static String getDate()
- {
- return dateTimeNow(YYYY_MM_DD);
- }
-
- public static final String getTime()
- {
- return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
- }
-
- public static final String dateTimeNow()
- {
- return dateTimeNow(YYYYMMDDHHMMSS);
- }
-
- public static final String dateTimeNow(final String format)
- {
- return parseDateToStr(format, new Date());
- }
-
- public static final String dateTime(final Date date)
- {
- return parseDateToStr(YYYY_MM_DD, date);
- }
-
- public static final String parseDateToStr(final String format, final Date date)
- {
- return new SimpleDateFormat(format).format(date);
- }
-
- public static final Date dateTime(final String format, final String ts)
- {
- try
- {
- return new SimpleDateFormat(format).parse(ts);
- }
- catch (ParseException e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * 日期路径 即年/月/日 如2018/08/08
- */
- public static final String datePath()
- {
- Date now = new Date();
- return DateFormatUtils.format(now, "yyyy/MM/dd");
- }
-
- /**
- * 日期路径 即年/月/日 如20180808
- */
- public static final String dateTime()
- {
- Date now = new Date();
- return DateFormatUtils.format(now, "yyyyMMdd");
- }
-
- /**
- * 日期型字符串转化为日期 格式
- */
- public static Date parseDate(Object str)
- {
- if (str == null)
- {
- return null;
- }
- try
- {
- return parseDate(str.toString(), parsePatterns);
- }
- catch (ParseException e)
- {
- return null;
- }
- }
-
- /**
- * 获取服务器启动时间
- */
- public static Date getServerStartDate()
- {
- long time = ManagementFactory.getRuntimeMXBean().getStartTime();
- return new Date(time);
- }
-
- /**
- * 计算相差天数
- */
- public static int differentDaysByMillisecond(Date date1, Date date2)
- {
- return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
- }
-
- /**
- * 计算时间差
- *
- * @param endDate 最后时间
- * @param startTime 开始时间
- * @return 时间差(天/小时/分钟)
- */
- public static String timeDistance(Date endDate, Date startTime)
- {
- long nd = 1000 * 24 * 60 * 60;
- long nh = 1000 * 60 * 60;
- long nm = 1000 * 60;
- // long ns = 1000;
- // 获得两个时间的毫秒时间差异
- long diff = endDate.getTime() - startTime.getTime();
- // 计算差多少天
- long day = diff / nd;
- // 计算差多少小时
- long hour = diff % nd / nh;
- // 计算差多少分钟
- long min = diff % nd % nh / nm;
- // 计算差多少秒//输出结果
- // long sec = diff % nd % nh % nm / ns;
- return day + "天" + hour + "小时" + min + "分钟";
- }
-
- /**
- * 增加 LocalDateTime ==> Date
- */
- public static Date toDate(LocalDateTime temporalAccessor)
- {
- ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
- return Date.from(zdt.toInstant());
- }
-
- /**
- * 增加 LocalDate ==> Date
- */
- public static Date toDate(LocalDate temporalAccessor)
- {
- LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
- ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
- return Date.from(zdt.toInstant());
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ExceptionUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ExceptionUtil.java
deleted file mode 100644
index f75e559..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ExceptionUtil.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-
-/**
- * 错误信息处理类。
- *
- * @author ruoyi
- */
-public class ExceptionUtil
-{
- /**
- * 获取exception的详细错误信息。
- */
- public static String getExceptionMessage(Throwable e)
- {
- StringWriter sw = new StringWriter();
- e.printStackTrace(new PrintWriter(sw, true));
- return sw.toString();
- }
-
- public static String getRootErrorMessage(Exception e)
- {
- Throwable root = ExceptionUtils.getRootCause(e);
- root = (root == null ? e : root);
- if (root == null)
- {
- return "";
- }
- String msg = root.getMessage();
- if (msg == null)
- {
- return "null";
- }
- return StringUtils.defaultString(msg);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
deleted file mode 100644
index abe93c0..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/JwtUtils.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.util.Map;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.constant.TokenConstants;
-import com.ruoyi.common.core.text.Convert;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
-
-/**
- * Jwt工具类
- *
- * @author ruoyi
- */
-public class JwtUtils
-{
- public static String secret = TokenConstants.SECRET;
-
- /**
- * 从数据声明生成令牌
- *
- * @param claims 数据声明
- * @return 令牌
- */
- public static String createToken(Map<String, Object> claims)
- {
- String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
- return token;
- }
-
- /**
- * 从令牌中获取数据声明
- *
- * @param token 令牌
- * @return 数据声明
- */
- public static Claims parseToken(String token)
- {
- return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
- }
-
- /**
- * 根据令牌获取用户标识
- *
- * @param token 令牌
- * @return 用户ID
- */
- public static String getUserKey(String token)
- {
- Claims claims = parseToken(token);
- return getValue(claims, SecurityConstants.USER_KEY);
- }
-
- /**
- * 根据令牌获取用户标识
- *
- * @param claims 身份信息
- * @return 用户ID
- */
- public static String getUserKey(Claims claims)
- {
- return getValue(claims, SecurityConstants.USER_KEY);
- }
-
- /**
- * 根据令牌获取用户ID
- *
- * @param token 令牌
- * @return 用户ID
- */
- public static String getUserId(String token)
- {
- Claims claims = parseToken(token);
- return getValue(claims, SecurityConstants.DETAILS_USER_ID);
- }
-
- /**
- * 根据身份信息获取用户ID
- *
- * @param claims 身份信息
- * @return 用户ID
- */
- public static String getUserId(Claims claims)
- {
- return getValue(claims, SecurityConstants.DETAILS_USER_ID);
- }
-
- /**
- * 根据令牌获取用户名
- *
- * @param token 令牌
- * @return 用户名
- */
- public static String getUserName(String token)
- {
- Claims claims = parseToken(token);
- return getValue(claims, SecurityConstants.DETAILS_USERNAME);
- }
-
- /**
- * 根据身份信息获取用户名
- *
- * @param claims 身份信息
- * @return 用户名
- */
- public static String getUserName(Claims claims)
- {
- return getValue(claims, SecurityConstants.DETAILS_USERNAME);
- }
-
- /**
- * 根据身份信息获取键值
- *
- * @param claims 身份信息
- * @param key 键
- * @return 值
- */
- public static String getValue(Claims claims, String key)
- {
- return Convert.toStr(claims.get(key), "");
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
deleted file mode 100644
index 95ee25b..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import com.github.pagehelper.PageHelper;
-import com.ruoyi.common.core.utils.sql.SqlUtil;
-import com.ruoyi.common.core.web.page.PageDomain;
-import com.ruoyi.common.core.web.page.TableSupport;
-
-/**
- * 分页工具类
- *
- * @author ruoyi
- */
-public class PageUtils extends PageHelper
-{
- /**
- * 设置请求分页数据
- */
- public static void startPage()
- {
- PageDomain pageDomain = TableSupport.buildPageRequest();
- Integer pageNum = pageDomain.getPageNum();
- Integer pageSize = pageDomain.getPageSize();
- String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
- Boolean reasonable = pageDomain.getReasonable();
- PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
- }
-
- /**
- * 清理分页的线程变量
- */
- public static void clearPage()
- {
- PageHelper.clearPage();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
deleted file mode 100644
index 377d465..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
+++ /dev/null
@@ -1,333 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.servlet.http.HttpSession;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.util.LinkedCaseInsensitiveMap;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.text.Convert;
-import reactor.core.publisher.Mono;
-
-/**
- * 客户端工具类
- *
- * @author ruoyi
- */
-public class ServletUtils
-{
- /**
- * 获取String参数
- */
- public static String getParameter(String name)
- {
- return getRequest().getParameter(name);
- }
-
- /**
- * 获取String参数
- */
- public static String getParameter(String name, String defaultValue)
- {
- return Convert.toStr(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获取Integer参数
- */
- public static Integer getParameterToInt(String name)
- {
- return Convert.toInt(getRequest().getParameter(name));
- }
-
- /**
- * 获取Integer参数
- */
- public static Integer getParameterToInt(String name, Integer defaultValue)
- {
- return Convert.toInt(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获取Boolean参数
- */
- public static Boolean getParameterToBool(String name)
- {
- return Convert.toBool(getRequest().getParameter(name));
- }
-
- /**
- * 获取Boolean参数
- */
- public static Boolean getParameterToBool(String name, Boolean defaultValue)
- {
- return Convert.toBool(getRequest().getParameter(name), defaultValue);
- }
-
- /**
- * 获得所有请求参数
- *
- * @param request 请求对象{@link ServletRequest}
- * @return Map
- */
- public static Map<String, String[]> getParams(ServletRequest request)
- {
- final Map<String, String[]> map = request.getParameterMap();
- return Collections.unmodifiableMap(map);
- }
-
- /**
- * 获得所有请求参数
- *
- * @param request 请求对象{@link ServletRequest}
- * @return Map
- */
- public static Map<String, String> getParamMap(ServletRequest request)
- {
- Map<String, String> params = new HashMap<>();
- for (Map.Entry<String, String[]> entry : getParams(request).entrySet())
- {
- params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
- }
- return params;
- }
-
- /**
- * 获取request
- */
- public static HttpServletRequest getRequest()
- {
- try
- {
- return getRequestAttributes().getRequest();
- }
- catch (Exception e)
- {
- return null;
- }
- }
-
- /**
- * 获取response
- */
- public static HttpServletResponse getResponse()
- {
- try
- {
- return getRequestAttributes().getResponse();
- }
- catch (Exception e)
- {
- return null;
- }
- }
-
- /**
- * 获取session
- */
- public static HttpSession getSession()
- {
- return getRequest().getSession();
- }
-
- public static ServletRequestAttributes getRequestAttributes()
- {
- try
- {
- RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
- return (ServletRequestAttributes) attributes;
- }
- catch (Exception e)
- {
- return null;
- }
- }
-
- public static String getHeader(HttpServletRequest request, String name)
- {
- String value = request.getHeader(name);
- if (StringUtils.isEmpty(value))
- {
- return StringUtils.EMPTY;
- }
- return urlDecode(value);
- }
-
- public static Map<String, String> getHeaders(HttpServletRequest request)
- {
- Map<String, String> map = new LinkedCaseInsensitiveMap<>();
- Enumeration<String> enumeration = request.getHeaderNames();
- if (enumeration != null)
- {
- while (enumeration.hasMoreElements())
- {
- String key = enumeration.nextElement();
- String value = request.getHeader(key);
- map.put(key, value);
- }
- }
- return map;
- }
-
- /**
- * 将字符串渲染到客户端
- *
- * @param response 渲染对象
- * @param string 待渲染的字符串
- */
- public static void renderString(HttpServletResponse response, String string)
- {
- try
- {
- response.setStatus(200);
- response.setContentType("application/json");
- response.setCharacterEncoding("utf-8");
- response.getWriter().print(string);
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
-
- /**
- * 是否是Ajax异步请求
- *
- * @param request
- */
- public static boolean isAjaxRequest(HttpServletRequest request)
- {
- String accept = request.getHeader("accept");
- if (accept != null && accept.contains("application/json"))
- {
- return true;
- }
-
- String xRequestedWith = request.getHeader("X-Requested-With");
- if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
- {
- return true;
- }
-
- String uri = request.getRequestURI();
- if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
- {
- return true;
- }
-
- String ajax = request.getParameter("__ajax");
- return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
- }
-
- /**
- * 内容编码
- *
- * @param str 内容
- * @return 编码后的内容
- */
- public static String urlEncode(String str)
- {
- try
- {
- return URLEncoder.encode(str, Constants.UTF8);
- }
- catch (UnsupportedEncodingException e)
- {
- return StringUtils.EMPTY;
- }
- }
-
- /**
- * 内容解码
- *
- * @param str 内容
- * @return 解码后的内容
- */
- public static String urlDecode(String str)
- {
- try
- {
- return URLDecoder.decode(str, Constants.UTF8);
- }
- catch (UnsupportedEncodingException e)
- {
- return StringUtils.EMPTY;
- }
- }
-
- /**
- * 设置webflux模型响应
- *
- * @param response ServerHttpResponse
- * @param value 响应内容
- * @return Mono<Void>
- */
- public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value)
- {
- return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL);
- }
-
- /**
- * 设置webflux模型响应
- *
- * @param response ServerHttpResponse
- * @param code 响应状态码
- * @param value 响应内容
- * @return Mono<Void>
- */
- public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code)
- {
- return webFluxResponseWriter(response, HttpStatus.OK, value, code);
- }
-
- /**
- * 设置webflux模型响应
- *
- * @param response ServerHttpResponse
- * @param status http状态码
- * @param code 响应状态码
- * @param value 响应内容
- * @return Mono<Void>
- */
- public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, int code)
- {
- return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
- }
-
- /**
- * 设置webflux模型响应
- *
- * @param response ServerHttpResponse
- * @param contentType content-type
- * @param status http状态码
- * @param code 响应状态码
- * @param value 响应内容
- * @return Mono<Void>
- */
- public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code)
- {
- response.setStatusCode(status);
- response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
- R<?> result = R.fail(code, value.toString());
- DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
- return response.writeWith(Mono.just(dataBuffer));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java
deleted file mode 100644
index 9dcbceb..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import org.springframework.aop.framework.AopContext;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.stereotype.Component;
-
-/**
- * spring工具类 方便在非spring管理环境中获取bean
- *
- * @author ruoyi
- */
-@Component
-public final class SpringUtils implements BeanFactoryPostProcessor
-{
- /** Spring应用上下文环境 */
- private static ConfigurableListableBeanFactory beanFactory;
-
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
- {
- SpringUtils.beanFactory = beanFactory;
- }
-
- /**
- * 获取对象
- *
- * @param name
- * @return Object 一个以所给名字注册的bean的实例
- * @throws org.springframework.beans.BeansException
- *
- */
- @SuppressWarnings("unchecked")
- public static <T> T getBean(String name) throws BeansException
- {
- return (T) beanFactory.getBean(name);
- }
-
- /**
- * 获取类型为requiredType的对象
- *
- * @param clz
- * @return
- * @throws org.springframework.beans.BeansException
- *
- */
- public static <T> T getBean(Class<T> clz) throws BeansException
- {
- T result = (T) beanFactory.getBean(clz);
- return result;
- }
-
- /**
- * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
- *
- * @param name
- * @return boolean
- */
- public static boolean containsBean(String name)
- {
- return beanFactory.containsBean(name);
- }
-
- /**
- * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
- *
- * @param name
- * @return boolean
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.isSingleton(name);
- }
-
- /**
- * @param name
- * @return Class 注册对象的类型
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.getType(name);
- }
-
- /**
- * 如果给定的bean名字在bean定义中有别名,则返回这些别名
- *
- * @param name
- * @return
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.getAliases(name);
- }
-
- /**
- * 获取aop代理对象
- *
- * @param invoker
- * @return
- */
- @SuppressWarnings("unchecked")
- public static <T> T getAopProxy(T invoker)
- {
- return (T) AopContext.currentProxy();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
deleted file mode 100644
index 152fdbf..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
+++ /dev/null
@@ -1,921 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang3.Strings;
-import org.springframework.util.AntPathMatcher;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.text.StrFormatter;
-
-/**
- * 字符串工具类
- *
- * @author ruoyi
- */
-@SuppressWarnings("deprecation")
-public class StringUtils extends org.apache.commons.lang3.StringUtils
-{
- /** 空字符串 */
- private static final String NULLSTR = "";
-
- /** 下划线 */
- private static final char SEPARATOR = '_';
-
- /** 星号 */
- private static final char ASTERISK = '*';
-
- /**
- * 获取参数不为空值
- *
- * @param value defaultValue 要判断的value
- * @return value 返回值
- */
- public static <T> T nvl(T value, T defaultValue)
- {
- return value != null ? value : defaultValue;
- }
-
- /**
- * * 判断一个Collection是否为空, 包含List,Set,Queue
- *
- * @param coll 要判断的Collection
- * @return true:为空 false:非空
- */
- public static boolean isEmpty(Collection<?> coll)
- {
- return isNull(coll) || coll.isEmpty();
- }
-
- /**
- * * 判断一个Collection是否非空,包含List,Set,Queue
- *
- * @param coll 要判断的Collection
- * @return true:非空 false:空
- */
- public static boolean isNotEmpty(Collection<?> coll)
- {
- return !isEmpty(coll);
- }
-
- /**
- * * 判断一个对象数组是否为空
- *
- * @param objects 要判断的对象数组
- ** @return true:为空 false:非空
- */
- public static boolean isEmpty(Object[] objects)
- {
- return isNull(objects) || (objects.length == 0);
- }
-
- /**
- * * 判断一个对象数组是否非空
- *
- * @param objects 要判断的对象数组
- * @return true:非空 false:空
- */
- public static boolean isNotEmpty(Object[] objects)
- {
- return !isEmpty(objects);
- }
-
- /**
- * * 判断一个Map是否为空
- *
- * @param map 要判断的Map
- * @return true:为空 false:非空
- */
- public static boolean isEmpty(Map<?, ?> map)
- {
- return isNull(map) || map.isEmpty();
- }
-
- /**
- * * 判断一个Map是否为空
- *
- * @param map 要判断的Map
- * @return true:非空 false:空
- */
- public static boolean isNotEmpty(Map<?, ?> map)
- {
- return !isEmpty(map);
- }
-
- /**
- * * 判断一个字符串是否为空串
- *
- * @param str String
- * @return true:为空 false:非空
- */
- public static boolean isEmpty(String str)
- {
- return isNull(str) || NULLSTR.equals(str.trim());
- }
-
- /**
- * * 判断一个字符串是否为非空串
- *
- * @param str String
- * @return true:非空串 false:空串
- */
- public static boolean isNotEmpty(String str)
- {
- return !isEmpty(str);
- }
-
- /**
- * * 判断一个对象是否为空
- *
- * @param object Object
- * @return true:为空 false:非空
- */
- public static boolean isNull(Object object)
- {
- return object == null;
- }
-
- /**
- * * 判断一个对象是否非空
- *
- * @param object Object
- * @return true:非空 false:空
- */
- public static boolean isNotNull(Object object)
- {
- return !isNull(object);
- }
-
- /**
- * * 判断一个对象是否是数组类型(Java基本型别的数组)
- *
- * @param object 对象
- * @return true:是数组 false:不是数组
- */
- public static boolean isArray(Object object)
- {
- return isNotNull(object) && object.getClass().isArray();
- }
-
- /**
- * 去空格
- */
- public static String trim(String str)
- {
- return (str == null ? "" : str.trim());
- }
-
- /**
- * 替换指定字符串的指定区间内字符为"*"
- *
- * @param str 字符串
- * @param startInclude 开始位置(包含)
- * @param endExclude 结束位置(不包含)
- * @return 替换后的字符串
- */
- public static String hide(CharSequence str, int startInclude, int endExclude)
- {
- if (isEmpty(str))
- {
- return NULLSTR;
- }
- final int strLength = str.length();
- if (startInclude > strLength)
- {
- return NULLSTR;
- }
- if (endExclude > strLength)
- {
- endExclude = strLength;
- }
- if (startInclude > endExclude)
- {
- // 如果起始位置大于结束位置,不替换
- return NULLSTR;
- }
- final char[] chars = new char[strLength];
- for (int i = 0; i < strLength; i++)
- {
- if (i >= startInclude && i < endExclude)
- {
- chars[i] = ASTERISK;
- }
- else
- {
- chars[i] = str.charAt(i);
- }
- }
- return new String(chars);
- }
-
- /**
- * 截取字符串
- *
- * @param str 字符串
- * @param start 开始
- * @return 结果
- */
- public static String substring(final String str, int start)
- {
- if (str == null)
- {
- return NULLSTR;
- }
-
- if (start < 0)
- {
- start = str.length() + start;
- }
-
- if (start < 0)
- {
- start = 0;
- }
- if (start > str.length())
- {
- return NULLSTR;
- }
-
- return str.substring(start);
- }
-
- /**
- * 截取字符串
- *
- * @param str 字符串
- * @param start 开始
- * @param end 结束
- * @return 结果
- */
- public static String substring(final String str, int start, int end)
- {
- if (str == null)
- {
- return NULLSTR;
- }
-
- if (end < 0)
- {
- end = str.length() + end;
- }
- if (start < 0)
- {
- start = str.length() + start;
- }
-
- if (end > str.length())
- {
- end = str.length();
- }
-
- if (start > end)
- {
- return NULLSTR;
- }
-
- if (start < 0)
- {
- start = 0;
- }
- if (end < 0)
- {
- end = 0;
- }
-
- return str.substring(start, end);
- }
-
- /**
- * 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
- *
- * @param str 要截取的字符串
- * @param open 起始字符串
- * @param close 结束字符串
- * @return 截取结果
- */
- public static String substringBetweenLast(final String str, final String open, final String close)
- {
- if (isEmpty(str) || isEmpty(open) || isEmpty(close))
- {
- return NULLSTR;
- }
- final int start = str.indexOf(open);
- if (start != INDEX_NOT_FOUND)
- {
- final int end = str.lastIndexOf(close);
- if (end != INDEX_NOT_FOUND)
- {
- return str.substring(start + open.length(), end);
- }
- }
- return NULLSTR;
- }
-
- /**
- * 判断是否为空,并且不是空白字符
- *
- * @param str 要判断的value
- * @return 结果
- */
- public static boolean hasText(String str)
- {
- return (str != null && !str.isEmpty() && containsText(str));
- }
-
- private static boolean containsText(CharSequence str)
- {
- int strLen = str.length();
- for (int i = 0; i < strLen; i++)
- {
- if (!Character.isWhitespace(str.charAt(i)))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * 格式化文本, {} 表示占位符<br>
- * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
- * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
- * 例:<br>
- * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
- * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
- * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
- *
- * @param template 文本模板,被替换的部分用 {} 表示
- * @param params 参数值
- * @return 格式化后的文本
- */
- public static String format(String template, Object... params)
- {
- if (isEmpty(params) || isEmpty(template))
- {
- return template;
- }
- return StrFormatter.format(template, params);
- }
-
- /**
- * 是否为http(s)://开头
- *
- * @param link 链接
- * @return 结果
- */
- public static boolean ishttp(String link)
- {
- return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
- }
-
- /**
- * 字符串转set
- *
- * @param str 字符串
- * @param sep 分隔符
- * @return set集合
- */
- public static final Set<String> str2Set(String str, String sep)
- {
- return new HashSet<String>(str2List(str, sep, true, false));
- }
-
- /**
- * 字符串转list
- *
- * @param str 字符串
- * @param sep 分隔符
- * @return list集合
- */
- public static final List<String> str2List(String str, String sep)
- {
- return str2List(str, sep, true, false);
- }
-
- /**
- * 字符串转list
- *
- * @param str 字符串
- * @param sep 分隔符
- * @param filterBlank 过滤纯空白
- * @param trim 去掉首尾空白
- * @return list集合
- */
- public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
- {
- List<String> list = new ArrayList<String>();
- if (StringUtils.isEmpty(str))
- {
- return list;
- }
-
- // 过滤空白字符串
- if (filterBlank && StringUtils.isBlank(str))
- {
- return list;
- }
- String[] split = str.split(sep);
- for (String string : split)
- {
- if (filterBlank && StringUtils.isBlank(string))
- {
- continue;
- }
- if (trim)
- {
- string = string.trim();
- }
- list.add(string);
- }
-
- return list;
- }
-
- /**
- * 检查子字符串是否存在
- *
- * @param seq 检查的字符串
- * @param searchSeq 查找的字符串
- * @return 结果
- */
- public static boolean contains(final CharSequence seq, final CharSequence searchSeq)
- {
- return Strings.CS.contains(seq, searchSeq);
- }
-
- /**
- * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
- *
- * @param collection 给定的集合
- * @param array 给定的数组
- * @return 结果
- */
- public static boolean containsAny(Collection<String> collection, String... array)
- {
- if (isEmpty(collection) || isEmpty(array))
- {
- return false;
- }
- else
- {
- for (String str : array)
- {
- if (collection.contains(str))
- {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * 判断是否包含给定数组中的任意一个。
- *
- * @param cs 要判断的字符串
- * @param searchCharSequences 要判断的数组
- * @return 结果
- */
- public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences)
- {
- return Strings.CS.containsAny(cs, searchCharSequences);
- }
-
- /**
- * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
- *
- * @param cs 指定字符串
- * @param searchCharSequences 需要检查的字符串数组
- * @return 是否包含任意一个字符串
- */
- public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
- {
- if (isEmpty(cs) || isEmpty(searchCharSequences))
- {
- return false;
- }
- for (CharSequence testStr : searchCharSequences)
- {
- if (containsIgnoreCase(cs, testStr))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * 检查是否包含要搜索的字符串,忽略大小写
- *
- * @param str 要检查的字符串
- * @param searchStr 要查找的字符串
- * @return 如果包含要搜索的字符串(忽略大小写)则返回true,如果不包含或返回false
- */
- public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr)
- {
- return Strings.CI.contains(str, searchStr);
- }
-
- /**
- * 检查字符串是否以任意前缀开始
- *
- * @param sequence 要检查的字符串
- * @param searchStrings 区分大小写的字符串前缀数组
- * @return 结果
- */
- public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings)
- {
- return Strings.CS.startsWithAny(sequence, searchStrings);
- }
-
- /**
- * 不区分大小写地检查一个字符串是否以指定前缀开头。
- *
- * @param str 待检查的字符串
- * @param 要查找的前缀
- * @return 结果
- */
- public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix)
- {
- return Strings.CI.startsWith(str, prefix);
- }
-
- /**
- * 比较两个字符串是否相同
- *
- * @param cs1 第一个字符串
- * @param cs2 第二个字符串
- * @return 如果给定对象与字符串相等,则返回 true;否则返回 false
- */
- public static boolean equals(final CharSequence cs1, final CharSequence cs2)
- {
- return Strings.CS.equals(cs1, cs2);
- }
-
- /**
- * 替换字符串中所有匹配的字符
- *
- * @param text 要搜索和替换的文本
- * @param searchString 要搜索的字符串
- * @param replacement 用于替换的字符串
- * @return 处理完所有替换后的文本
- */
- public static String replace(final String text, final String searchString, final String replacement)
- {
- return Strings.CS.replace(text, searchString, replacement);
- }
-
- /**
- * 仅当子字符串位于源字符串末尾时才将其移除,否则返回源字符串。
- * @param str 要搜索的源字符串
- * @param remove 要搜索并移除的字符串
- * @return 如果找到并移除了字符串,则返回移除后的子字符串
- */
- public static String removeEnd(final String str, final String remove)
- {
- return Strings.CS.removeEnd(str, remove);
- }
-
- /**
- * 查找字符串首次出现位置的索引
- *
- * @param seq 要检查的字符串
- * @param searchSeq 要查找的字符串
- * @return 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
- */
- public static int indexOf(final CharSequence seq, final CharSequence searchSeq)
- {
- return Strings.CS.indexOf(seq, searchSeq);
- }
-
- /**
- * 检查字符串是否以指定的后缀结尾
- *
- * @param str 要检查的字符
- * @param suffix 要检查的后缀
- * @return 若参数与该字符串末尾相符 true;否则 false
- */
- public static boolean endsWith(final CharSequence str, final CharSequence suffix)
- {
- return Strings.CS.endsWith(str, suffix);
- }
-
- /**
- * 将给定的字符串与数组进行比较
- *
- * @param string 要比较的字符串
- * @param searchStrings 字符串数组
- * @return 如果字符串等于(区分大小写){@code searchStrings}中的任意其他元素,则返回true;如果{@code searchStrings}为null或不包含匹配项,则返回false
- */
- public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings)
- {
- return Strings.CS.equalsAny(string, searchStrings);
- }
-
- /**
- * 检查一个字符串是否以任意提供的区分大小写的后缀结尾。
- *
- * @param sequence 要检查的字符串
- * @param searchStrings 要查找的区分大小写的字符串数组
- * @return 如果输入参数{@code sequence}为null且未提供任何{@code searchStrings},或者输入{@code sequence}以任意提供的区分大小写的{@code searchStrings}结尾,则返回{@code true}。
- */
- public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings)
- {
- return Strings.CS.endsWithAny(sequence, searchStrings);
- }
-
- /**
- * 不区分大小写地检查字符序列是否以指定的后缀结尾
- *
- * @param str 要检查的字符序列
- * @param suffix 要查找的后缀
- * @return 如果字符序列以该后缀结尾(不区分大小写),或两者均为{@code null},则返回{@code true}
- */
- public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix)
- {
- return Strings.CI.endsWith(str, suffix);
- }
-
- /**
- * 指定范围内查找字符串,忽略大小写
- *
- * @param str 要检查的字符串
- * @param searchStr 要查找的字符串
- * @return 搜索字符串的第一个索引,如果未找到匹配项则返回 -1
- */
- public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr)
- {
- return Strings.CI.indexOf(str, searchStr);
- }
-
- /**
- * Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
- * returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
- *
- * @param string to compare, may be {@code null}.
- * @param searchStrings a vararg of strings, may be {@code null}.
- * @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
- */
- public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings)
- {
- return Strings.CI.equalsAny(string, searchStrings);
- }
-
- /**
- * 驼峰转下划线命名
- */
- public static String toUnderScoreCase(String str)
- {
- if (str == null)
- {
- return null;
- }
- StringBuilder sb = new StringBuilder();
- // 前置字符是否大写
- boolean preCharIsUpperCase = true;
- // 当前字符是否大写
- boolean curreCharIsUpperCase = true;
- // 下一字符是否大写
- boolean nexteCharIsUpperCase = true;
- for (int i = 0; i < str.length(); i++)
- {
- char c = str.charAt(i);
- if (i > 0)
- {
- preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
- }
- else
- {
- preCharIsUpperCase = false;
- }
-
- curreCharIsUpperCase = Character.isUpperCase(c);
-
- if (i < (str.length() - 1))
- {
- nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
- }
-
- if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
- {
- sb.append(SEPARATOR);
- }
- else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
- {
- sb.append(SEPARATOR);
- }
- sb.append(Character.toLowerCase(c));
- }
-
- return sb.toString();
- }
-
- /**
- * 是否包含字符串
- *
- * @param str 验证字符串
- * @param strs 字符串组
- * @return 包含返回true
- */
- public static boolean inStringIgnoreCase(String str, String... strs)
- {
- if (str != null && strs != null)
- {
- for (String s : strs)
- {
- if (str.equalsIgnoreCase(trim(s)))
- {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * 删除最后一个字符串
- *
- * @param str 输入字符串
- * @param spit 以什么类型结尾的
- * @return 截取后的字符串
- */
- public static String lastStringDel(String str, String spit)
- {
- if (!StringUtils.isEmpty(str) && str.endsWith(spit))
- {
- return str.subSequence(0, str.length() - 1).toString();
- }
- return str;
- }
-
- /**
- * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
- *
- * @param name 转换前的下划线大写方式命名的字符串
- * @return 转换后的驼峰式命名的字符串
- */
- public static String convertToCamelCase(String name)
- {
- StringBuilder result = new StringBuilder();
- // 快速检查
- if (name == null || name.isEmpty())
- {
- // 没必要转换
- return "";
- }
- else if (!name.contains("_"))
- {
- // 不含下划线,仅将首字母大写
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }
- // 用下划线将原始字符串分割
- String[] camels = name.split("_");
- for (String camel : camels)
- {
- // 跳过原始字符串中开头、结尾的下换线或双重下划线
- if (camel.isEmpty())
- {
- continue;
- }
- // 首字母大写
- result.append(camel.substring(0, 1).toUpperCase());
- result.append(camel.substring(1).toLowerCase());
- }
- return result.toString();
- }
-
- /**
- * 驼峰式命名法
- * 例如:user_name->userName
- */
- public static String toCamelCase(String s)
- {
- if (s == null)
- {
- return null;
- }
- if (s.indexOf(SEPARATOR) == -1)
- {
- return s;
- }
- s = s.toLowerCase();
- StringBuilder sb = new StringBuilder(s.length());
- boolean upperCase = false;
- for (int i = 0; i < s.length(); i++)
- {
- char c = s.charAt(i);
-
- if (c == SEPARATOR)
- {
- upperCase = true;
- }
- else if (upperCase)
- {
- sb.append(Character.toUpperCase(c));
- upperCase = false;
- }
- else
- {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- /**
- * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
- *
- * @param str 指定字符串
- * @param strs 需要检查的字符串数组
- * @return 是否匹配
- */
- public static boolean matches(String str, List<String> strs)
- {
- if (isEmpty(str) || isEmpty(strs))
- {
- return false;
- }
- for (String pattern : strs)
- {
- if (isMatch(pattern, str))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * 判断url是否与规则配置:
- * ? 表示单个字符;
- * * 表示一层路径内的任意字符串,不可跨层级;
- * ** 表示任意层路径;
- *
- * @param pattern 匹配规则
- * @param url 需要匹配的url
- * @return
- */
- public static boolean isMatch(String pattern, String url)
- {
- AntPathMatcher matcher = new AntPathMatcher();
- return matcher.match(pattern, url);
- }
-
- @SuppressWarnings("unchecked")
- public static <T> T cast(Object obj)
- {
- return (T) obj;
- }
-
- /**
- * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
- *
- * @param num 数字对象
- * @param size 字符串指定长度
- * @return 返回数字的字符串格式,该字符串为指定长度。
- */
- public static final String padl(final Number num, final int size)
- {
- return padl(num.toString(), size, '0');
- }
-
- /**
- * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
- *
- * @param s 原始字符串
- * @param size 字符串指定长度
- * @param c 用于补齐的字符
- * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
- */
- public static final String padl(final String s, final int size, final char c)
- {
- final StringBuilder sb = new StringBuilder(size);
- if (s != null)
- {
- final int len = s.length();
- if (s.length() <= size)
- {
- for (int i = size - len; i > 0; i--)
- {
- sb.append(c);
- }
- sb.append(s);
- }
- else
- {
- return s.substring(len - size, len);
- }
- }
- else
- {
- for (int i = size; i > 0; i--)
- {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanUtils.java
deleted file mode 100644
index d027cef..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanUtils.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.ruoyi.common.core.utils.bean;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Bean 工具类
- *
- * @author ruoyi
- */
-public class BeanUtils extends org.springframework.beans.BeanUtils
-{
- /** Bean方法名中属性名开始的下标 */
- private static final int BEAN_METHOD_PROP_INDEX = 3;
-
- /** * 匹配getter方法的正则表达式 */
- private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
-
- /** * 匹配setter方法的正则表达式 */
- private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
-
- /**
- * Bean属性复制工具方法。
- *
- * @param dest 目标对象
- * @param src 源对象
- */
- public static void copyBeanProp(Object dest, Object src)
- {
- try
- {
- copyProperties(src, dest);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
-
- /**
- * 获取对象的setter方法。
- *
- * @param obj 对象
- * @return 对象的setter方法列表
- */
- public static List<Method> getSetterMethods(Object obj)
- {
- // setter方法列表
- List<Method> setterMethods = new ArrayList<Method>();
-
- // 获取所有方法
- Method[] methods = obj.getClass().getMethods();
-
- // 查找setter方法
-
- for (Method method : methods)
- {
- Matcher m = SET_PATTERN.matcher(method.getName());
- if (m.matches() && (method.getParameterTypes().length == 1))
- {
- setterMethods.add(method);
- }
- }
- // 返回setter方法列表
- return setterMethods;
- }
-
- /**
- * 获取对象的getter方法。
- *
- * @param obj 对象
- * @return 对象的getter方法列表
- */
-
- public static List<Method> getGetterMethods(Object obj)
- {
- // getter方法列表
- List<Method> getterMethods = new ArrayList<Method>();
- // 获取所有方法
- Method[] methods = obj.getClass().getMethods();
- // 查找getter方法
- for (Method method : methods)
- {
- Matcher m = GET_PATTERN.matcher(method.getName());
- if (m.matches() && (method.getParameterTypes().length == 0))
- {
- getterMethods.add(method);
- }
- }
- // 返回getter方法列表
- return getterMethods;
- }
-
- /**
- * 检查Bean方法名中的属性名是否相等。<br>
- * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
- *
- * @param m1 方法名1
- * @param m2 方法名2
- * @return 属性名一样返回true,否则返回false
- */
-
- public static boolean isMethodPropEquals(String m1, String m2)
- {
- return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java
deleted file mode 100644
index 3e94f84..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.core.utils.bean;
-
-import java.util.Set;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.ConstraintViolationException;
-import jakarta.validation.Validator;
-
-/**
- * bean对象属性验证
- *
- * @author ruoyi
- */
-public class BeanValidators
-{
- public static void validateWithException(Validator validator, Object object, Class<?>... groups)
- throws ConstraintViolationException
- {
- Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
- if (!constraintViolations.isEmpty())
- {
- throw new ConstraintViolationException(constraintViolations);
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileTypeUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileTypeUtils.java
deleted file mode 100644
index fa494b5..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileTypeUtils.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.ruoyi.common.core.utils.file;
-
-import java.io.File;
-import java.util.Objects;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-/**
- * 文件类型工具类
- *
- * @author ruoyi
- */
-public class FileTypeUtils
-{
- /**
- * 获取文件类型
- * <p>
- * 例如: ruoyi.txt, 返回: txt
- *
- * @param file 文件名
- * @return 后缀(不含".")
- */
- public static String getFileType(File file)
- {
- if (null == file)
- {
- return StringUtils.EMPTY;
- }
- return getFileType(file.getName());
- }
-
- /**
- * 获取文件类型
- * <p>
- * 例如: ruoyi.txt, 返回: txt
- *
- * @param fileName 文件名
- * @return 后缀(不含".")
- */
- public static String getFileType(String fileName)
- {
- int separatorIndex = fileName.lastIndexOf(".");
- if (separatorIndex < 0)
- {
- return "";
- }
- return fileName.substring(separatorIndex + 1).toLowerCase();
- }
-
- /**
- * 获取文件名的后缀
- *
- * @param file 表单文件
- * @return 后缀名
- */
- public static final String getExtension(MultipartFile file)
- {
- String extension = FilenameUtils.getExtension(file.getOriginalFilename());
- if (StringUtils.isEmpty(extension))
- {
- extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
- }
- return extension;
- }
-
- /**
- * 获取文件类型
- *
- * @param photoByte 文件字节码
- * @return 后缀(不含".")
- */
- public static String getFileExtendName(byte[] photoByte)
- {
- String strFileExtendName = "JPG";
- if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
- && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
- {
- strFileExtendName = "GIF";
- }
- else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
- {
- strFileExtendName = "JPG";
- }
- else if ((photoByte[0] == 66) && (photoByte[1] == 77))
- {
- strFileExtendName = "BMP";
- }
- else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
- {
- strFileExtendName = "PNG";
- }
- return strFileExtendName;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java
deleted file mode 100644
index fab668a..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package com.ruoyi.common.core.utils.file;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 文件处理工具类
- *
- * @author ruoyi
- */
-public class FileUtils
-{
- /** 字符常量:斜杠 {@code '/'} */
- public static final char SLASH = '/';
-
- /** 字符常量:反斜杠 {@code '\\'} */
- public static final char BACKSLASH = '\\';
-
- public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
-
- /**
- * 输出指定文件的byte数组
- *
- * @param filePath 文件路径
- * @param os 输出流
- * @return
- */
- public static void writeBytes(String filePath, OutputStream os) throws IOException
- {
- FileInputStream fis = null;
- try
- {
- File file = new File(filePath);
- if (!file.exists())
- {
- throw new FileNotFoundException(filePath);
- }
- fis = new FileInputStream(file);
- byte[] b = new byte[1024];
- int length;
- while ((length = fis.read(b)) > 0)
- {
- os.write(b, 0, length);
- }
- }
- catch (IOException e)
- {
- throw e;
- }
- finally
- {
- if (os != null)
- {
- try
- {
- os.close();
- }
- catch (IOException e1)
- {
- e1.printStackTrace();
- }
- }
- if (fis != null)
- {
- try
- {
- fis.close();
- }
- catch (IOException e1)
- {
- e1.printStackTrace();
- }
- }
- }
- }
-
- /**
- * 删除文件
- *
- * @param filePath 文件
- * @return
- */
- public static boolean deleteFile(String filePath)
- {
- boolean flag = false;
- File file = new File(filePath);
- // 路径为文件且不为空则进行删除
- if (file.isFile() && file.exists())
- {
- flag = file.delete();
- }
- return flag;
- }
-
- /**
- * 文件名称验证
- *
- * @param filename 文件名称
- * @return true 正常 false 非法
- */
- public static boolean isValidFilename(String filename)
- {
- return filename.matches(FILENAME_PATTERN);
- }
-
- /**
- * 校验文件路径合法性(安全性与扩展名)
- *
- * @param fileUrl 待校验的文件地址
- * @return true 正常 false 非法
- */
- public static boolean validateFilePath(String fileUrl)
- {
- // 禁止目录上跳级别
- if (StringUtils.contains(fileUrl, ".."))
- {
- return false;
- }
- // 判断是否在允许下载的文件规则内
- return ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(fileUrl));
- }
-
- /**
- * 下载文件名重新编码
- *
- * @param request 请求对象
- * @param fileName 文件名
- * @return 编码后的文件名
- */
- public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
- {
- final String agent = request.getHeader("USER-AGENT");
- String filename = fileName;
- if (agent.contains("MSIE"))
- {
- // IE浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- filename = filename.replace("+", " ");
- }
- else if (agent.contains("Firefox"))
- {
- // 火狐浏览器
- filename = new String(fileName.getBytes(), "ISO8859-1");
- }
- else if (agent.contains("Chrome"))
- {
- // google浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- }
- else
- {
- // 其它浏览器
- filename = URLEncoder.encode(filename, "utf-8");
- }
- return filename;
- }
-
- /**
- * 返回文件名
- *
- * @param filePath 文件
- * @return 文件名
- */
- public static String getName(String filePath)
- {
- if (null == filePath)
- {
- return null;
- }
- int len = filePath.length();
- if (0 == len)
- {
- return filePath;
- }
- if (isFileSeparator(filePath.charAt(len - 1)))
- {
- // 以分隔符结尾的去掉结尾分隔符
- len--;
- }
-
- int begin = 0;
- char c;
- for (int i = len - 1; i > -1; i--)
- {
- c = filePath.charAt(i);
- if (isFileSeparator(c))
- {
- // 查找最后一个路径分隔符(/或者\)
- begin = i + 1;
- break;
- }
- }
-
- return filePath.substring(begin, len);
- }
-
- /**
- * 是否为Windows或者Linux(Unix)文件分隔符<br>
- * Windows平台下分隔符为\,Linux(Unix)为/
- *
- * @param c 字符
- * @return 是否为Windows或者Linux(Unix)文件分隔符
- */
- public static boolean isFileSeparator(char c)
- {
- return SLASH == c || BACKSLASH == c;
- }
-
- /**
- * 下载文件名重新编码
- *
- * @param response 响应对象
- * @param realFileName 真实文件名
- * @return
- */
- public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
- {
- String percentEncodedFileName = percentEncode(realFileName);
-
- StringBuilder contentDispositionValue = new StringBuilder();
- contentDispositionValue.append("attachment; filename=")
- .append(percentEncodedFileName)
- .append(";")
- .append("filename*=")
- .append("utf-8''")
- .append(percentEncodedFileName);
-
- response.setHeader("Content-disposition", contentDispositionValue.toString());
- response.setHeader("download-filename", percentEncodedFileName);
- }
-
- /**
- * 百分号编码工具方法
- *
- * @param s 需要百分号编码的字符串
- * @return 百分号编码后的字符串
- */
- public static String percentEncode(String s) throws UnsupportedEncodingException
- {
- String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
- return encode.replaceAll("\\+", "%20");
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/ImageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/ImageUtils.java
deleted file mode 100644
index c3b19fc..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/ImageUtils.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.ruoyi.common.core.utils.file;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Arrays;
-import org.apache.poi.util.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 图片处理工具类
- *
- * @author ruoyi
- */
-public class ImageUtils
-{
- private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
-
- public static byte[] getImage(String imagePath)
- {
- InputStream is = getFile(imagePath);
- try
- {
- return IOUtils.toByteArray(is);
- }
- catch (Exception e)
- {
- log.error("图片加载异常 {}", e);
- return null;
- }
- finally
- {
- IOUtils.closeQuietly(is);
- }
- }
-
- public static InputStream getFile(String imagePath)
- {
- try
- {
- byte[] result = readFile(imagePath);
- result = Arrays.copyOf(result, result.length);
- return new ByteArrayInputStream(result);
- }
- catch (Exception e)
- {
- log.error("获取图片异常 {}", e);
- }
- return null;
- }
-
- /**
- * 读取文件为字节数据
- *
- * @param url 地址
- * @return 字节数据
- */
- public static byte[] readFile(String url)
- {
- InputStream in = null;
- try
- {
- // 网络地址
- URL urlObj = new URL(url);
- URLConnection urlConnection = urlObj.openConnection();
- urlConnection.setConnectTimeout(30 * 1000);
- urlConnection.setReadTimeout(60 * 1000);
- urlConnection.setDoInput(true);
- in = urlConnection.getInputStream();
- return IOUtils.toByteArray(in);
- }
- catch (Exception e)
- {
- log.error("访问文件异常 {}", e);
- return null;
- }
- finally
- {
- IOUtils.closeQuietly(in);
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/MimeTypeUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/MimeTypeUtils.java
deleted file mode 100644
index b8a3bc3..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/MimeTypeUtils.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.common.core.utils.file;
-
-/**
- * 媒体类型工具类
- *
- * @author ruoyi
- */
-public class MimeTypeUtils
-{
- public static final String IMAGE_PNG = "image/png";
-
- public static final String IMAGE_JPG = "image/jpg";
-
- public static final String IMAGE_JPEG = "image/jpeg";
-
- public static final String IMAGE_BMP = "image/bmp";
-
- public static final String IMAGE_GIF = "image/gif";
-
- public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
-
- public static final String[] FLASH_EXTENSION = { "swf", "flv" };
-
- public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
- "asf", "rm", "rmvb" };
-
- public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
-
- public static final String[] DEFAULT_ALLOWED_EXTENSION = {
- // 图片
- "bmp", "gif", "jpg", "jpeg", "png",
- // word excel powerpoint
- "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
- // 压缩文件
- "rar", "zip", "gz", "bz2",
- // 视频格式
- "mp4", "avi", "rmvb",
- // pdf
- "pdf" };
-
- public static String getExtension(String prefix)
- {
- switch (prefix)
- {
- case IMAGE_PNG:
- return "png";
- case IMAGE_JPG:
- return "jpg";
- case IMAGE_JPEG:
- return "jpeg";
- case IMAGE_BMP:
- return "bmp";
- case IMAGE_GIF:
- return "gif";
- default:
- return "";
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/EscapeUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/EscapeUtil.java
deleted file mode 100644
index 2f5a872..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/EscapeUtil.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package com.ruoyi.common.core.utils.html;
-
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 转义和反转义工具类
- *
- * @author ruoyi
- */
-public class EscapeUtil
-{
- public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
-
- private static final char[][] TEXT = new char[64][];
-
- static
- {
- for (int i = 0; i < 64; i++)
- {
- TEXT[i] = new char[] { (char) i };
- }
-
- // special HTML characters
- TEXT['\''] = "'".toCharArray(); // 单引号
- TEXT['"'] = """.toCharArray(); // 双引号
- TEXT['&'] = "&".toCharArray(); // &符
- TEXT['<'] = "<".toCharArray(); // 小于号
- TEXT['>'] = ">".toCharArray(); // 大于号
- }
-
- /**
- * 转义文本中的HTML字符为安全的字符
- *
- * @param text 被转义的文本
- * @return 转义后的文本
- */
- public static String escape(String text)
- {
- return encode(text);
- }
-
- /**
- * 还原被转义的HTML特殊字符
- *
- * @param content 包含转义符的HTML内容
- * @return 转换后的字符串
- */
- public static String unescape(String content)
- {
- return decode(content);
- }
-
- /**
- * 清除所有HTML标签,但是不删除标签内的内容
- *
- * @param content 文本
- * @return 清除标签后的文本
- */
- public static String clean(String content)
- {
- return new HTMLFilter().filter(content);
- }
-
- /**
- * Escape编码
- *
- * @param text 被编码的文本
- * @return 编码后的字符
- */
- private static String encode(String text)
- {
- if (StringUtils.isEmpty(text))
- {
- return StringUtils.EMPTY;
- }
-
- final StringBuilder tmp = new StringBuilder(text.length() * 6);
- char c;
- for (int i = 0; i < text.length(); i++)
- {
- c = text.charAt(i);
- if (c < 256)
- {
- tmp.append("%");
- if (c < 16)
- {
- tmp.append("0");
- }
- tmp.append(Integer.toString(c, 16));
- }
- else
- {
- tmp.append("%u");
- if (c <= 0xfff)
- {
- // issue#I49JU8@Gitee
- tmp.append("0");
- }
- tmp.append(Integer.toString(c, 16));
- }
- }
- return tmp.toString();
- }
-
- /**
- * Escape解码
- *
- * @param content 被转义的内容
- * @return 解码后的字符串
- */
- public static String decode(String content)
- {
- if (StringUtils.isEmpty(content))
- {
- return content;
- }
-
- StringBuilder tmp = new StringBuilder(content.length());
- int lastPos = 0, pos = 0;
- char ch;
- while (lastPos < content.length())
- {
- pos = content.indexOf("%", lastPos);
- if (pos == lastPos)
- {
- if (content.charAt(pos + 1) == 'u')
- {
- ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
- tmp.append(ch);
- lastPos = pos + 6;
- }
- else
- {
- ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
- tmp.append(ch);
- lastPos = pos + 3;
- }
- }
- else
- {
- if (pos == -1)
- {
- tmp.append(content.substring(lastPos));
- lastPos = content.length();
- }
- else
- {
- tmp.append(content.substring(lastPos, pos));
- lastPos = pos;
- }
- }
- }
- return tmp.toString();
- }
-
- public static void main(String[] args)
- {
- String html = "<script>alert(1);</script>";
- String escape = EscapeUtil.escape(html);
- // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
- // String html = "<123";
- // String html = "123>";
- System.out.println("clean: " + EscapeUtil.clean(html));
- System.out.println("escape: " + escape);
- System.out.println("unescape: " + EscapeUtil.unescape(escape));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/HTMLFilter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/HTMLFilter.java
deleted file mode 100644
index ba53dc9..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/html/HTMLFilter.java
+++ /dev/null
@@ -1,570 +0,0 @@
-package com.ruoyi.common.core.utils.html;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * HTML过滤器,用于去除XSS漏洞隐患。
- *
- * @author ruoyi
- */
-public final class HTMLFilter
-{
- /**
- * regex flag union representing /si modifiers in php
- **/
- private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
- private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
- private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
- private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
- private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
- private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
- private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
- private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
- private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
- private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
- private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
- private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
- private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
- private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
- private static final Pattern P_END_ARROW = Pattern.compile("^>");
- private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
- private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
- private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
- private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
- private static final Pattern P_AMP = Pattern.compile("&");
- private static final Pattern P_QUOTE = Pattern.compile("\"");
- private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
- private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
- private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
-
- // @xxx could grow large... maybe use sesat's ReferenceMap
- private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
- private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
-
- /**
- * set of allowed html elements, along with allowed attributes for each element
- **/
- private final Map<String, List<String>> vAllowed;
- /**
- * counts of open tags for each (allowable) html element
- **/
- private final Map<String, Integer> vTagCounts = new HashMap<>();
-
- /**
- * html elements which must always be self-closing (e.g. "<img />")
- **/
- private final String[] vSelfClosingTags;
- /**
- * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
- **/
- private final String[] vNeedClosingTags;
- /**
- * set of disallowed html elements
- **/
- private final String[] vDisallowed;
- /**
- * attributes which should be checked for valid protocols
- **/
- private final String[] vProtocolAtts;
- /**
- * allowed protocols
- **/
- private final String[] vAllowedProtocols;
- /**
- * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
- **/
- private final String[] vRemoveBlanks;
- /**
- * entities allowed within html markup
- **/
- private final String[] vAllowedEntities;
- /**
- * flag determining whether comments are allowed in input String.
- */
- private final boolean stripComment;
- private final boolean encodeQuotes;
- /**
- * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
- * becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
- */
- private final boolean alwaysMakeTags;
-
- /**
- * Default constructor.
- */
- public HTMLFilter()
- {
- vAllowed = new HashMap<>();
-
- final ArrayList<String> a_atts = new ArrayList<>();
- a_atts.add("href");
- a_atts.add("target");
- vAllowed.put("a", a_atts);
-
- final ArrayList<String> img_atts = new ArrayList<>();
- img_atts.add("src");
- img_atts.add("width");
- img_atts.add("height");
- img_atts.add("alt");
- vAllowed.put("img", img_atts);
-
- final ArrayList<String> no_atts = new ArrayList<>();
- vAllowed.put("b", no_atts);
- vAllowed.put("strong", no_atts);
- vAllowed.put("i", no_atts);
- vAllowed.put("em", no_atts);
-
- vSelfClosingTags = new String[] { "img" };
- vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
- vDisallowed = new String[] {};
- vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
- vProtocolAtts = new String[] { "src", "href" };
- vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
- vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
- stripComment = true;
- encodeQuotes = true;
- alwaysMakeTags = false;
- }
-
- /**
- * Map-parameter configurable constructor.
- *
- * @param conf map containing configuration. keys match field names.
- */
- @SuppressWarnings("unchecked")
- public HTMLFilter(final Map<String, Object> conf)
- {
-
- assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
- assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
- assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
- assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
- assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
- assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
- assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
- assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
-
- vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
- vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
- vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
- vDisallowed = (String[]) conf.get("vDisallowed");
- vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
- vProtocolAtts = (String[]) conf.get("vProtocolAtts");
- vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
- vAllowedEntities = (String[]) conf.get("vAllowedEntities");
- stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
- encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
- alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
- }
-
- private void reset()
- {
- vTagCounts.clear();
- }
-
- // ---------------------------------------------------------------
- // my versions of some PHP library functions
- public static String chr(final int decimal)
- {
- return String.valueOf((char) decimal);
- }
-
- public static String htmlSpecialChars(final String s)
- {
- String result = s;
- result = regexReplace(P_AMP, "&", result);
- result = regexReplace(P_QUOTE, """, result);
- result = regexReplace(P_LEFT_ARROW, "<", result);
- result = regexReplace(P_RIGHT_ARROW, ">", result);
- return result;
- }
-
- // ---------------------------------------------------------------
-
- /**
- * given a user submitted input String, filter out any invalid or restricted html.
- *
- * @param input text (i.e. submitted by a user) than may contain html
- * @return "clean" version of input, with only valid, whitelisted html elements allowed
- */
- public String filter(final String input)
- {
- reset();
- String s = input;
-
- s = escapeComments(s);
-
- s = balanceHTML(s);
-
- s = checkTags(s);
-
- s = processRemoveBlanks(s);
-
- // s = validateEntities(s);
-
- return s;
- }
-
- public boolean isAlwaysMakeTags()
- {
- return alwaysMakeTags;
- }
-
- public boolean isStripComments()
- {
- return stripComment;
- }
-
- private String escapeComments(final String s)
- {
- final Matcher m = P_COMMENTS.matcher(s);
- final StringBuffer buf = new StringBuffer();
- if (m.find())
- {
- final String match = m.group(1); // (.*?)
- m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
- }
- m.appendTail(buf);
-
- return buf.toString();
- }
-
- private String balanceHTML(String s)
- {
- if (alwaysMakeTags)
- {
- //
- // try and form html
- //
- s = regexReplace(P_END_ARROW, "", s);
- // 不追加结束标签
- s = regexReplace(P_BODY_TO_END, "<$1>", s);
- s = regexReplace(P_XML_CONTENT, "$1<$2", s);
-
- }
- else
- {
- //
- // escape stray brackets
- //
- s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
- s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
-
- //
- // the last regexp causes '<>' entities to appear
- // (we need to do a lookahead assertion so that the last bracket can
- // be used in the next pass of the regexp)
- //
- s = regexReplace(P_BOTH_ARROWS, "", s);
- }
-
- return s;
- }
-
- private String checkTags(String s)
- {
- Matcher m = P_TAGS.matcher(s);
-
- final StringBuffer buf = new StringBuffer();
- while (m.find())
- {
- String replaceStr = m.group(1);
- replaceStr = processTag(replaceStr);
- m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
- }
- m.appendTail(buf);
-
- // these get tallied in processTag
- // (remember to reset before subsequent calls to filter method)
- final StringBuilder sBuilder = new StringBuilder(buf.toString());
- for (String key : vTagCounts.keySet())
- {
- for (int ii = 0; ii < vTagCounts.get(key); ii++)
- {
- sBuilder.append("</").append(key).append(">");
- }
- }
- s = sBuilder.toString();
-
- return s;
- }
-
- private String processRemoveBlanks(final String s)
- {
- String result = s;
- for (String tag : vRemoveBlanks)
- {
- if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
- {
- P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
- }
- result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
- if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
- {
- P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
- }
- result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
- }
-
- return result;
- }
-
- private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
- {
- Matcher m = regex_pattern.matcher(s);
- return m.replaceAll(replacement);
- }
-
- private String processTag(final String s)
- {
- // ending tags
- Matcher m = P_END_TAG.matcher(s);
- if (m.find())
- {
- final String name = m.group(1).toLowerCase();
- if (allowed(name))
- {
- if (!inArray(name, vSelfClosingTags))
- {
- if (vTagCounts.containsKey(name))
- {
- vTagCounts.put(name, vTagCounts.get(name) - 1);
- return "</" + name + ">";
- }
- }
- }
- }
-
- // starting tags
- m = P_START_TAG.matcher(s);
- if (m.find())
- {
- final String name = m.group(1).toLowerCase();
- final String body = m.group(2);
- String ending = m.group(3);
-
- // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
- if (allowed(name))
- {
- final StringBuilder params = new StringBuilder();
-
- final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
- final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
- final List<String> paramNames = new ArrayList<>();
- final List<String> paramValues = new ArrayList<>();
- while (m2.find())
- {
- paramNames.add(m2.group(1)); // ([a-z0-9]+)
- paramValues.add(m2.group(3)); // (.*?)
- }
- while (m3.find())
- {
- paramNames.add(m3.group(1)); // ([a-z0-9]+)
- paramValues.add(m3.group(3)); // ([^\"\\s']+)
- }
-
- String paramName, paramValue;
- for (int ii = 0; ii < paramNames.size(); ii++)
- {
- paramName = paramNames.get(ii).toLowerCase();
- paramValue = paramValues.get(ii);
-
- // debug( "paramName='" + paramName + "'" );
- // debug( "paramValue='" + paramValue + "'" );
- // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
-
- if (allowedAttribute(name, paramName))
- {
- if (inArray(paramName, vProtocolAtts))
- {
- paramValue = processParamProtocol(paramValue);
- }
- params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
- }
- }
-
- if (inArray(name, vSelfClosingTags))
- {
- ending = " /";
- }
-
- if (inArray(name, vNeedClosingTags))
- {
- ending = "";
- }
-
- if (ending == null || ending.length() < 1)
- {
- if (vTagCounts.containsKey(name))
- {
- vTagCounts.put(name, vTagCounts.get(name) + 1);
- }
- else
- {
- vTagCounts.put(name, 1);
- }
- }
- else
- {
- ending = " /";
- }
- return "<" + name + params + ending + ">";
- }
- else
- {
- return "";
- }
- }
-
- // comments
- m = P_COMMENT.matcher(s);
- if (!stripComment && m.find())
- {
- return "<" + m.group() + ">";
- }
-
- return "";
- }
-
- private String processParamProtocol(String s)
- {
- s = decodeEntities(s);
- final Matcher m = P_PROTOCOL.matcher(s);
- if (m.find())
- {
- final String protocol = m.group(1);
- if (!inArray(protocol, vAllowedProtocols))
- {
- // bad protocol, turn into local anchor link instead
- s = "#" + s.substring(protocol.length() + 1);
- if (s.startsWith("#//"))
- {
- s = "#" + s.substring(3);
- }
- }
- }
-
- return s;
- }
-
- private String decodeEntities(String s)
- {
- StringBuffer buf = new StringBuffer();
-
- Matcher m = P_ENTITY.matcher(s);
- while (m.find())
- {
- final String match = m.group(1);
- final int decimal = Integer.decode(match).intValue();
- m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
- }
- m.appendTail(buf);
- s = buf.toString();
-
- buf = new StringBuffer();
- m = P_ENTITY_UNICODE.matcher(s);
- while (m.find())
- {
- final String match = m.group(1);
- final int decimal = Integer.valueOf(match, 16).intValue();
- m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
- }
- m.appendTail(buf);
- s = buf.toString();
-
- buf = new StringBuffer();
- m = P_ENCODE.matcher(s);
- while (m.find())
- {
- final String match = m.group(1);
- final int decimal = Integer.valueOf(match, 16).intValue();
- m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
- }
- m.appendTail(buf);
- s = buf.toString();
-
- s = validateEntities(s);
- return s;
- }
-
- private String validateEntities(final String s)
- {
- StringBuffer buf = new StringBuffer();
-
- // validate entities throughout the string
- Matcher m = P_VALID_ENTITIES.matcher(s);
- while (m.find())
- {
- final String one = m.group(1); // ([^&;]*)
- final String two = m.group(2); // (?=(;|&|$))
- m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
- }
- m.appendTail(buf);
-
- return encodeQuotes(buf.toString());
- }
-
- private String encodeQuotes(final String s)
- {
- if (encodeQuotes)
- {
- StringBuffer buf = new StringBuffer();
- Matcher m = P_VALID_QUOTES.matcher(s);
- while (m.find())
- {
- final String one = m.group(1); // (>|^)
- final String two = m.group(2); // ([^<]+?)
- final String three = m.group(3); // (<|$)
- // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two)
- m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
- }
- m.appendTail(buf);
- return buf.toString();
- }
- else
- {
- return s;
- }
- }
-
- private String checkEntity(final String preamble, final String term)
- {
-
- return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble;
- }
-
- private boolean isValidEntity(final String entity)
- {
- return inArray(entity, vAllowedEntities);
- }
-
- private static boolean inArray(final String s, final String[] array)
- {
- for (String item : array)
- {
- if (item != null && item.equals(s))
- {
- return true;
- }
- }
- return false;
- }
-
- private boolean allowed(final String name)
- {
- return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
- }
-
- private boolean allowedAttribute(final String name, final String paramName)
- {
- return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ip/IpUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ip/IpUtils.java
deleted file mode 100644
index 878ed91..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ip/IpUtils.java
+++ /dev/null
@@ -1,382 +0,0 @@
-package com.ruoyi.common.core.utils.ip;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import jakarta.servlet.http.HttpServletRequest;
-import com.ruoyi.common.core.utils.ServletUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 获取IP方法
- *
- * @author ruoyi
- */
-public class IpUtils
-{
- public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
- // 匹配 ip
- public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
- public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
- // 匹配网段
- public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
-
- /**
- * 获取客户端IP
- *
- * @return IP地址
- */
- public static String getIpAddr()
- {
- return getIpAddr(ServletUtils.getRequest());
- }
-
- /**
- * 获取客户端IP
- *
- * @param request 请求对象
- * @return IP地址
- */
- public static String getIpAddr(HttpServletRequest request)
- {
- if (request == null)
- {
- return "unknown";
- }
- String ip = request.getHeader("x-forwarded-for");
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
- {
- ip = request.getHeader("Proxy-Client-IP");
- }
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
- {
- ip = request.getHeader("X-Forwarded-For");
- }
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
- {
- ip = request.getHeader("WL-Proxy-Client-IP");
- }
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
- {
- ip = request.getHeader("X-Real-IP");
- }
-
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
- {
- ip = request.getRemoteAddr();
- }
-
- return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
- }
-
- /**
- * 检查是否为内部IP地址
- *
- * @param ip IP地址
- * @return 结果
- */
- public static boolean internalIp(String ip)
- {
- byte[] addr = textToNumericFormatV4(ip);
- return internalIp(addr) || "127.0.0.1".equals(ip);
- }
-
- /**
- * 检查是否为内部IP地址
- *
- * @param addr byte地址
- * @return 结果
- */
- private static boolean internalIp(byte[] addr)
- {
- if (StringUtils.isNull(addr) || addr.length < 2)
- {
- return true;
- }
- final byte b0 = addr[0];
- final byte b1 = addr[1];
- // 10.x.x.x/8
- final byte SECTION_1 = 0x0A;
- // 172.16.x.x/12
- final byte SECTION_2 = (byte) 0xAC;
- final byte SECTION_3 = (byte) 0x10;
- final byte SECTION_4 = (byte) 0x1F;
- // 192.168.x.x/16
- final byte SECTION_5 = (byte) 0xC0;
- final byte SECTION_6 = (byte) 0xA8;
- switch (b0)
- {
- case SECTION_1:
- return true;
- case SECTION_2:
- if (b1 >= SECTION_3 && b1 <= SECTION_4)
- {
- return true;
- }
- case SECTION_5:
- switch (b1)
- {
- case SECTION_6:
- return true;
- }
- default:
- return false;
- }
- }
-
- /**
- * 将IPv4地址转换成字节
- *
- * @param text IPv4地址
- * @return byte 字节
- */
- public static byte[] textToNumericFormatV4(String text)
- {
- if (text.length() == 0)
- {
- return null;
- }
-
- byte[] bytes = new byte[4];
- String[] elements = text.split("\\.", -1);
- try
- {
- long l;
- int i;
- switch (elements.length)
- {
- case 1:
- l = Long.parseLong(elements[0]);
- if ((l < 0L) || (l > 4294967295L))
- {
- return null;
- }
- bytes[0] = (byte) (int) (l >> 24 & 0xFF);
- bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
- bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
- bytes[3] = (byte) (int) (l & 0xFF);
- break;
- case 2:
- l = Integer.parseInt(elements[0]);
- if ((l < 0L) || (l > 255L))
- {
- return null;
- }
- bytes[0] = (byte) (int) (l & 0xFF);
- l = Integer.parseInt(elements[1]);
- if ((l < 0L) || (l > 16777215L))
- {
- return null;
- }
- bytes[1] = (byte) (int) (l >> 16 & 0xFF);
- bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
- bytes[3] = (byte) (int) (l & 0xFF);
- break;
- case 3:
- for (i = 0; i < 2; ++i)
- {
- l = Integer.parseInt(elements[i]);
- if ((l < 0L) || (l > 255L))
- {
- return null;
- }
- bytes[i] = (byte) (int) (l & 0xFF);
- }
- l = Integer.parseInt(elements[2]);
- if ((l < 0L) || (l > 65535L))
- {
- return null;
- }
- bytes[2] = (byte) (int) (l >> 8 & 0xFF);
- bytes[3] = (byte) (int) (l & 0xFF);
- break;
- case 4:
- for (i = 0; i < 4; ++i)
- {
- l = Integer.parseInt(elements[i]);
- if ((l < 0L) || (l > 255L))
- {
- return null;
- }
- bytes[i] = (byte) (int) (l & 0xFF);
- }
- break;
- default:
- return null;
- }
- }
- catch (NumberFormatException e)
- {
- return null;
- }
- return bytes;
- }
-
- /**
- * 获取IP地址
- *
- * @return 本地IP地址
- */
- public static String getHostIp()
- {
- try
- {
- return InetAddress.getLocalHost().getHostAddress();
- }
- catch (UnknownHostException e)
- {
- }
- return "127.0.0.1";
- }
-
- /**
- * 获取主机名
- *
- * @return 本地主机名
- */
- public static String getHostName()
- {
- try
- {
- return InetAddress.getLocalHost().getHostName();
- }
- catch (UnknownHostException e)
- {
- }
- return "未知";
- }
-
- /**
- * 从多级反向代理中获得第一个非unknown IP地址
- *
- * @param ip 获得的IP地址
- * @return 第一个非unknown IP地址
- */
- public static String getMultistageReverseProxyIp(String ip)
- {
- // 多级反向代理检测
- if (ip != null && ip.indexOf(",") > 0)
- {
- final String[] ips = ip.trim().split(",");
- for (String subIp : ips)
- {
- if (false == isUnknown(subIp))
- {
- ip = subIp;
- break;
- }
- }
- }
- return StringUtils.substring(ip, 0, 255);
- }
-
- /**
- * 检测给定字符串是否为未知,多用于检测HTTP请求相关
- *
- * @param checkString 被检测的字符串
- * @return 是否未知
- */
- public static boolean isUnknown(String checkString)
- {
- return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
- }
-
- /**
- * 是否为IP
- */
- public static boolean isIP(String ip)
- {
- return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
- }
-
- /**
- * 是否为IP,或 *为间隔的通配符地址
- */
- public static boolean isIpWildCard(String ip)
- {
- return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
- }
-
- /**
- * 检测参数是否在ip通配符里
- */
- public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
- {
- String[] s1 = ipWildCard.split("\\.");
- String[] s2 = ip.split("\\.");
- boolean isMatchedSeg = true;
- for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
- {
- if (!s1[i].equals(s2[i]))
- {
- isMatchedSeg = false;
- break;
- }
- }
- return isMatchedSeg;
- }
-
- /**
- * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
- */
- public static boolean isIPSegment(String ipSeg)
- {
- return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
- }
-
- /**
- * 判断ip是否在指定网段中
- */
- public static boolean ipIsInNetNoCheck(String iparea, String ip)
- {
- int idx = iparea.indexOf('-');
- String[] sips = iparea.substring(0, idx).split("\\.");
- String[] sipe = iparea.substring(idx + 1).split("\\.");
- String[] sipt = ip.split("\\.");
- long ips = 0L, ipe = 0L, ipt = 0L;
- for (int i = 0; i < 4; ++i)
- {
- ips = ips << 8 | Integer.parseInt(sips[i]);
- ipe = ipe << 8 | Integer.parseInt(sipe[i]);
- ipt = ipt << 8 | Integer.parseInt(sipt[i]);
- }
- if (ips > ipe)
- {
- long t = ips;
- ips = ipe;
- ipe = t;
- }
- return ips <= ipt && ipt <= ipe;
- }
-
- /**
- * 校验ip是否符合过滤串规则
- *
- * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
- * @param ip 校验IP地址
- * @return boolean 结果
- */
- public static boolean isMatchedIp(String filter, String ip)
- {
- if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
- {
- return false;
- }
- String[] ips = filter.split(";");
- for (String iStr : ips)
- {
- if (isIP(iStr) && iStr.equals(ip))
- {
- return true;
- }
- else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
- {
- return true;
- }
- else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
- {
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelHandlerAdapter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelHandlerAdapter.java
deleted file mode 100644
index f8f863e..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelHandlerAdapter.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.core.utils.poi;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Workbook;
-
-/**
- * Excel数据格式处理适配器
- *
- * @author ruoyi
- */
-public interface ExcelHandlerAdapter
-{
- /**
- * 格式化
- *
- * @param value 单元格数据值
- * @param args excel注解args参数组
- * @param cell 单元格对象
- * @param wb 工作簿对象
- *
- * @return 处理后的值
- */
- Object format(Object value, String[] args, Cell cell, Workbook wb);
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelSheet.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelSheet.java
deleted file mode 100644
index f72e888..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelSheet.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.ruoyi.common.core.utils.poi;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * 多 Sheet 导出时的数据信息
- *
- * 使用示例:
- * <pre>
- * List<ExcelSheet<?>> sheets = new ArrayList<>();
- * sheets.add(new ExcelSheet<>("参数数据", configList, Config.class, "参数信息"));
- * sheets.add(new ExcelSheet<>("岗位数据", postList, Post.class, "岗位信息"));
- * return ExcelUtil.exportMultiSheet(sheets);
- * </pre>
- *
- * @author ruoyi
- */
-public class ExcelSheet<T>
-{
- /** Sheet 名称 */
- private String sheetName;
-
- /** 导出数据集合 */
- private List<T> list;
-
- /** 数据对应的实体 Class */
- private Class<T> clazz;
-
- /** Sheet 顶部大标题(可为空) */
- private String title;
-
- public ExcelSheet(String sheetName, List<T> list, Class<T> clazz)
- {
- this(sheetName, list, clazz, "");
- }
-
- public ExcelSheet(String sheetName, List<T> list, Class<T> clazz, String title)
- {
- this.sheetName = sheetName;
- this.list = list != null ? list : new ArrayList<>();
- this.clazz = clazz;
- this.title = title != null ? title : "";
- }
-
- public String getSheetName()
- {
- return sheetName;
- }
-
- public List<T> getList()
- {
- return list;
- }
-
- public Class<T> getClazz()
- {
- return clazz;
- }
-
- public String getTitle()
- {
- return title;
- }
-
- public void setSheetName(String sheetName)
- {
- this.sheetName = sheetName;
- }
-
- public void setList(List<T> list)
- {
- this.list = list;
- }
-
- public void setClazz(Class<T> clazz)
- {
- this.clazz = clazz;
- }
-
- public void setTitle(String title)
- {
- this.title = title;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java
deleted file mode 100644
index 1320e8b..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java
+++ /dev/null
@@ -1,1765 +0,0 @@
-package com.ruoyi.common.core.utils.poi;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.RegExUtils;
-import org.apache.commons.lang3.reflect.FieldUtils;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.DataFormat;
-import org.apache.poi.ss.usermodel.DataValidation;
-import org.apache.poi.ss.usermodel.DataValidationConstraint;
-import org.apache.poi.ss.usermodel.DataValidationHelper;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Name;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.annotation.Excel.Type;
-import com.ruoyi.common.core.annotation.Excels;
-import com.ruoyi.common.core.exception.UtilException;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.file.FileTypeUtils;
-import com.ruoyi.common.core.utils.file.ImageUtils;
-import com.ruoyi.common.core.utils.reflect.ReflectUtils;
-
-/**
- * Excel相关处理
- *
- * @author ruoyi
- */
-public class ExcelUtil<T>
-{
- private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
-
- public static final String SEPARATOR = ",";
-
- public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
-
- public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
-
- /**
- * 单元格样式缓存
- */
- private Map<String, CellStyle> cellStyleCache = new HashMap<String, CellStyle>();
-
- /**
- * Excel sheet最大行数,默认65536
- */
- public static final int sheetSize = 65536;
-
- /**
- * 工作表名称
- */
- private String sheetName;
-
- /**
- * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
- */
- private Type type;
-
- /**
- * 工作薄对象
- */
- private Workbook wb;
-
- /**
- * 工作表对象
- */
- private Sheet sheet;
-
- /**
- * 样式列表
- */
- private Map<String, CellStyle> styles;
-
- /**
- * 导入导出数据列表
- */
- private List<T> list;
-
- /**
- * 注解列表
- */
- private List<Object[]> fields;
-
- /**
- * 当前行号
- */
- private int rownum;
-
- /**
- * 标题
- */
- private String title;
-
- /**
- * 最大高度
- */
- private short maxHeight;
-
- /**
- * 合并后最后行数
- */
- private int subMergedLastRowNum = 0;
-
- /**
- * 合并后开始行数
- */
- private int subMergedFirstRowNum = 1;
-
- /**
- * 对象的子列表方法
- */
- private Map<String, Method> subMethods;
-
- /**
- * 对象的子列表属性
- */
- private Map<String, List<Field>> subFieldsMap;
-
- /**
- * 统计列表
- */
- private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
-
- /**
- * 实体对象
- */
- public Class<T> clazz;
-
- /**
- * 需要显示列属性
- */
- public String[] includeFields;
-
- /**
- * 需要排除列属性
- */
- public String[] excludeFields;
-
- public ExcelUtil(Class<T> clazz)
- {
- this.clazz = clazz;
- }
-
- /**
- * 仅在Excel中显示列属性
- *
- * @param fields 列属性名 示例[单个"name"/多个"id","name"]
- */
- public void showColumn(String... fields)
- {
- this.includeFields = fields;
- }
-
- /**
- * 隐藏Excel中列属性
- *
- * @param fields 列属性名 示例[单个"name"/多个"id","name"]
- */
- public void hideColumn(String... fields)
- {
- this.excludeFields = fields;
- }
-
- public void init(List<T> list, String sheetName, String title, Type type)
- {
- if (list == null)
- {
- list = new ArrayList<T>();
- }
- this.list = list;
- this.sheetName = sheetName;
- this.type = type;
- this.title = title;
- createExcelField();
- createWorkbook();
- createTitle();
- createSubHead();
- }
-
- /**
- * 创建excel第一行标题
- */
- public void createTitle()
- {
- if (StringUtils.isNotEmpty(title))
- {
- int titleLastCol = this.fields.size() - 1;
- if (isSubList())
- {
- for (List<Field> currentSubFields : subFieldsMap.values())
- {
- titleLastCol = titleLastCol + currentSubFields.size() - 1;
- }
- }
- Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
- titleRow.setHeightInPoints(30);
- Cell titleCell = titleRow.createCell(0);
- titleCell.setCellStyle(styles.get("title"));
- titleCell.setCellValue(title);
- sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
- }
- }
-
- /**
- * 创建对象的子列表名称
- */
- public void createSubHead()
- {
- if (isSubList())
- {
- Row subRow = sheet.createRow(rownum);
- int column = 0;
- for (Object[] objects : fields)
- {
- Field field = (Field) objects[0];
- Excel attr = (Excel) objects[1];
- CellStyle cellStyle = styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()));
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- Cell cell = subRow.createCell(column);
- cell.setCellValue(attr.name());
- cell.setCellStyle(cellStyle);
- int subFieldSize = subFieldsMap != null ? subFieldsMap.get(field.getName()).size() : 0;
- if (subFieldSize > 1)
- {
- CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
- sheet.addMergedRegion(cellAddress);
- }
- column += subFieldSize;
- }
- else
- {
- Cell cell = subRow.createCell(column++);
- cell.setCellValue(attr.name());
- cell.setCellStyle(cellStyle);
- }
- }
- rownum++;
- }
- }
-
- /**
- * 对excel表单默认第一个索引名转换成list
- *
- * @param is 输入流
- * @return 转换后集合
- */
- public List<T> importExcel(InputStream is)
- {
- return importExcel(is, 0);
- }
-
- /**
- * 对excel表单默认第一个索引名转换成list
- *
- * @param is 输入流
- * @param titleNum 标题占用行数
- * @return 转换后集合
- */
- public List<T> importExcel(InputStream is, int titleNum)
- {
- List<T> list = null;
- try
- {
- list = importExcel(StringUtils.EMPTY, is, titleNum);
- }
- catch (Exception e)
- {
- log.error("导入Excel异常{}", e.getMessage());
- throw new UtilException(e.getMessage());
- }
- finally
- {
- IOUtils.closeQuietly(is);
- }
- return list;
- }
-
- /**
- * 对excel表单指定表格索引名转换成list
- *
- * @param sheetName 表格索引名
- * @param titleNum 标题占用行数
- * @param is 输入流
- * @return 转换后集合
- */
- public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
- {
- this.type = Type.IMPORT;
- this.wb = WorkbookFactory.create(is);
- List<T> list = new ArrayList<T>();
- // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
- Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
- if (sheet == null)
- {
- throw new IOException("文件sheet不存在");
- }
-
- // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1
- int rows = sheet.getLastRowNum();
- if (rows > 0)
- {
- // 定义一个map用于存放excel列的序号和field.
- Map<String, Integer> cellMap = new HashMap<String, Integer>();
- // 获取表头
- Row heard = sheet.getRow(titleNum);
- if (heard == null)
- {
- throw new UtilException("文件标题行为空,请检查Excel文件格式");
- }
- for (int i = 0; i < heard.getLastCellNum(); i++)
- {
- Cell cell = heard.getCell(i);
- if (StringUtils.isNotNull(cell))
- {
- String value = this.getCellValue(heard, i).toString();
- cellMap.put(value, i);
- }
- }
- // 有数据时才处理 得到类的所有field.
- List<Object[]> fields = this.getFields();
- Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
- for (Object[] objects : fields)
- {
- Excel attr = (Excel) objects[1];
- Integer column = cellMap.get(attr.name());
- if (column != null)
- {
- fieldsMap.put(column, objects);
- }
- }
- for (int i = titleNum + 1; i <= rows; i++)
- {
- // 从第2行开始取数据,默认第一行是表头.
- Row row = sheet.getRow(i);
- // 判断当前行是否是空行
- if (isRowEmpty(row))
- {
- continue;
- }
- T entity = null;
- for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
- {
- Object val = this.getCellValue(row, entry.getKey());
-
- // 如果不存在实例则新建.
- entity = (entity == null ? clazz.getDeclaredConstructor().newInstance() : entity);
- // 从map中得到对应列的field.
- Field field = (Field) entry.getValue()[0];
- Excel attr = (Excel) entry.getValue()[1];
- // 取得类型,并根据对象类型设置值.
- Class<?> fieldType = field.getType();
- if (String.class == fieldType)
- {
- String s = Convert.toStr(val);
- if (s.matches("^\\d+\\.0$"))
- {
- val = StringUtils.substringBefore(s, ".0");
- }
- else
- {
- String dateFormat = field.getAnnotation(Excel.class).dateFormat();
- if (StringUtils.isNotEmpty(dateFormat))
- {
- val = parseDateToStr(dateFormat, val);
- }
- else
- {
- val = Convert.toStr(val);
- }
- }
- }
- else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
- {
- val = Convert.toInt(val);
- }
- else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
- {
- val = Convert.toLong(val);
- }
- else if (Double.TYPE == fieldType || Double.class == fieldType)
- {
- val = Convert.toDouble(val);
- }
- else if (Float.TYPE == fieldType || Float.class == fieldType)
- {
- val = Convert.toFloat(val);
- }
- else if (BigDecimal.class == fieldType)
- {
- val = Convert.toBigDecimal(val);
- }
- else if (Date.class == fieldType)
- {
- if (val instanceof String)
- {
- val = DateUtils.parseDate(val);
- }
- else if (val instanceof Double)
- {
- val = DateUtil.getJavaDate((Double) val);
- }
- }
- else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
- {
- val = Convert.toBool(val, false);
- }
- if (StringUtils.isNotNull(fieldType))
- {
- String propertyName = field.getName();
- if (StringUtils.isNotEmpty(attr.targetAttr()))
- {
- propertyName = field.getName() + "." + attr.targetAttr();
- }
- if (StringUtils.isNotEmpty(attr.readConverterExp()))
- {
- val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
- }
- else if (!attr.handler().equals(ExcelHandlerAdapter.class))
- {
- val = dataFormatHandlerAdapter(val, attr, null);
- }
- ReflectUtils.invokeSetter(entity, propertyName, val);
- }
- }
- list.add(entity);
- }
- }
- return list;
- }
-
- /**
- * 对list数据源将其里面的数据导入到excel表单
- *
- * @param response 返回数据
- * @param list 导出数据集合
- * @param sheetName 工作表的名称
- * @return 结果
- */
- public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
- {
- exportExcel(response, list, sheetName, StringUtils.EMPTY);
- }
-
- /**
- * 对list数据源将其里面的数据导入到excel表单
- *
- * @param response 返回数据
- * @param list 导出数据集合
- * @param sheetName 工作表的名称
- * @param title 标题
- * @return 结果
- */
- public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
- {
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- response.setCharacterEncoding("utf-8");
- this.init(list, sheetName, title, Type.EXPORT);
- exportExcel(response);
- }
-
- /**
- * 多 Sheet 导出 —— 将多个不同类型的数据集合写入同一 Excel,直接输出到 HttpServletResponse
- *
- * @param response HTTP 响应
- * @param sheets Sheet 描述列表
- */
- public static void exportMultiSheet(HttpServletResponse response, List<ExcelSheet<?>> sheets)
- {
- if (sheets == null || sheets.isEmpty())
- {
- return;
- }
- SXSSFWorkbook wb = buildWorkbook(sheets);
- try
- {
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- response.setCharacterEncoding("utf-8");
- wb.write(response.getOutputStream());
- }
- catch (Exception e)
- {
- log.error("多Sheet导出Excel异常{}", e.getMessage());
- }
- finally
- {
- IOUtils.closeQuietly(wb);
- }
- }
-
- /**
- * 构建多 Sheet Workbook —— 创建 SXSSFWorkbook 并将所有 Sheet 数据写入
- *
- * @param sheets Sheet 描述列表
- * @return 已写入所有 Sheet 数据的 SXSSFWorkbook
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private static SXSSFWorkbook buildWorkbook(List<ExcelSheet<?>> sheets)
- {
- SXSSFWorkbook wb = new SXSSFWorkbook(500);
- for (ExcelSheet<?> excelSheet : sheets)
- {
- ExcelUtil util = new ExcelUtil(excelSheet.getClazz());
- util.initWithWorkbook(wb, excelSheet.getList(), excelSheet.getSheetName(), excelSheet.getTitle());
- util.writeSheet();
- }
- return wb;
- }
-
- /**
- * 使用外部传入的 Workbook 初始化(多 Sheet 导出专用)
- * 与 init() 的区别:不新建 Workbook,而是在已有 wb 上追加新 Sheet
- *
- * @param wb 已有工作簿
- * @param list 数据集合
- * @param sheetName Sheet 名称
- * @param title 大标题(可为空)
- */
- public void initWithWorkbook(SXSSFWorkbook wb, List<T> list, String sheetName, String title)
- {
- if (list == null)
- {
- list = new ArrayList<T>();
- }
- this.list = list;
- this.sheetName = sheetName;
- this.title = title != null ? title : "";
- this.type = Type.EXPORT;
- this.rownum = 0;
- this.wb = wb;
- this.sheet = wb.createSheet(sheetName);
- createExcelField();
- this.styles = createStyles(wb);
- createTitle();
- createSubHead();
- }
-
- /**
- * 对list数据源将其里面的数据导入到excel表单
- *
- * @param sheetName 工作表的名称
- * @return 结果
- */
- public void importTemplateExcel(HttpServletResponse response, String sheetName)
- {
- importTemplateExcel(response, sheetName, StringUtils.EMPTY);
- }
-
- /**
- * 对list数据源将其里面的数据导入到excel表单
- *
- * @param sheetName 工作表的名称
- * @param title 标题
- * @return 结果
- */
- public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)
- {
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- response.setCharacterEncoding("utf-8");
- this.init(null, sheetName, title, Type.IMPORT);
- exportExcel(response);
- }
-
- /**
- * 对list数据源将其里面的数据导入到excel表单
- *
- * @return 结果
- */
- public void exportExcel(HttpServletResponse response)
- {
- try
- {
- writeSheet();
- wb.write(response.getOutputStream());
- }
- catch (Exception e)
- {
- log.error("导出Excel异常{}", e.getMessage());
- }
- finally
- {
- IOUtils.closeQuietly(wb);
- }
- }
-
- /**
- * 创建写入数据到Sheet
- */
- public void writeSheet()
- {
- // 取出一共有多少个sheet.
- int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
- for (int index = 0; index < sheetNo; index++)
- {
- createSheet(sheetNo, index);
-
- // 产生一行
- Row row = sheet.createRow(rownum);
- int column = 0;
- // 写入各个字段的列头名称
- for (Object[] os : fields)
- {
- Field field = (Field) os[0];
- Excel excel = (Excel) os[1];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- List<Field> currentSubFields = subFieldsMap.get(field.getName());
- for (Field subField : currentSubFields)
- {
- Excel subExcel = subField.getAnnotation(Excel.class);
- this.createHeadCell(subExcel, row, column++);
- }
- }
- else
- {
- this.createHeadCell(excel, row, column++);
- }
- }
- if (Type.EXPORT.equals(type))
- {
- fillExcelData(index);
- addStatisticsRow();
- }
- }
- }
-
- /**
- * 填充excel数据
- *
- * @param index 序号
- */
- @SuppressWarnings("unchecked")
- public void fillExcelData(int index)
- {
- int startNo = index * sheetSize;
- int endNo = Math.min(startNo + sheetSize, list.size());
- int currentRowNum = rownum + 1; // 从标题行后开始
-
- for (int i = startNo; i < endNo; i++)
- {
- Row row = sheet.createRow(currentRowNum);
- T vo = (T) list.get(i);
- int column = 0;
- int maxSubListSize = getCurrentMaxSubListSize(vo);
- for (Object[] os : fields)
- {
- Field field = (Field) os[0];
- Excel excel = (Excel) os[1];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- try
- {
- Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
- List<Field> currentSubFields = subFieldsMap.get(field.getName());
- if (subList != null && !subList.isEmpty())
- {
- int subIndex = 0;
- for (Object subVo : subList)
- {
- Row subRow = sheet.getRow(currentRowNum + subIndex);
- if (subRow == null)
- {
- subRow = sheet.createRow(currentRowNum + subIndex);
- }
-
- int subColumn = column;
- for (Field subField : currentSubFields)
- {
- Excel subExcel = subField.getAnnotation(Excel.class);
- addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
- }
- subIndex++;
- }
- }
- column += currentSubFields.size();
- }
- catch (Exception e)
- {
- log.error("填充集合数据失败", e);
- }
- }
- else
- {
- // 创建单元格并设置值
- addCell(excel, row, vo, field, column);
- if (maxSubListSize > 1 && excel.needMerge())
- {
- sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
- }
- column++;
- }
- }
- currentRowNum += maxSubListSize;
- }
- }
-
- /**
- * 获取子列表最大数
- */
- private int getCurrentMaxSubListSize(T vo)
- {
- int maxSubListSize = 1;
- for (Object[] os : fields)
- {
- Field field = (Field) os[0];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- try
- {
- Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
- if (subList != null && !subList.isEmpty())
- {
- maxSubListSize = Math.max(maxSubListSize, subList.size());
- }
- }
- catch (Exception e)
- {
- log.error("获取集合大小失败", e);
- }
- }
- }
- return maxSubListSize;
- }
-
- /**
- * 创建表格样式
- *
- * @param wb 工作薄对象
- * @return 样式列表
- */
- private Map<String, CellStyle> createStyles(Workbook wb)
- {
- // 写入各条记录,每条记录对应excel表中的一行
- Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
- CellStyle style = wb.createCellStyle();
- style.setAlignment(HorizontalAlignment.CENTER);
- style.setVerticalAlignment(VerticalAlignment.CENTER);
- Font titleFont = wb.createFont();
- titleFont.setFontName("Arial");
- titleFont.setFontHeightInPoints((short) 16);
- titleFont.setBold(true);
- style.setFont(titleFont);
- DataFormat dataFormat = wb.createDataFormat();
- style.setDataFormat(dataFormat.getFormat("@"));
- styles.put("title", style);
-
- style = wb.createCellStyle();
- style.setAlignment(HorizontalAlignment.CENTER);
- style.setVerticalAlignment(VerticalAlignment.CENTER);
- style.setBorderRight(BorderStyle.THIN);
- style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderLeft(BorderStyle.THIN);
- style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderTop(BorderStyle.THIN);
- style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderBottom(BorderStyle.THIN);
- style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- Font dataFont = wb.createFont();
- dataFont.setFontName("Arial");
- dataFont.setFontHeightInPoints((short) 10);
- style.setFont(dataFont);
- styles.put("data", style);
-
- style = wb.createCellStyle();
- style.setAlignment(HorizontalAlignment.CENTER);
- style.setVerticalAlignment(VerticalAlignment.CENTER);
- style.setDataFormat(dataFormat.getFormat("######0.00"));
- Font totalFont = wb.createFont();
- totalFont.setFontName("Arial");
- totalFont.setFontHeightInPoints((short) 10);
- style.setFont(totalFont);
- styles.put("total", style);
-
- styles.putAll(annotationHeaderStyles(wb, styles));
-
- styles.putAll(annotationDataStyles(wb));
-
- return styles;
- }
-
- /**
- * 根据Excel注解创建表格头样式
- *
- * @param wb 工作薄对象
- * @return 自定义样式列表
- */
- private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles)
- {
- Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>();
- for (Object[] os : fields)
- {
- Excel excel = (Excel) os[1];
- String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor());
- if (!headerStyles.containsKey(key))
- {
- CellStyle style = wb.createCellStyle();
- style.cloneStyleFrom(styles.get("data"));
- style.setAlignment(HorizontalAlignment.CENTER);
- style.setVerticalAlignment(VerticalAlignment.CENTER);
- style.setFillForegroundColor(excel.headerBackgroundColor().index);
- style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
- Font headerFont = wb.createFont();
- headerFont.setFontName("Arial");
- headerFont.setFontHeightInPoints((short) 10);
- headerFont.setBold(true);
- headerFont.setColor(excel.headerColor().index);
- style.setFont(headerFont);
- // 设置表格头单元格文本形式
- DataFormat dataFormat = wb.createDataFormat();
- style.setDataFormat(dataFormat.getFormat("@"));
- headerStyles.put(key, style);
- }
- }
- return headerStyles;
- }
-
- /**
- * 根据Excel注解创建表格列样式
- *
- * @param wb 工作薄对象
- * @return 自定义样式列表
- */
- private Map<String, CellStyle> annotationDataStyles(Workbook wb)
- {
- Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
- for (Object[] os : fields)
- {
- Field field = (Field) os[0];
- Excel excel = (Excel) os[1];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- ParameterizedType pt = (ParameterizedType) field.getGenericType();
- Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
- List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
- for (Field subField : subFields)
- {
- Excel subExcel = subField.getAnnotation(Excel.class);
- annotationDataStyles(styles, subField, subExcel);
- }
- }
- else
- {
- annotationDataStyles(styles, field, excel);
- }
- }
- return styles;
- }
-
- /**
- * 根据Excel注解创建表格列样式
- *
- * @param styles 自定义样式列表
- * @param field 属性列信息
- * @param excel 注解信息
- */
- public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
- {
- String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
- if (!styles.containsKey(key))
- {
- CellStyle style = wb.createCellStyle();
- style.setAlignment(excel.align());
- style.setVerticalAlignment(VerticalAlignment.CENTER);
- style.setBorderRight(BorderStyle.THIN);
- style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderLeft(BorderStyle.THIN);
- style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderTop(BorderStyle.THIN);
- style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setBorderBottom(BorderStyle.THIN);
- style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
- style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
- style.setFillForegroundColor(excel.backgroundColor().getIndex());
- style.setWrapText(excel.wrapText());
- Font dataFont = wb.createFont();
- dataFont.setFontName("Arial");
- dataFont.setFontHeightInPoints((short) 10);
- dataFont.setColor(excel.color().index);
- style.setFont(dataFont);
- if (ColumnType.TEXT == excel.cellType())
- {
- DataFormat dataFormat = wb.createDataFormat();
- style.setDataFormat(dataFormat.getFormat("@"));
- }
- styles.put(key, style);
- }
- }
-
- /**
- * 创建单元格
- */
- public Cell createHeadCell(Excel attr, Row row, int column)
- {
- // 创建列
- Cell cell = row.createCell(column);
- // 写入列信息
- cell.setCellValue(attr.name());
- setDataValidation(attr, row, column);
- cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
- if (isSubList())
- {
- // 填充默认样式,防止合并单元格样式失效
- sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
- if (attr.needMerge())
- {
- sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
- }
- }
- return cell;
- }
-
- /**
- * 设置单元格信息
- *
- * @param value 单元格值
- * @param attr 注解相关
- * @param cell 单元格信息
- */
- public void setCellVo(Object value, Excel attr, Cell cell)
- {
- if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())
- {
- String cellValue = Convert.toStr(value);
- // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。
- if (StringUtils.startsWithAny(cellValue, FORMULA_STR))
- {
- cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
- }
- if (value instanceof Collection && StringUtils.equals("[]", cellValue))
- {
- cellValue = StringUtils.EMPTY;
- }
- cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
- }
- else if (ColumnType.NUMERIC == attr.cellType())
- {
- if (StringUtils.isNotNull(value))
- {
- cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
- }
- }
- else if (ColumnType.IMAGE == attr.cellType())
- {
- ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
- String imagePath = Convert.toStr(value);
- if (StringUtils.isNotEmpty(imagePath))
- {
- byte[] data = ImageUtils.getImage(imagePath);
- getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
- cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
- }
- }
- }
-
- /**
- * 获取画布
- */
- public static Drawing<?> getDrawingPatriarch(Sheet sheet)
- {
- if (sheet.getDrawingPatriarch() == null)
- {
- sheet.createDrawingPatriarch();
- }
- return sheet.getDrawingPatriarch();
- }
-
- /**
- * 获取图片类型,设置图片插入类型
- */
- public int getImageType(byte[] value)
- {
- String type = FileTypeUtils.getFileExtendName(value);
- if ("JPG".equalsIgnoreCase(type))
- {
- return Workbook.PICTURE_TYPE_JPEG;
- }
- else if ("PNG".equalsIgnoreCase(type))
- {
- return Workbook.PICTURE_TYPE_PNG;
- }
- return Workbook.PICTURE_TYPE_JPEG;
- }
-
- /**
- * 创建表格样式
- */
- public void setDataValidation(Excel attr, Row row, int column)
- {
- if (attr.name().indexOf("注:") >= 0)
- {
- sheet.setColumnWidth(column, 6000);
- }
- else
- {
- // 设置列宽
- sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
- }
- if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0)
- {
- if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255)
- {
- // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到
- setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
- }
- else
- {
- // 提示信息或只能选择不能输入的列内容.
- setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
- }
- }
- }
-
- /**
- * 添加单元格
- */
- @SuppressWarnings("deprecation")
- public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
- {
- Cell cell = null;
- try
- {
- // 设置行高
- row.setHeight(maxHeight);
- // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
- if (attr.isExport())
- {
- // 创建cell
- cell = row.createCell(column);
- if (isSubListValue(vo) && getListCellValue(vo) > 1 && attr.needMerge())
- {
- if (subMergedLastRowNum >= subMergedFirstRowNum)
- {
- sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
- }
- }
- cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
-
- // 用于读取对象中的属性
- Object value = getTargetValue(vo, field, attr);
- String dateFormat = attr.dateFormat();
- String readConverterExp = attr.readConverterExp();
- String separator = attr.separator();
- if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
- {
- cell.setCellStyle(createCellStyle(cell.getCellStyle(), dateFormat));
- cell.setCellValue(parseDateToStr(dateFormat, value));
- }
- else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
- {
- cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
- }
- else if (value instanceof BigDecimal && -1 != attr.scale())
- {
- cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
- }
- else if (!attr.handler().equals(ExcelHandlerAdapter.class))
- {
- cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
- }
- else
- {
- // 设置列类型
- setCellVo(value, attr, cell);
- }
- addStatisticsData(column, Convert.toStr(value), attr);
- }
- }
- catch (Exception e)
- {
- log.error("导出Excel失败{}", e);
- }
- return cell;
- }
-
- /**
- * 使用自定义格式,同时避免样式污染
- *
- * @param cellStyle 从此样式复制
- * @param format 格式匹配的字符串
- * @return 格式化后CellStyle对象
- */
- private CellStyle createCellStyle(CellStyle cellStyle, String format)
- {
- String key = cellStyle.getIndex() + "|" + format;
- CellStyle cached = cellStyleCache.get(key);
- if (cached != null)
- {
- return cached;
- }
- CellStyle style = wb.createCellStyle();
- style.cloneStyleFrom(cellStyle);
- style.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat(format));
- cellStyleCache.put(key, style);
- return style;
- }
-
- /**
- * 设置 POI XSSFSheet 单元格提示或选择框
- *
- * @param sheet 表单
- * @param textlist 下拉框显示的内容
- * @param promptContent 提示内容
- * @param firstRow 开始行
- * @param endRow 结束行
- * @param firstCol 开始列
- * @param endCol 结束列
- */
- public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,
- int firstCol, int endCol)
- {
- DataValidationHelper helper = sheet.getDataValidationHelper();
- DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1");
- CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
- DataValidation dataValidation = helper.createValidation(constraint, regions);
- if (StringUtils.isNotEmpty(promptContent))
- {
- // 如果设置了提示信息则鼠标放上去提示
- dataValidation.createPromptBox("", promptContent);
- dataValidation.setShowPromptBox(true);
- }
- // 处理Excel兼容性问题
- if (dataValidation instanceof XSSFDataValidation)
- {
- dataValidation.setSuppressDropDownArrow(true);
- dataValidation.setShowErrorBox(true);
- }
- else
- {
- dataValidation.setSuppressDropDownArrow(false);
- }
- sheet.addValidationData(dataValidation);
- }
-
- /**
- * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框).
- *
- * @param sheet 要设置的sheet.
- * @param textlist 下拉框显示的内容
- * @param promptContent 提示内容
- * @param firstRow 开始行
- * @param endRow 结束行
- * @param firstCol 开始列
- * @param endCol 结束列
- */
- public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)
- {
- String hideSheetName = "combo_" + firstCol + "_" + endCol;
- Sheet hideSheet = null;
- String hideSheetDataName = hideSheetName + "_data";
- Name name = wb.getName(hideSheetDataName);
- if (name != null)
- {
- // 名称已存在,尝试从名称的引用中找到sheet名称
- String refersToFormula = name.getRefersToFormula();
- if (StringUtils.isNotEmpty(refersToFormula) && refersToFormula.contains("!"))
- {
- String sheetNameFromFormula = refersToFormula.substring(0, refersToFormula.indexOf("!"));
- hideSheet = wb.getSheet(sheetNameFromFormula);
- }
- }
-
- if (hideSheet == null)
- {
- hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
- for (int i = 0; i < textlist.length; i++)
- {
- hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
- }
- // 创建名称,可被其他单元格引用
- name = wb.createName();
- name.setNameName(hideSheetDataName);
- name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
- }
-
- DataValidationHelper helper = sheet.getDataValidationHelper();
- // 加载下拉列表内容
- DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetDataName);
- // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
- CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
- // 数据有效性对象
- DataValidation dataValidation = helper.createValidation(constraint, regions);
- if (StringUtils.isNotEmpty(promptContent))
- {
- // 如果设置了提示信息则鼠标放上去提示
- dataValidation.createPromptBox("", promptContent);
- dataValidation.setShowPromptBox(true);
- }
- // 处理Excel兼容性问题
- if (dataValidation instanceof XSSFDataValidation)
- {
- dataValidation.setSuppressDropDownArrow(true);
- dataValidation.setShowErrorBox(true);
- }
- else
- {
- dataValidation.setSuppressDropDownArrow(false);
- }
-
- sheet.addValidationData(dataValidation);
- // 设置hiddenSheet隐藏
- wb.setSheetHidden(wb.getSheetIndex(hideSheet), true);
- }
-
- /**
- * 解析导出值 0=男,1=女,2=未知
- *
- * @param propertyValue 参数值
- * @param converterExp 翻译注解
- * @param separator 分隔符
- * @return 解析后值
- */
- public static String convertByExp(String propertyValue, String converterExp, String separator)
- {
- StringBuilder propertyString = new StringBuilder();
- String[] convertSource = converterExp.split(SEPARATOR);
- for (String item : convertSource)
- {
- String[] itemArray = item.split("=");
- if (StringUtils.containsAny(propertyValue, separator))
- {
- for (String value : propertyValue.split(separator))
- {
- if (itemArray[0].equals(value))
- {
- propertyString.append(itemArray[1] + separator);
- break;
- }
- }
- }
- else
- {
- if (itemArray[0].equals(propertyValue))
- {
- return itemArray[1];
- }
- }
- }
- return StringUtils.stripEnd(propertyString.toString(), separator);
- }
-
- /**
- * 反向解析值 男=0,女=1,未知=2
- *
- * @param propertyValue 参数值
- * @param converterExp 翻译注解
- * @param separator 分隔符
- * @return 解析后值
- */
- public static String reverseByExp(String propertyValue, String converterExp, String separator)
- {
- StringBuilder propertyString = new StringBuilder();
- String[] convertSource = converterExp.split(SEPARATOR);
- for (String item : convertSource)
- {
- String[] itemArray = item.split("=");
- if (StringUtils.containsAny(propertyValue, separator))
- {
- for (String value : propertyValue.split(separator))
- {
- if (itemArray[1].equals(value))
- {
- propertyString.append(itemArray[0] + separator);
- break;
- }
- }
- }
- else
- {
- if (itemArray[1].equals(propertyValue))
- {
- return itemArray[0];
- }
- }
- }
- return StringUtils.stripEnd(propertyString.toString(), separator);
- }
-
- /**
- * 数据处理器
- *
- * @param value 数据值
- * @param excel 数据注解
- * @return
- */
- public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
- {
- try
- {
- Object instance = excel.handler().getDeclaredConstructor().newInstance();
- Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
- value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
- }
- catch (Exception e)
- {
- log.error("不能格式化数据 " + excel.handler(), e.getMessage());
- }
- return Convert.toStr(value);
- }
-
- /**
- * 合计统计信息
- */
- private void addStatisticsData(Integer index, String text, Excel entity)
- {
- if (entity != null && entity.isStatistics())
- {
- Double temp = 0D;
- if (!statistics.containsKey(index))
- {
- statistics.put(index, temp);
- }
- try
- {
- temp = Double.valueOf(text);
- }
- catch (NumberFormatException e)
- {
- }
- statistics.put(index, statistics.get(index) + temp);
- }
- }
-
- /**
- * 创建统计行
- */
- public void addStatisticsRow()
- {
- if (statistics.size() > 0)
- {
- Row row = sheet.createRow(sheet.getLastRowNum() + 1);
- Set<Integer> keys = statistics.keySet();
- Cell cell = row.createCell(0);
- cell.setCellStyle(styles.get("total"));
- cell.setCellValue("合计");
-
- for (Integer key : keys)
- {
- cell = row.createCell(key);
- cell.setCellStyle(styles.get("total"));
- cell.setCellValue(statistics.get(key));
- }
- statistics.clear();
- }
- }
-
- /**
- * 获取bean中的属性值
- *
- * @param vo 实体对象
- * @param field 字段
- * @param excel 注解
- * @return 最终的属性值
- * @throws Exception
- */
- private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
- {
- field.setAccessible(true);
- Object o = field.get(vo);
- if (StringUtils.isNotEmpty(excel.targetAttr()))
- {
- String target = excel.targetAttr();
- if (target.contains("."))
- {
- String[] targets = target.split("[.]");
- for (String name : targets)
- {
- o = getValue(o, name);
- }
- }
- else
- {
- o = getValue(o, target);
- }
- }
- return o;
- }
-
- /**
- * 以类的属性的get方法方法形式获取值
- *
- * @param o
- * @param name
- * @return value
- * @throws Exception
- */
- private Object getValue(Object o, String name) throws Exception
- {
- if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
- {
- Class<?> clazz = o.getClass();
- Field field = clazz.getDeclaredField(name);
- field.setAccessible(true);
- o = field.get(o);
- }
- return o;
- }
-
- /**
- * 得到所有定义字段
- */
- private void createExcelField()
- {
- this.fields = getFields();
- this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
- this.maxHeight = getRowHeight();
- }
-
- /**
- * 获取字段注解信息
- */
- public List<Object[]> getFields()
- {
- List<Object[]> fields = new ArrayList<Object[]>();
- List<Field> tempFields = new ArrayList<>();
- subFieldsMap = new HashMap<>();
- subMethods = new HashMap<>();
- tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
- tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
- if (StringUtils.isNotEmpty(includeFields))
- {
- for (Field field : tempFields)
- {
- if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
- {
- addField(fields, field);
- }
- }
- }
- else if (StringUtils.isNotEmpty(excludeFields))
- {
- for (Field field : tempFields)
- {
- if (!ArrayUtils.contains(this.excludeFields, field.getName()))
- {
- addField(fields, field);
- }
- }
- }
- else
- {
- for (Field field : tempFields)
- {
- addField(fields, field);
- }
- }
- return fields;
- }
-
- /**
- * 添加字段信息
- */
- public void addField(List<Object[]> fields, Field field)
- {
- // 单注解
- if (field.isAnnotationPresent(Excel.class))
- {
- Excel attr = field.getAnnotation(Excel.class);
- if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
- {
- fields.add(new Object[] { field, attr });
- }
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- String fieldName = field.getName();
- subMethods.put(fieldName, getSubMethod(fieldName, clazz));
- ParameterizedType pt = (ParameterizedType) field.getGenericType();
- Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
- subFieldsMap.put(fieldName, FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class));
- }
- }
-
- // 多注解
- if (field.isAnnotationPresent(Excels.class))
- {
- Excels attrs = field.getAnnotation(Excels.class);
- Excel[] excels = attrs.value();
- for (Excel attr : excels)
- {
- if (StringUtils.isNotEmpty(includeFields))
- {
- if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
- && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
- {
- fields.add(new Object[] { field, attr });
- }
- }
- else
- {
- if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
- && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
- {
- fields.add(new Object[] { field, attr });
- }
- }
- }
- }
- }
-
- /**
- * 根据注解获取最大行高
- */
- public short getRowHeight()
- {
- double maxHeight = 0;
- for (Object[] os : this.fields)
- {
- Excel excel = (Excel) os[1];
- maxHeight = Math.max(maxHeight, excel.height());
- }
- return (short) (maxHeight * 20);
- }
-
- /**
- * 创建一个工作簿
- */
- public void createWorkbook()
- {
- this.wb = new SXSSFWorkbook(500);
- this.sheet = wb.createSheet();
- wb.setSheetName(0, sheetName);
- this.styles = createStyles(wb);
- }
-
- /**
- * 创建工作表
- *
- * @param sheetNo sheet数量
- * @param index 序号
- */
- public void createSheet(int sheetNo, int index)
- {
- // 设置工作表的名称.
- if (sheetNo > 1 && index > 0)
- {
- this.sheet = wb.createSheet();
- this.createTitle();
- int actualIndex = wb.getSheetIndex(this.sheet);
- wb.setSheetName(actualIndex, sheetName + index);
- }
- }
-
- /**
- * 获取单元格值
- *
- * @param row 获取的行
- * @param column 获取单元格列号
- * @return 单元格值
- */
- public Object getCellValue(Row row, int column)
- {
- if (row == null)
- {
- return row;
- }
- Object val = "";
- try
- {
- Cell cell = row.getCell(column);
- if (StringUtils.isNotNull(cell))
- {
- if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
- {
- val = cell.getNumericCellValue();
- if (DateUtil.isCellDateFormatted(cell))
- {
- val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
- }
- else
- {
- if ((Double) val % 1 != 0)
- {
- val = new BigDecimal(val.toString());
- }
- else
- {
- val = new DecimalFormat("0").format(val);
- }
- }
- }
- else if (cell.getCellType() == CellType.STRING)
- {
- val = cell.getStringCellValue();
- }
- else if (cell.getCellType() == CellType.BOOLEAN)
- {
- val = cell.getBooleanCellValue();
- }
- else if (cell.getCellType() == CellType.ERROR)
- {
- val = cell.getErrorCellValue();
- }
-
- }
- }
- catch (Exception e)
- {
- return val;
- }
- return val;
- }
-
- /**
- * 判断是否是空行
- *
- * @param row 判断的行
- * @return
- */
- private boolean isRowEmpty(Row row)
- {
- if (row == null)
- {
- return true;
- }
- for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++)
- {
- Cell cell = row.getCell(i);
- if (cell != null && cell.getCellType() != CellType.BLANK)
- {
- return false;
- }
- }
- return true;
- }
-
- /**
- * 格式化不同类型的日期对象
- *
- * @param dateFormat 日期格式
- * @param val 被格式化的日期对象
- * @return 格式化后的日期字符
- */
- public String parseDateToStr(String dateFormat, Object val)
- {
- if (val == null)
- {
- return "";
- }
- String str;
- if (val instanceof Date)
- {
- str = DateUtils.parseDateToStr(dateFormat, (Date) val);
- }
- else if (val instanceof LocalDateTime)
- {
- str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));
- }
- else if (val instanceof LocalDate)
- {
- str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));
- }
- else
- {
- str = val.toString();
- }
- return str;
- }
-
- /**
- * 是否有对象的子列表
- */
- public boolean isSubList()
- {
- return !StringUtils.isEmpty(subFieldsMap);
- }
-
- /**
- * 是否有对象的子列表,集合不为空
- */
- public boolean isSubListValue(T vo)
- {
- return !StringUtils.isEmpty(subFieldsMap) && getListCellValue(vo) > 0;
- }
-
- /**
- * 获取集合的值
- */
- public int getListCellValue(Object obj)
- {
- Collection<?> value;
- int max = 0;
- try
- {
- for (String s : subMethods.keySet())
- {
- value = (Collection<?>) subMethods.get(s).invoke(obj);
- if (value.size() > max)
- {
- max = value.size();
- }
- }
- }
- catch (Exception e)
- {
- return 0;
- }
- return max;
- }
-
- /**
- * 获取对象的子列表方法
- *
- * @param name 名称
- * @param pojoClass 类对象
- * @return 子列表方法
- */
- public Method getSubMethod(String name, Class<?> pojoClass)
- {
- StringBuffer getMethodName = new StringBuffer("get");
- getMethodName.append(name.substring(0, 1).toUpperCase());
- getMethodName.append(name.substring(1));
- Method method = null;
- try
- {
- method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});
- }
- catch (Exception e)
- {
- log.error("获取对象异常{}", e.getMessage());
- }
- return method;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java
deleted file mode 100644
index 82e25e9..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java
+++ /dev/null
@@ -1,412 +0,0 @@
-package com.ruoyi.common.core.utils.reflect;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Date;
-import org.apache.commons.lang3.Validate;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
- *
- * @author ruoyi
- */
-@SuppressWarnings("rawtypes")
-public class ReflectUtils
-{
- private static final String SETTER_PREFIX = "set";
-
- private static final String GETTER_PREFIX = "get";
-
- private static final String CGLIB_CLASS_SEPARATOR = "$$";
-
- private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
-
- /**
- * 调用Getter方法.
- * 支持多级,如:对象名.对象名.方法
- */
- @SuppressWarnings("unchecked")
- public static <E> E invokeGetter(Object obj, String propertyName)
- {
- Object object = obj;
- for (String name : StringUtils.split(propertyName, "."))
- {
- String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
- object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
- }
- return (E) object;
- }
-
- /**
- * 调用Setter方法, 仅匹配方法名。
- * 支持多级,如:对象名.对象名.方法
- */
- public static <E> void invokeSetter(Object obj, String propertyName, E value)
- {
- Object object = obj;
- String[] names = StringUtils.split(propertyName, ".");
- for (int i = 0; i < names.length; i++)
- {
- if (i < names.length - 1)
- {
- String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
- object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
- }
- else
- {
- String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
- invokeMethodByName(object, setterMethodName, new Object[] { value });
- }
- }
- }
-
- /**
- * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
- */
- @SuppressWarnings("unchecked")
- public static <E> E getFieldValue(final Object obj, final String fieldName)
- {
- Field field = getAccessibleField(obj, fieldName);
- if (field == null)
- {
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- return null;
- }
- E result = null;
- try
- {
- result = (E) field.get(obj);
- }
- catch (IllegalAccessException e)
- {
- logger.error("不可能抛出的异常{}", e.getMessage());
- }
- return result;
- }
-
- /**
- * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
- */
- public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
- {
- Field field = getAccessibleField(obj, fieldName);
- if (field == null)
- {
- // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- return;
- }
- try
- {
- field.set(obj, value);
- }
- catch (IllegalAccessException e)
- {
- logger.error("不可能抛出的异常: {}", e.getMessage());
- }
- }
-
- /**
- * 直接调用对象方法, 无视private/protected修饰符.
- * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
- * 同时匹配方法名+参数类型,
- */
- @SuppressWarnings("unchecked")
- public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
- final Object[] args)
- {
- if (obj == null || methodName == null)
- {
- return null;
- }
- Method method = getAccessibleMethod(obj, methodName, parameterTypes);
- if (method == null)
- {
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
- return null;
- }
- try
- {
- return (E) method.invoke(obj, args);
- }
- catch (Exception e)
- {
- String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
- throw convertReflectionExceptionToUnchecked(msg, e);
- }
- }
-
- /**
- * 直接调用对象方法, 无视private/protected修饰符,
- * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
- * 只匹配函数名,如果有多个同名函数调用第一个。
- */
- @SuppressWarnings("unchecked")
- public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
- {
- Method method = getAccessibleMethodByName(obj, methodName, args.length);
- if (method == null)
- {
- // 如果为空不报错,直接返回空。
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
- return null;
- }
- try
- {
- // 类型转换(将参数数据类型转换为目标方法参数类型)
- Class<?>[] cs = method.getParameterTypes();
- for (int i = 0; i < cs.length; i++)
- {
- if (args[i] != null && !args[i].getClass().equals(cs[i]))
- {
- if (cs[i] == String.class)
- {
- args[i] = Convert.toStr(args[i]);
- if (StringUtils.endsWith((String) args[i], ".0"))
- {
- args[i] = StringUtils.substringBefore((String) args[i], ".0");
- }
- }
- else if (cs[i] == Integer.class)
- {
- args[i] = Convert.toInt(args[i]);
- }
- else if (cs[i] == Long.class)
- {
- args[i] = Convert.toLong(args[i]);
- }
- else if (cs[i] == Double.class)
- {
- args[i] = Convert.toDouble(args[i]);
- }
- else if (cs[i] == Float.class)
- {
- args[i] = Convert.toFloat(args[i]);
- }
- else if (cs[i] == Date.class)
- {
- if (args[i] instanceof String)
- {
- args[i] = DateUtils.parseDate(args[i]);
- }
- else
- {
- args[i] = DateUtil.getJavaDate((Double) args[i]);
- }
- }
- else if (cs[i] == boolean.class || cs[i] == Boolean.class)
- {
- args[i] = Convert.toBool(args[i]);
- }
- }
- }
- return (E) method.invoke(obj, args);
- }
- catch (Exception e)
- {
- String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
- throw convertReflectionExceptionToUnchecked(msg, e);
- }
- }
-
- /**
- * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
- * 如向上转型到Object仍无法找到, 返回null.
- */
- public static Field getAccessibleField(final Object obj, final String fieldName)
- {
- // 为空不报错。直接返回 null
- if (obj == null)
- {
- return null;
- }
- Validate.notBlank(fieldName, "fieldName can't be blank");
- for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
- {
- try
- {
- Field field = superClass.getDeclaredField(fieldName);
- makeAccessible(field);
- return field;
- }
- catch (NoSuchFieldException e)
- {
- continue;
- }
- }
- return null;
- }
-
- /**
- * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
- * 如向上转型到Object仍无法找到, 返回null.
- * 匹配函数名+参数类型。
- * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
- */
- public static Method getAccessibleMethod(final Object obj, final String methodName,
- final Class<?>... parameterTypes)
- {
- // 为空不报错。直接返回 null
- if (obj == null)
- {
- return null;
- }
- Validate.notBlank(methodName, "methodName can't be blank");
- for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
- {
- try
- {
- Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
- makeAccessible(method);
- return method;
- }
- catch (NoSuchMethodException e)
- {
- continue;
- }
- }
- return null;
- }
-
- /**
- * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
- * 如向上转型到Object仍无法找到, 返回null.
- * 只匹配函数名。
- * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
- */
- public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
- {
- // 为空不报错。直接返回 null
- if (obj == null)
- {
- return null;
- }
- Validate.notBlank(methodName, "methodName can't be blank");
- for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
- {
- Method[] methods = searchType.getDeclaredMethods();
- for (Method method : methods)
- {
- if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
- {
- makeAccessible(method);
- return method;
- }
- }
- }
- return null;
- }
-
- /**
- * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
- */
- @SuppressWarnings("deprecation")
- public static void makeAccessible(Method method)
- {
- if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
- && !method.isAccessible())
- {
- method.setAccessible(true);
- }
- }
-
- /**
- * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
- */
- @SuppressWarnings("deprecation")
- public static void makeAccessible(Field field)
- {
- if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
- || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
- {
- field.setAccessible(true);
- }
- }
-
- /**
- * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
- * 如无法找到, 返回Object.class.
- */
- @SuppressWarnings("unchecked")
- public static <T> Class<T> getClassGenricType(final Class clazz)
- {
- return getClassGenricType(clazz, 0);
- }
-
- /**
- * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
- * 如无法找到, 返回Object.class.
- */
- public static Class getClassGenricType(final Class clazz, final int index)
- {
- Type genType = clazz.getGenericSuperclass();
-
- if (!(genType instanceof ParameterizedType))
- {
- logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
- return Object.class;
- }
-
- Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
-
- if (index >= params.length || index < 0)
- {
- logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
- + params.length);
- return Object.class;
- }
- if (!(params[index] instanceof Class))
- {
- logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
- return Object.class;
- }
-
- return (Class) params[index];
- }
-
- public static Class<?> getUserClass(Object instance)
- {
- if (instance == null)
- {
- throw new RuntimeException("Instance must not be null");
- }
- Class clazz = instance.getClass();
- if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
- {
- Class<?> superClass = clazz.getSuperclass();
- if (superClass != null && !Object.class.equals(superClass))
- {
- return superClass;
- }
- }
- return clazz;
-
- }
-
- /**
- * 将反射时的checked exception转换为unchecked exception.
- */
- public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
- {
- if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
- || e instanceof NoSuchMethodException)
- {
- return new IllegalArgumentException(msg, e);
- }
- else if (e instanceof InvocationTargetException)
- {
- return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
- }
- return new RuntimeException(msg, e);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sign/Base64.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sign/Base64.java
deleted file mode 100644
index 6f6e8d3..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sign/Base64.java
+++ /dev/null
@@ -1,291 +0,0 @@
-package com.ruoyi.common.core.utils.sign;
-
-/**
- * Base64工具类
- *
- * @author ruoyi
- */
-public final class Base64
-{
- static private final int BASELENGTH = 128;
- static private final int LOOKUPLENGTH = 64;
- static private final int TWENTYFOURBITGROUP = 24;
- static private final int EIGHTBIT = 8;
- static private final int SIXTEENBIT = 16;
- static private final int FOURBYTE = 4;
- static private final int SIGN = -128;
- static private final char PAD = '=';
- static final private byte[] base64Alphabet = new byte[BASELENGTH];
- static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
-
- static
- {
- for (int i = 0; i < BASELENGTH; ++i)
- {
- base64Alphabet[i] = -1;
- }
- for (int i = 'Z'; i >= 'A'; i--)
- {
- base64Alphabet[i] = (byte) (i - 'A');
- }
- for (int i = 'z'; i >= 'a'; i--)
- {
- base64Alphabet[i] = (byte) (i - 'a' + 26);
- }
-
- for (int i = '9'; i >= '0'; i--)
- {
- base64Alphabet[i] = (byte) (i - '0' + 52);
- }
-
- base64Alphabet['+'] = 62;
- base64Alphabet['/'] = 63;
-
- for (int i = 0; i <= 25; i++)
- {
- lookUpBase64Alphabet[i] = (char) ('A' + i);
- }
-
- for (int i = 26, j = 0; i <= 51; i++, j++)
- {
- lookUpBase64Alphabet[i] = (char) ('a' + j);
- }
-
- for (int i = 52, j = 0; i <= 61; i++, j++)
- {
- lookUpBase64Alphabet[i] = (char) ('0' + j);
- }
- lookUpBase64Alphabet[62] = (char) '+';
- lookUpBase64Alphabet[63] = (char) '/';
- }
-
- private static boolean isWhiteSpace(char octect)
- {
- return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
- }
-
- private static boolean isPad(char octect)
- {
- return (octect == PAD);
- }
-
- private static boolean isData(char octect)
- {
- return (octect < BASELENGTH && base64Alphabet[octect] != -1);
- }
-
- /**
- * Encodes hex octects into Base64
- *
- * @param binaryData Array containing binaryData
- * @return Encoded Base64 array
- */
- public static String encode(byte[] binaryData)
- {
- if (binaryData == null)
- {
- return null;
- }
-
- int lengthDataBits = binaryData.length * EIGHTBIT;
- if (lengthDataBits == 0)
- {
- return "";
- }
-
- int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
- int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
- int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
- char encodedData[] = null;
-
- encodedData = new char[numberQuartet * 4];
-
- byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
-
- int encodedIndex = 0;
- int dataIndex = 0;
-
- for (int i = 0; i < numberTriplets; i++)
- {
- b1 = binaryData[dataIndex++];
- b2 = binaryData[dataIndex++];
- b3 = binaryData[dataIndex++];
-
- l = (byte) (b2 & 0x0f);
- k = (byte) (b1 & 0x03);
-
- byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
- byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
- byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
-
- encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
- }
-
- // form integral number of 6-bit groups
- if (fewerThan24bits == EIGHTBIT)
- {
- b1 = binaryData[dataIndex];
- k = (byte) (b1 & 0x03);
- byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
- encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
- encodedData[encodedIndex++] = PAD;
- encodedData[encodedIndex++] = PAD;
- }
- else if (fewerThan24bits == SIXTEENBIT)
- {
- b1 = binaryData[dataIndex];
- b2 = binaryData[dataIndex + 1];
- l = (byte) (b2 & 0x0f);
- k = (byte) (b1 & 0x03);
-
- byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
- byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
-
- encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
- encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
- encodedData[encodedIndex++] = PAD;
- }
- return new String(encodedData);
- }
-
- /**
- * Decodes Base64 data into octects
- *
- * @param encoded string containing Base64 data
- * @return Array containind decoded data.
- */
- public static byte[] decode(String encoded)
- {
- if (encoded == null)
- {
- return null;
- }
-
- char[] base64Data = encoded.toCharArray();
- // remove white spaces
- int len = removeWhiteSpace(base64Data);
-
- if (len % FOURBYTE != 0)
- {
- return null;// should be divisible by four
- }
-
- int numberQuadruple = (len / FOURBYTE);
-
- if (numberQuadruple == 0)
- {
- return new byte[0];
- }
-
- byte decodedData[] = null;
- byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
- char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
-
- int i = 0;
- int encodedIndex = 0;
- int dataIndex = 0;
- decodedData = new byte[(numberQuadruple) * 3];
-
- for (; i < numberQuadruple - 1; i++)
- {
-
- if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
- || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
- {
- return null;
- } // if found "no data" just return null
-
- b1 = base64Alphabet[d1];
- b2 = base64Alphabet[d2];
- b3 = base64Alphabet[d3];
- b4 = base64Alphabet[d4];
-
- decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
- decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
- decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
- }
-
- if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])))
- {
- return null;// if found "no data" just return null
- }
-
- b1 = base64Alphabet[d1];
- b2 = base64Alphabet[d2];
-
- d3 = base64Data[dataIndex++];
- d4 = base64Data[dataIndex++];
- if (!isData((d3)) || !isData((d4)))
- {// Check if they are PAD characters
- if (isPad(d3) && isPad(d4))
- {
- if ((b2 & 0xf) != 0)// last 4 bits should be zero
- {
- return null;
- }
- byte[] tmp = new byte[i * 3 + 1];
- System.arraycopy(decodedData, 0, tmp, 0, i * 3);
- tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
- return tmp;
- }
- else if (!isPad(d3) && isPad(d4))
- {
- b3 = base64Alphabet[d3];
- if ((b3 & 0x3) != 0)// last 2 bits should be zero
- {
- return null;
- }
- byte[] tmp = new byte[i * 3 + 2];
- System.arraycopy(decodedData, 0, tmp, 0, i * 3);
- tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
- tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
- return tmp;
- }
- else
- {
- return null;
- }
- }
- else
- { // No PAD e.g 3cQl
- b3 = base64Alphabet[d3];
- b4 = base64Alphabet[d4];
- decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
- decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
- decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
-
- }
- return decodedData;
- }
-
- /**
- * remove WhiteSpace from MIME containing encoded Base64 data.
- *
- * @param data the byte array of base64 data (with WS)
- * @return the new length
- */
- private static int removeWhiteSpace(char[] data)
- {
- if (data == null)
- {
- return 0;
- }
-
- // count characters that's not whitespace
- int newSize = 0;
- int len = data.length;
- for (int i = 0; i < len; i++)
- {
- if (!isWhiteSpace(data[i]))
- {
- data[newSize++] = data[i];
- }
- }
- return newSize;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sql/SqlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sql/SqlUtil.java
deleted file mode 100644
index 79eef92..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/sql/SqlUtil.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.ruoyi.common.core.utils.sql;
-
-import com.ruoyi.common.core.exception.UtilException;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * sql操作工具类
- *
- * @author ruoyi
- */
-public class SqlUtil
-{
- /**
- * 定义常用的 sql关键字
- */
- public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
-
- /**
- * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
- */
- public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
-
- /**
- * 限制orderBy最大长度
- */
- private static final int ORDER_BY_MAX_LENGTH = 500;
-
- /**
- * 检查字符,防止注入绕过
- */
- public static String escapeOrderBySql(String value)
- {
- if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
- {
- throw new UtilException("参数不符合规范,不能进行查询");
- }
- if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
- {
- throw new UtilException("参数已超过最大限制,不能进行查询");
- }
- return value;
- }
-
- /**
- * 验证 order by 语法是否符合规范
- */
- public static boolean isValidOrderBySql(String value)
- {
- return value.matches(SQL_PATTERN);
- }
-
- /**
- * SQL关键字检查
- */
- public static void filterKeyword(String value)
- {
- if (StringUtils.isEmpty(value))
- {
- return;
- }
- String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
- for (String sqlKeyword : sqlKeywords)
- {
- if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
- {
- throw new UtilException("参数存在SQL注入风险");
- }
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/IdUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/IdUtils.java
deleted file mode 100644
index 64d9024..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/IdUtils.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.ruoyi.common.core.utils.uuid;
-
-/**
- * ID生成器工具类
- *
- * @author ruoyi
- */
-public class IdUtils
-{
- /**
- * 获取随机UUID
- *
- * @return 随机UUID
- */
- public static String randomUUID()
- {
- return UUID.randomUUID().toString();
- }
-
- /**
- * 简化的UUID,去掉了横线
- *
- * @return 简化的UUID,去掉了横线
- */
- public static String simpleUUID()
- {
- return UUID.randomUUID().toString(true);
- }
-
- /**
- * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
- *
- * @return 随机UUID
- */
- public static String fastUUID()
- {
- return UUID.fastUUID().toString();
- }
-
- /**
- * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
- *
- * @return 简化的UUID,去掉了横线
- */
- public static String fastSimpleUUID()
- {
- return UUID.fastUUID().toString(true);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/Seq.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/Seq.java
deleted file mode 100644
index ba1c8a9..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/Seq.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.ruoyi.common.core.utils.uuid;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * @author ruoyi 序列生成类
- */
-public class Seq
-{
- // 通用序列类型
- public static final String commSeqType = "COMMON";
-
- // 上传序列类型
- public static final String uploadSeqType = "UPLOAD";
-
- // 通用接口序列数
- private static AtomicInteger commSeq = new AtomicInteger(1);
-
- // 上传接口序列数
- private static AtomicInteger uploadSeq = new AtomicInteger(1);
-
- // 机器标识
- private static final String machineCode = "A";
-
- /**
- * 获取通用序列号
- *
- * @return 序列值
- */
- public static String getId()
- {
- return getId(commSeqType);
- }
-
- /**
- * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
- *
- * @return 序列值
- */
- public static String getId(String type)
- {
- AtomicInteger atomicInt = commSeq;
- if (uploadSeqType.equals(type))
- {
- atomicInt = uploadSeq;
- }
- return getId(atomicInt, 3);
- }
-
- /**
- * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
- *
- * @param atomicInt 序列数
- * @param length 数值长度
- * @return 序列值
- */
- public static String getId(AtomicInteger atomicInt, int length)
- {
- String result = DateUtils.dateTimeNow();
- result += machineCode;
- result += getSeq(atomicInt, length);
- return result;
- }
-
- /**
- * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
- *
- * @return 序列值
- */
- private synchronized static String getSeq(AtomicInteger atomicInt, int length)
- {
- // 先取值再+1
- int value = atomicInt.getAndIncrement();
-
- // 如果更新后值>=10 的 (length)幂次方则重置为1
- int maxSeq = (int) Math.pow(10, length);
- if (atomicInt.get() >= maxSeq)
- {
- atomicInt.set(1);
- }
- // 转字符串,用0左补齐
- return StringUtils.padl(value, length);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/UUID.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/UUID.java
deleted file mode 100644
index cd7cb0f..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/uuid/UUID.java
+++ /dev/null
@@ -1,484 +0,0 @@
-package com.ruoyi.common.core.utils.uuid;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import com.ruoyi.common.core.exception.UtilException;
-
-/**
- * 提供通用唯一识别码(universally unique identifier)(UUID)实现
- *
- * @author ruoyi
- */
-public final class UUID implements java.io.Serializable, Comparable<UUID>
-{
- private static final long serialVersionUID = -1185015143654744140L;
-
- /**
- * SecureRandom 的单例
- *
- */
- private static class Holder
- {
- static final SecureRandom numberGenerator = getSecureRandom();
- }
-
- /** 此UUID的最高64有效位 */
- private final long mostSigBits;
-
- /** 此UUID的最低64有效位 */
- private final long leastSigBits;
-
- /**
- * 私有构造
- *
- * @param data 数据
- */
- private UUID(byte[] data)
- {
- long msb = 0;
- long lsb = 0;
- assert data.length == 16 : "data must be 16 bytes in length";
- for (int i = 0; i < 8; i++)
- {
- msb = (msb << 8) | (data[i] & 0xff);
- }
- for (int i = 8; i < 16; i++)
- {
- lsb = (lsb << 8) | (data[i] & 0xff);
- }
- this.mostSigBits = msb;
- this.leastSigBits = lsb;
- }
-
- /**
- * 使用指定的数据构造新的 UUID。
- *
- * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
- * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
- */
- public UUID(long mostSigBits, long leastSigBits)
- {
- this.mostSigBits = mostSigBits;
- this.leastSigBits = leastSigBits;
- }
-
- /**
- * 获取类型 4(伪随机生成的)UUID 的静态工厂。
- *
- * @return 随机生成的 {@code UUID}
- */
- public static UUID fastUUID()
- {
- return randomUUID(false);
- }
-
- /**
- * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
- *
- * @return 随机生成的 {@code UUID}
- */
- public static UUID randomUUID()
- {
- return randomUUID(true);
- }
-
- /**
- * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
- *
- * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
- * @return 随机生成的 {@code UUID}
- */
- public static UUID randomUUID(boolean isSecure)
- {
- final Random ng = isSecure ? Holder.numberGenerator : getRandom();
-
- byte[] randomBytes = new byte[16];
- ng.nextBytes(randomBytes);
- randomBytes[6] &= 0x0f; /* clear version */
- randomBytes[6] |= 0x40; /* set to version 4 */
- randomBytes[8] &= 0x3f; /* clear variant */
- randomBytes[8] |= 0x80; /* set to IETF variant */
- return new UUID(randomBytes);
- }
-
- /**
- * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
- *
- * @param name 用于构造 UUID 的字节数组。
- *
- * @return 根据指定数组生成的 {@code UUID}
- */
- public static UUID nameUUIDFromBytes(byte[] name)
- {
- MessageDigest md;
- try
- {
- md = MessageDigest.getInstance("MD5");
- }
- catch (NoSuchAlgorithmException nsae)
- {
- throw new InternalError("MD5 not supported");
- }
- byte[] md5Bytes = md.digest(name);
- md5Bytes[6] &= 0x0f; /* clear version */
- md5Bytes[6] |= 0x30; /* set to version 3 */
- md5Bytes[8] &= 0x3f; /* clear variant */
- md5Bytes[8] |= 0x80; /* set to IETF variant */
- return new UUID(md5Bytes);
- }
-
- /**
- * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
- *
- * @param name 指定 {@code UUID} 字符串
- * @return 具有指定值的 {@code UUID}
- * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
- *
- */
- public static UUID fromString(String name)
- {
- String[] components = name.split("-");
- if (components.length != 5)
- {
- throw new IllegalArgumentException("Invalid UUID string: " + name);
- }
- for (int i = 0; i < 5; i++)
- {
- components[i] = "0x" + components[i];
- }
-
- long mostSigBits = Long.decode(components[0]).longValue();
- mostSigBits <<= 16;
- mostSigBits |= Long.decode(components[1]).longValue();
- mostSigBits <<= 16;
- mostSigBits |= Long.decode(components[2]).longValue();
-
- long leastSigBits = Long.decode(components[3]).longValue();
- leastSigBits <<= 48;
- leastSigBits |= Long.decode(components[4]).longValue();
-
- return new UUID(mostSigBits, leastSigBits);
- }
-
- /**
- * 返回此 UUID 的 128 位值中的最低有效 64 位。
- *
- * @return 此 UUID 的 128 位值中的最低有效 64 位。
- */
- public long getLeastSignificantBits()
- {
- return leastSigBits;
- }
-
- /**
- * 返回此 UUID 的 128 位值中的最高有效 64 位。
- *
- * @return 此 UUID 的 128 位值中最高有效 64 位。
- */
- public long getMostSignificantBits()
- {
- return mostSigBits;
- }
-
- /**
- * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
- * <p>
- * 版本号具有以下含意:
- * <ul>
- * <li>1 基于时间的 UUID
- * <li>2 DCE 安全 UUID
- * <li>3 基于名称的 UUID
- * <li>4 随机生成的 UUID
- * </ul>
- *
- * @return 此 {@code UUID} 的版本号
- */
- public int version()
- {
- // Version is bits masked by 0x000000000000F000 in MS long
- return (int) ((mostSigBits >> 12) & 0x0f);
- }
-
- /**
- * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
- * <p>
- * 变体号具有以下含意:
- * <ul>
- * <li>0 为 NCS 向后兼容保留
- * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类
- * <li>6 保留,微软向后兼容
- * <li>7 保留供以后定义使用
- * </ul>
- *
- * @return 此 {@code UUID} 相关联的变体号
- */
- public int variant()
- {
- // This field is composed of a varying number of bits.
- // 0 - - Reserved for NCS backward compatibility
- // 1 0 - The IETF aka Leach-Salz variant (used by this class)
- // 1 1 0 Reserved, Microsoft backward compatibility
- // 1 1 1 Reserved for future definition.
- return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
- }
-
- /**
- * 与此 UUID 相关联的时间戳值。
- *
- * <p>
- * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
- * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
- *
- * <p>
- * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
- * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
- *
- * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
- */
- public long timestamp() throws UnsupportedOperationException
- {
- checkTimeBase();
- return (mostSigBits & 0x0FFFL) << 48//
- | ((mostSigBits >> 16) & 0x0FFFFL) << 32//
- | mostSigBits >>> 32;
- }
-
- /**
- * 与此 UUID 相关联的时钟序列值。
- *
- * <p>
- * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
- * <p>
- * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
- * UnsupportedOperationException。
- *
- * @return 此 {@code UUID} 的时钟序列
- *
- * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
- */
- public int clockSequence() throws UnsupportedOperationException
- {
- checkTimeBase();
- return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
- }
-
- /**
- * 与此 UUID 相关的节点值。
- *
- * <p>
- * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
- * <p>
- * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
- * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
- *
- * @return 此 {@code UUID} 的节点值
- *
- * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
- */
- public long node() throws UnsupportedOperationException
- {
- checkTimeBase();
- return leastSigBits & 0x0000FFFFFFFFFFFFL;
- }
-
- /**
- * 返回此{@code UUID} 的字符串表现形式。
- *
- * <p>
- * UUID 的字符串表示形式由此 BNF 描述:
- *
- * <pre>
- * {@code
- * UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
- * time_low = 4*<hexOctet>
- * time_mid = 2*<hexOctet>
- * time_high_and_version = 2*<hexOctet>
- * variant_and_sequence = 2*<hexOctet>
- * node = 6*<hexOctet>
- * hexOctet = <hexDigit><hexDigit>
- * hexDigit = [0-9a-fA-F]
- * }
- * </pre>
- *
- * </blockquote>
- *
- * @return 此{@code UUID} 的字符串表现形式
- * @see #toString(boolean)
- */
- @Override
- public String toString()
- {
- return toString(false);
- }
-
- /**
- * 返回此{@code UUID} 的字符串表现形式。
- *
- * <p>
- * UUID 的字符串表示形式由此 BNF 描述:
- *
- * <pre>
- * {@code
- * UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
- * time_low = 4*<hexOctet>
- * time_mid = 2*<hexOctet>
- * time_high_and_version = 2*<hexOctet>
- * variant_and_sequence = 2*<hexOctet>
- * node = 6*<hexOctet>
- * hexOctet = <hexDigit><hexDigit>
- * hexDigit = [0-9a-fA-F]
- * }
- * </pre>
- *
- * </blockquote>
- *
- * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
- * @return 此{@code UUID} 的字符串表现形式
- */
- public String toString(boolean isSimple)
- {
- final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
- // time_low
- builder.append(digits(mostSigBits >> 32, 8));
- if (!isSimple)
- {
- builder.append('-');
- }
- // time_mid
- builder.append(digits(mostSigBits >> 16, 4));
- if (!isSimple)
- {
- builder.append('-');
- }
- // time_high_and_version
- builder.append(digits(mostSigBits, 4));
- if (!isSimple)
- {
- builder.append('-');
- }
- // variant_and_sequence
- builder.append(digits(leastSigBits >> 48, 4));
- if (!isSimple)
- {
- builder.append('-');
- }
- // node
- builder.append(digits(leastSigBits, 12));
-
- return builder.toString();
- }
-
- /**
- * 返回此 UUID 的哈希码。
- *
- * @return UUID 的哈希码值。
- */
- @Override
- public int hashCode()
- {
- long hilo = mostSigBits ^ leastSigBits;
- return ((int) (hilo >> 32)) ^ (int) hilo;
- }
-
- /**
- * 将此对象与指定对象比较。
- * <p>
- * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
- *
- * @param obj 要与之比较的对象
- *
- * @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
- */
- @Override
- public boolean equals(Object obj)
- {
- if ((null == obj) || (obj.getClass() != UUID.class))
- {
- return false;
- }
- UUID id = (UUID) obj;
- return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
- }
-
- // Comparison Operations
-
- /**
- * 将此 UUID 与指定的 UUID 比较。
- *
- * <p>
- * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
- *
- * @param val 与此 UUID 比较的 UUID
- *
- * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
- *
- */
- @Override
- public int compareTo(UUID val)
- {
- // The ordering is intentionally set up so that the UUIDs
- // can simply be numerically compared as two numbers
- return (this.mostSigBits < val.mostSigBits ? -1 : //
- (this.mostSigBits > val.mostSigBits ? 1 : //
- (this.leastSigBits < val.leastSigBits ? -1 : //
- (this.leastSigBits > val.leastSigBits ? 1 : //
- 0))));
- }
-
- // -------------------------------------------------------------------------------------------------------------------
- // Private method start
- /**
- * 返回指定数字对应的hex值
- *
- * @param val 值
- * @param digits 位
- * @return 值
- */
- private static String digits(long val, int digits)
- {
- long hi = 1L << (digits * 4);
- return Long.toHexString(hi | (val & (hi - 1))).substring(1);
- }
-
- /**
- * 检查是否为time-based版本UUID
- */
- private void checkTimeBase()
- {
- if (version() != 1)
- {
- throw new UnsupportedOperationException("Not a time-based UUID");
- }
- }
-
- /**
- * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
- *
- * @return {@link SecureRandom}
- */
- public static SecureRandom getSecureRandom()
- {
- try
- {
- return SecureRandom.getInstance("SHA1PRNG");
- }
- catch (NoSuchAlgorithmException e)
- {
- throw new UtilException(e);
- }
- }
-
- /**
- * 获取随机数生成器对象<br>
- * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
- *
- * @return {@link ThreadLocalRandom}
- */
- public static ThreadLocalRandom getRandom()
- {
- return ThreadLocalRandom.current();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java
deleted file mode 100644
index 4109e29..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.ruoyi.common.core.web.controller;
-
-import java.beans.PropertyEditorSupport;
-import java.util.Date;
-import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.WebDataBinder;
-import org.springframework.web.bind.annotation.InitBinder;
-import com.github.pagehelper.PageHelper;
-import com.github.pagehelper.PageInfo;
-import com.ruoyi.common.core.constant.HttpStatus;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.PageUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.sql.SqlUtil;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.PageDomain;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.core.web.page.TableSupport;
-
-/**
- * web层通用数据处理
- *
- * @author ruoyi
- */
-public class BaseController
-{
- protected final Logger logger = LoggerFactory.getLogger(this.getClass());
-
- /**
- * 将前台传递过来的日期格式的字符串,自动转化为Date类型
- */
- @InitBinder
- public void initBinder(WebDataBinder binder)
- {
- // Date 类型转换
- binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
- {
- @Override
- public void setAsText(String text)
- {
- setValue(DateUtils.parseDate(text));
- }
- });
- }
-
- /**
- * 设置请求分页数据
- */
- protected void startPage()
- {
- PageUtils.startPage();
- }
-
- /**
- * 设置请求排序数据
- */
- protected void startOrderBy()
- {
- PageDomain pageDomain = TableSupport.buildPageRequest();
- if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
- {
- String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
- PageHelper.orderBy(orderBy);
- }
- }
-
- /**
- * 清理分页的线程变量
- */
- protected void clearPage()
- {
- PageUtils.clearPage();
- }
-
- /**
- * 响应请求分页数据
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- protected TableDataInfo getDataTable(List<?> list)
- {
- TableDataInfo rspData = new TableDataInfo();
- rspData.setCode(HttpStatus.SUCCESS);
- rspData.setRows(list);
- rspData.setMsg("查询成功");
- rspData.setTotal(new PageInfo(list).getTotal());
- return rspData;
- }
-
- /**
- * 返回成功
- */
- public AjaxResult success()
- {
- return AjaxResult.success();
- }
-
- /**
- * 返回成功消息
- */
- public AjaxResult success(String message)
- {
- return AjaxResult.success(message);
- }
-
- /**
- * 返回成功消息
- */
- public AjaxResult success(Object data)
- {
- return AjaxResult.success(data);
- }
-
- /**
- * 返回失败消息
- */
- public AjaxResult error()
- {
- return AjaxResult.error();
- }
-
- /**
- * 返回失败消息
- */
- public AjaxResult error(String message)
- {
- return AjaxResult.error(message);
- }
-
- /**
- * 返回警告消息
- */
- public AjaxResult warn(String message)
- {
- return AjaxResult.warn(message);
- }
-
- /**
- * 响应返回结果
- *
- * @param rows 影响行数
- * @return 操作结果
- */
- protected AjaxResult toAjax(int rows)
- {
- return rows > 0 ? AjaxResult.success() : AjaxResult.error();
- }
-
- /**
- * 响应返回结果
- *
- * @param result 结果
- * @return 操作结果
- */
- protected AjaxResult toAjax(boolean result)
- {
- return result ? success() : error();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
deleted file mode 100644
index 61d00ae..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package com.ruoyi.common.core.web.domain;
-
-import java.util.HashMap;
-import java.util.Objects;
-import com.ruoyi.common.core.constant.HttpStatus;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 操作消息提醒
- *
- * @author ruoyi
- */
-public class AjaxResult extends HashMap<String, Object>
-{
- private static final long serialVersionUID = 1L;
-
- /** 状态码 */
- public static final String CODE_TAG = "code";
-
- /** 返回内容 */
- public static final String MSG_TAG = "msg";
-
- /** 数据对象 */
- public static final String DATA_TAG = "data";
-
- /**
- * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
- */
- public AjaxResult()
- {
- }
-
- /**
- * 初始化一个新创建的 AjaxResult 对象
- *
- * @param code 状态码
- * @param msg 返回内容
- */
- public AjaxResult(int code, String msg)
- {
- super.put(CODE_TAG, code);
- super.put(MSG_TAG, msg);
- }
-
- /**
- * 初始化一个新创建的 AjaxResult 对象
- *
- * @param code 状态码
- * @param msg 返回内容
- * @param data 数据对象
- */
- public AjaxResult(int code, String msg, Object data)
- {
- super.put(CODE_TAG, code);
- super.put(MSG_TAG, msg);
- if (StringUtils.isNotNull(data))
- {
- super.put(DATA_TAG, data);
- }
- }
-
- /**
- * 返回成功消息
- *
- * @return 成功消息
- */
- public static AjaxResult success()
- {
- return AjaxResult.success("操作成功");
- }
-
- /**
- * 返回成功数据
- *
- * @return 成功消息
- */
- public static AjaxResult success(Object data)
- {
- return AjaxResult.success("操作成功", data);
- }
-
- /**
- * 返回成功消息
- *
- * @param msg 返回内容
- * @return 成功消息
- */
- public static AjaxResult success(String msg)
- {
- return AjaxResult.success(msg, null);
- }
-
- /**
- * 返回成功消息
- *
- * @param msg 返回内容
- * @param data 数据对象
- * @return 成功消息
- */
- public static AjaxResult success(String msg, Object data)
- {
- return new AjaxResult(HttpStatus.SUCCESS, msg, data);
- }
-
- /**
- * 返回警告消息
- *
- * @param msg 返回内容
- * @return 警告消息
- */
- public static AjaxResult warn(String msg)
- {
- return AjaxResult.warn(msg, null);
- }
-
- /**
- * 返回警告消息
- *
- * @param msg 返回内容
- * @param data 数据对象
- * @return 警告消息
- */
- public static AjaxResult warn(String msg, Object data)
- {
- return new AjaxResult(HttpStatus.WARN, msg, data);
- }
-
- /**
- * 返回错误消息
- *
- * @return 错误消息
- */
- public static AjaxResult error()
- {
- return AjaxResult.error("操作失败");
- }
-
- /**
- * 返回错误消息
- *
- * @param msg 返回内容
- * @return 错误消息
- */
- public static AjaxResult error(String msg)
- {
- return AjaxResult.error(msg, null);
- }
-
- /**
- * 返回错误消息
- *
- * @param msg 返回内容
- * @param data 数据对象
- * @return 错误消息
- */
- public static AjaxResult error(String msg, Object data)
- {
- return new AjaxResult(HttpStatus.ERROR, msg, data);
- }
-
- /**
- * 返回错误消息
- *
- * @param code 状态码
- * @param msg 返回内容
- * @return 错误消息
- */
- public static AjaxResult error(int code, String msg)
- {
- return new AjaxResult(code, msg, null);
- }
-
- /**
- * 是否为成功消息
- *
- * @return 结果
- */
- public boolean isSuccess()
- {
- return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
- }
-
- /**
- * 是否为警告消息
- *
- * @return 结果
- */
- public boolean isWarn()
- {
- return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
- }
-
- /**
- * 是否为错误消息
- *
- * @return 结果
- */
- public boolean isError()
- {
- return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
- }
-
- /**
- * 方便链式调用
- *
- * @param key
- * @param value
- * @return
- */
- @Override
- public AjaxResult put(String key, Object value)
- {
- super.put(key, value);
- return this;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/BaseEntity.java
deleted file mode 100644
index 1327c9b..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/BaseEntity.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.ruoyi.common.core.web.domain;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonInclude;
-
-/**
- * Entity基类
- *
- * @author ruoyi
- */
-public class BaseEntity implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /** 搜索值 */
- @JsonIgnore
- private String searchValue;
-
- /** 创建者 */
- private String createBy;
-
- /** 创建时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date createTime;
-
- /** 更新者 */
- private String updateBy;
-
- /** 更新时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date updateTime;
-
- /** 备注 */
- private String remark;
-
- /** 请求参数 */
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
- private Map<String, Object> params;
-
- public String getSearchValue()
- {
- return searchValue;
- }
-
- public void setSearchValue(String searchValue)
- {
- this.searchValue = searchValue;
- }
-
- public String getCreateBy()
- {
- return createBy;
- }
-
- public void setCreateBy(String createBy)
- {
- this.createBy = createBy;
- }
-
- public Date getCreateTime()
- {
- return createTime;
- }
-
- public void setCreateTime(Date createTime)
- {
- this.createTime = createTime;
- }
-
- public String getUpdateBy()
- {
- return updateBy;
- }
-
- public void setUpdateBy(String updateBy)
- {
- this.updateBy = updateBy;
- }
-
- public Date getUpdateTime()
- {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime)
- {
- this.updateTime = updateTime;
- }
-
- public String getRemark()
- {
- return remark;
- }
-
- public void setRemark(String remark)
- {
- this.remark = remark;
- }
-
- public Map<String, Object> getParams()
- {
- if (params == null)
- {
- params = new HashMap<>();
- }
- return params;
- }
-
- public void setParams(Map<String, Object> params)
- {
- this.params = params;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/TreeEntity.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/TreeEntity.java
deleted file mode 100644
index 909d1e6..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/TreeEntity.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.ruoyi.common.core.web.domain;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tree基类
- *
- * @author ruoyi
- */
-public class TreeEntity extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 父菜单名称 */
- private String parentName;
-
- /** 父菜单ID */
- private Long parentId;
-
- /** 显示顺序 */
- private Integer orderNum;
-
- /** 祖级列表 */
- private String ancestors;
-
- /** 子部门 */
- private List<?> children = new ArrayList<>();
-
- public String getParentName()
- {
- return parentName;
- }
-
- public void setParentName(String parentName)
- {
- this.parentName = parentName;
- }
-
- public Long getParentId()
- {
- return parentId;
- }
-
- public void setParentId(Long parentId)
- {
- this.parentId = parentId;
- }
-
- public Integer getOrderNum()
- {
- return orderNum;
- }
-
- public void setOrderNum(Integer orderNum)
- {
- this.orderNum = orderNum;
- }
-
- public String getAncestors()
- {
- return ancestors;
- }
-
- public void setAncestors(String ancestors)
- {
- this.ancestors = ancestors;
- }
-
- public List<?> getChildren()
- {
- return children;
- }
-
- public void setChildren(List<?> children)
- {
- this.children = children;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/PageDomain.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/PageDomain.java
deleted file mode 100644
index 413aabf..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/PageDomain.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.ruoyi.common.core.web.page;
-
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 分页数据
- *
- * @author ruoyi
- */
-public class PageDomain
-{
- /** 当前记录起始索引 */
- private Integer pageNum;
-
- /** 每页显示记录数 */
- private Integer pageSize;
-
- /** 排序列 */
- private String orderByColumn;
-
- /** 排序的方向desc或者asc */
- private String isAsc = "asc";
-
- /** 分页参数合理化 */
- private Boolean reasonable = true;
-
- public String getOrderBy()
- {
- if (StringUtils.isEmpty(orderByColumn))
- {
- return "";
- }
- return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
- }
-
- public Integer getPageNum()
- {
- return pageNum;
- }
-
- public void setPageNum(Integer pageNum)
- {
- this.pageNum = pageNum;
- }
-
- public Integer getPageSize()
- {
- return pageSize;
- }
-
- public void setPageSize(Integer pageSize)
- {
- this.pageSize = pageSize;
- }
-
- public String getOrderByColumn()
- {
- return orderByColumn;
- }
-
- public void setOrderByColumn(String orderByColumn)
- {
- this.orderByColumn = orderByColumn;
- }
-
- public String getIsAsc()
- {
- return isAsc;
- }
-
- public void setIsAsc(String isAsc)
- {
- if (StringUtils.isNotEmpty(isAsc))
- {
- // 兼容前端排序类型
- if ("ascending".equals(isAsc))
- {
- isAsc = "asc";
- }
- else if ("descending".equals(isAsc))
- {
- isAsc = "desc";
- }
- this.isAsc = isAsc;
- }
- }
-
- public Boolean getReasonable()
- {
- if (StringUtils.isNull(reasonable))
- {
- return Boolean.TRUE;
- }
- return reasonable;
- }
-
- public void setReasonable(Boolean reasonable)
- {
- this.reasonable = reasonable;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableDataInfo.java
deleted file mode 100644
index 7fe3ac0..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableDataInfo.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.ruoyi.common.core.web.page;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 表格分页数据对象
- *
- * @author ruoyi
- */
-public class TableDataInfo implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /** 总记录数 */
- private long total;
-
- /** 列表数据 */
- private List<?> rows;
-
- /** 消息状态码 */
- private int code;
-
- /** 消息内容 */
- private String msg;
-
- /**
- * 表格数据对象
- */
- public TableDataInfo()
- {
- }
-
- /**
- * 分页
- *
- * @param list 列表数据
- * @param total 总记录数
- */
- public TableDataInfo(List<?> list, long total)
- {
- this.rows = list;
- this.total = total;
- }
-
- public long getTotal()
- {
- return total;
- }
-
- public void setTotal(long total)
- {
- this.total = total;
- }
-
- public List<?> getRows()
- {
- return rows;
- }
-
- public void setRows(List<?> rows)
- {
- this.rows = rows;
- }
-
- public int getCode()
- {
- return code;
- }
-
- public void setCode(int code)
- {
- this.code = code;
- }
-
- public String getMsg()
- {
- return msg;
- }
-
- public void setMsg(String msg)
- {
- this.msg = msg;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableSupport.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableSupport.java
deleted file mode 100644
index 0f4abaa..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/page/TableSupport.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.ruoyi.common.core.web.page;
-
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.ServletUtils;
-
-/**
- * 表格数据处理
- *
- * @author ruoyi
- */
-public class TableSupport
-{
- /**
- * 当前记录起始索引
- */
- public static final String PAGE_NUM = "pageNum";
-
- /**
- * 每页显示记录数
- */
- public static final String PAGE_SIZE = "pageSize";
-
- /**
- * 排序列
- */
- public static final String ORDER_BY_COLUMN = "orderByColumn";
-
- /**
- * 排序的方向 "desc" 或者 "asc".
- */
- public static final String IS_ASC = "isAsc";
-
- /**
- * 分页参数合理化
- */
- public static final String REASONABLE = "reasonable";
-
- /**
- * 封装分页对象
- */
- public static PageDomain getPageDomain()
- {
- PageDomain pageDomain = new PageDomain();
- pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
- pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
- pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
- pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
- pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
- return pageDomain;
- }
-
- public static PageDomain buildPageRequest()
- {
- return getPageDomain();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java
deleted file mode 100644
index 081a5a7..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.ruoyi.common.core.xss;
-
-import jakarta.validation.Constraint;
-import jakarta.validation.Payload;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 自定义xss校验注解
- *
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
-@Constraint(validatedBy = { XssValidator.class })
-public @interface Xss
-{
- String message()
-
- default "不允许任何脚本运行";
-
- Class<?>[] groups() default {};
-
- Class<? extends Payload>[] payload() default {};
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java
deleted file mode 100644
index b64c209..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.ruoyi.common.core.xss;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import jakarta.validation.ConstraintValidator;
-import jakarta.validation.ConstraintValidatorContext;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 自定义xss校验注解实现
- *
- * @author ruoyi
- */
-public class XssValidator implements ConstraintValidator<Xss, String>
-{
- private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
-
- @Override
- public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
- {
- if (StringUtils.isBlank(value))
- {
- return true;
- }
- return !containsHtml(value);
- }
-
- public static boolean containsHtml(String value)
- {
- StringBuilder sHtml = new StringBuilder();
- Pattern pattern = Pattern.compile(HTML_PATTERN);
- Matcher matcher = pattern.matcher(value);
- while (matcher.find())
- {
- sHtml.append(matcher.group());
- }
- return pattern.matcher(sHtml).matches();
- }
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/annotation/DataScope.java b/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/annotation/DataScope.java
deleted file mode 100644
index 77e2860..0000000
--- a/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/annotation/DataScope.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.ruoyi.common.datascope.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 数据权限过滤注解
- *
- * @author ruoyi
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface DataScope
-{
- /**
- * 用户表的别名
- */
- public String userAlias() default "";
-
- /**
- * 部门表的别名
- */
- public String deptAlias() default "";
-
- /**
- * 用户字段名
- */
- public String userField() default "user_id";
-
- /**
- * 部门字段名
- */
- public String deptField() default "dept_id";
-
- /**
- * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@RequiresPermissions获取,多个权限用逗号分隔开来
- */
- public String permission() default "";
-}
diff --git a/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/aspect/DataScopeAspect.java b/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/aspect/DataScopeAspect.java
deleted file mode 100644
index 847c143..0000000
--- a/ruoyi-common/ruoyi-common-datascope/src/main/java/com/ruoyi/common/datascope/aspect/DataScopeAspect.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.ruoyi.common.datascope.aspect;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.context.SecurityContextHolder;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-import com.ruoyi.common.datascope.annotation.DataScope;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.model.LoginUser;
-
-/**
- * 数据过滤处理
- *
- * @author ruoyi
- */
-@Aspect
-@Component
-public class DataScopeAspect
-{
- /**
- * 数据权限过滤关键字
- */
- public static final String DATA_SCOPE = "dataScope";
-
- @Before("@annotation(controllerDataScope)")
- public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
- {
- clearDataScope(point);
- handleDataScope(point, controllerDataScope);
- }
-
- protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
- {
- // 获取当前的用户
- LoginUser loginUser = SecurityUtils.getLoginUser();
- if (StringUtils.isNotNull(loginUser))
- {
- SysUser currentUser = loginUser.getSysUser();
- // 如果是超级管理员,则不过滤数据
- if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
- {
- String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission());
- dataScopeFilter(joinPoint, currentUser, controllerDataScope.userAlias(), controllerDataScope.deptAlias(), controllerDataScope.userField(), controllerDataScope.deptField(), permission);
- }
- }
- }
-
- /**
- * 数据范围过滤
- *
- * @param joinPoint 切点
- * @param user 用户
- * @param deptAlias 部门别名
- * @param userAlias 用户别名
- * @param permission 权限字符
- */
- public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String userAlias, String deptAlias, String userField, String deptField, String permission)
- {
- StringBuilder sqlString = new StringBuilder();
- List<String> conditions = new ArrayList<String>();
- List<String> scopeCustomIds = new ArrayList<String>();
- user.getRoles().forEach(role -> {
- if (Constants.Dept.DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && (StringUtils.isEmpty(permission) || StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))))
- {
- scopeCustomIds.add(Convert.toStr(role.getRoleId()));
- }
- });
-
- for (SysRole role : user.getRoles())
- {
- String dataScope = role.getDataScope();
- if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
- {
- continue;
- }
- if (StringUtils.isNotEmpty(permission) && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
- {
- continue;
- }
- if (Constants.Dept.DATA_SCOPE_ALL.equals(dataScope))
- {
- sqlString = new StringBuilder();
- conditions.add(dataScope);
- break;
- }
- else if (Constants.Dept.DATA_SCOPE_CUSTOM.equals(dataScope))
- {
- if (scopeCustomIds.size() > 1)
- {
- // 多个自定数据权限使用in查询,避免多次拼接。
- sqlString.append(StringUtils.format(" OR {}.{} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, deptField, String.join(",", scopeCustomIds)));
- }
- else
- {
- sqlString.append(StringUtils.format(" OR {}.{} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, deptField, role.getRoleId()));
- }
- }
- else if (Constants.Dept.DATA_SCOPE_DEPT.equals(dataScope))
- {
- sqlString.append(StringUtils.format(" OR {}.{} = {} ", deptAlias, deptField, user.getDeptId()));
- }
- else if (Constants.Dept.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
- {
- sqlString.append(StringUtils.format(" OR {}.{} IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, deptField, user.getDeptId(), user.getDeptId()));
- }
- else if (Constants.Dept.DATA_SCOPE_SELF.equals(dataScope))
- {
- if (StringUtils.isNotBlank(userAlias))
- {
- sqlString.append(StringUtils.format(" OR {}.{} = {} ", userAlias, userField, user.getUserId()));
- }
- else
- {
- // 数据权限为仅本人且没有userAlias别名不查询任何数据
- sqlString.append(StringUtils.format(" OR {}.{} = 0 ", deptAlias, deptField));
- }
- }
- conditions.add(dataScope);
- }
-
- // 角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据
- if (StringUtils.isEmpty(conditions))
- {
- sqlString.append(StringUtils.format(" OR {}.{} = 0 ", deptAlias, deptField));
- }
-
- if (StringUtils.isNotBlank(sqlString.toString()))
- {
- Object params = joinPoint.getArgs()[0];
- if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
- {
- BaseEntity baseEntity = (BaseEntity) params;
- baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
- }
- }
- }
-
- /**
- * 拼接权限sql前先清空params.dataScope参数防止注入
- */
- private void clearDataScope(final JoinPoint joinPoint)
- {
- Object params = joinPoint.getArgs()[0];
- if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
- {
- BaseEntity baseEntity = (BaseEntity) params;
- baseEntity.getParams().put(DATA_SCOPE, "");
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Master.java b/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Master.java
deleted file mode 100644
index 6ebec02..0000000
--- a/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Master.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.common.datasource.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.baomidou.dynamic.datasource.annotation.DS;
-
-/**
- * 主库数据源
- *
- * @author ruoyi
- */
-@Target({ ElementType.TYPE, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@DS("master")
-public @interface Master
-{
-
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Slave.java b/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Slave.java
deleted file mode 100644
index 9ee0941..0000000
--- a/ruoyi-common/ruoyi-common-datasource/src/main/java/com/ruoyi/common/datasource/annotation/Slave.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.common.datasource.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.baomidou.dynamic.datasource.annotation.DS;
-
-/**
- * 从库数据源
- *
- * @author ruoyi
- */
-@Target({ ElementType.TYPE, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@DS("slave")
-public @interface Slave
-{
-
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java
deleted file mode 100644
index 7735c65..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/annotation/Log.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.ruoyi.common.log.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.log.enums.OperatorType;
-
-/**
- * 自定义操作日志记录注解
- *
- * @author ruoyi
- *
- */
-@Target({ ElementType.PARAMETER, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Log
-{
- /**
- * 模块
- */
- public String title() default "";
-
- /**
- * 功能
- */
- public BusinessType businessType() default BusinessType.OTHER;
-
- /**
- * 操作人类别
- */
- public OperatorType operatorType() default OperatorType.MANAGE;
-
- /**
- * 是否保存请求的参数
- */
- public boolean isSaveRequestData() default true;
-
- /**
- * 是否保存响应的参数
- */
- public boolean isSaveResponseData() default true;
-
- /**
- * 排除指定的请求参数
- */
- public String[] excludeParamNames() default {};
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java
deleted file mode 100644
index e09c4c1..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/aspect/LogAspect.java
+++ /dev/null
@@ -1,258 +0,0 @@
-package com.ruoyi.common.log.aspect;
-
-import java.util.Collection;
-import java.util.Map;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.AfterReturning;
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.NamedThreadLocal;
-import org.springframework.http.HttpMethod;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.BindingResult;
-import org.springframework.web.multipart.MultipartFile;
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.ExceptionUtil;
-import com.ruoyi.common.core.utils.ServletUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.ip.IpUtils;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessStatus;
-import com.ruoyi.common.log.filter.PropertyPreExcludeFilter;
-import com.ruoyi.common.log.service.AsyncLogService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysOperLog;
-
-/**
- * 操作日志记录处理
- *
- * @author ruoyi
- */
-@Aspect
-@Component
-public class LogAspect
-{
- private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
-
- /** 排除敏感属性字段 */
- public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
-
- /** 计算操作消耗时间 */
- private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
-
- /** 参数最大长度限制 */
- private static final int PARAM_MAX_LENGTH = 2000;
-
- @Autowired
- private AsyncLogService asyncLogService;
-
- /**
- * 处理请求前执行
- */
- @Before(value = "@annotation(controllerLog)")
- public void doBefore(JoinPoint joinPoint, Log controllerLog)
- {
- TIME_THREADLOCAL.set(System.currentTimeMillis());
- }
-
- /**
- * 处理完请求后执行
- *
- * @param joinPoint 切点
- */
- @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
- public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
- {
- handleLog(joinPoint, controllerLog, null, jsonResult);
- }
-
- /**
- * 拦截异常操作
- *
- * @param joinPoint 切点
- * @param e 异常
- */
- @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
- public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
- {
- handleLog(joinPoint, controllerLog, e, null);
- }
-
- protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
- {
- try
- {
- // *========数据库日志=========*//
- SysOperLog operLog = new SysOperLog();
- operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
- // 请求的地址
- String ip = IpUtils.getIpAddr();
- operLog.setOperIp(ip);
- operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
- String username = SecurityUtils.getUsername();
- if (StringUtils.isNotBlank(username))
- {
- operLog.setOperName(username);
- }
-
- if (e != null)
- {
- operLog.setStatus(BusinessStatus.FAIL.ordinal());
- operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000));
- }
- // 设置方法名称
- String className = joinPoint.getTarget().getClass().getName();
- String methodName = joinPoint.getSignature().getName();
- operLog.setMethod(className + "." + methodName + "()");
- // 设置请求方式
- operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
- // 处理设置注解上的参数
- getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
- // 设置消耗时间
- operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
- // 保存数据库
- asyncLogService.saveSysLog(operLog);
- }
- catch (Exception exp)
- {
- // 记录本地异常日志
- log.error("异常信息:{}", exp.getMessage());
- exp.printStackTrace();
- }
- finally
- {
- TIME_THREADLOCAL.remove();
- }
- }
-
- /**
- * 获取注解中对方法的描述信息 用于Controller层注解
- *
- * @param log 日志
- * @param operLog 操作日志
- * @throws Exception
- */
- public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
- {
- // 设置action动作
- operLog.setBusinessType(log.businessType().ordinal());
- // 设置标题
- operLog.setTitle(log.title());
- // 设置操作人类别
- operLog.setOperatorType(log.operatorType().ordinal());
- // 是否需要保存request,参数和值
- if (log.isSaveRequestData())
- {
- // 获取参数的信息,传入到数据库中。
- setRequestValue(joinPoint, operLog, log.excludeParamNames());
- }
- // 是否需要保存response,参数和值
- if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
- {
- operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
- }
- }
-
- /**
- * 获取请求的参数,放到log中
- *
- * @param operLog 操作日志
- * @throws Exception 异常
- */
- private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
- {
- String requestMethod = operLog.getRequestMethod();
- Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
- if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
- {
- String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
- operLog.setOperParam(params);
- }
- else
- {
- operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, PARAM_MAX_LENGTH));
- }
- }
-
- /**
- * 参数拼装
- */
- private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
- {
- StringBuilder params = new StringBuilder();
- if (paramsArray != null && paramsArray.length > 0)
- {
- for (Object o : paramsArray)
- {
- if (StringUtils.isNotNull(o) && !isFilterObject(o))
- {
- try
- {
- String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
- params.append(jsonObj).append(" ");
- if (params.length() >= PARAM_MAX_LENGTH)
- {
- return StringUtils.substring(params.toString(), 0, PARAM_MAX_LENGTH);
- }
- }
- catch (Exception e)
- {
- log.error("请求参数拼装异常 msg:{}, 参数:{}", e.getMessage(), paramsArray, e);
- }
- }
- }
- }
- return params.toString();
- }
-
- /**
- * 忽略敏感属性
- */
- public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
- {
- return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
- }
-
- /**
- * 判断是否需要过滤的对象。
- *
- * @param o 对象信息。
- * @return 如果是需要过滤的对象,则返回true;否则返回false。
- */
- @SuppressWarnings("rawtypes")
- public boolean isFilterObject(final Object o)
- {
- Class<?> clazz = o.getClass();
- if (clazz.isArray())
- {
- return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
- }
- else if (Collection.class.isAssignableFrom(clazz))
- {
- Collection collection = (Collection) o;
- for (Object value : collection)
- {
- return value instanceof MultipartFile;
- }
- }
- else if (Map.class.isAssignableFrom(clazz))
- {
- Map map = (Map) o;
- for (Object value : map.entrySet())
- {
- Map.Entry entry = (Map.Entry) value;
- return entry.getValue() instanceof MultipartFile;
- }
- }
- return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
- || o instanceof BindingResult;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java
deleted file mode 100644
index cd644ba..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessStatus.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.common.log.enums;
-
-/**
- * 操作状态
- *
- * @author ruoyi
- *
- */
-public enum BusinessStatus
-{
- /**
- * 成功
- */
- SUCCESS,
-
- /**
- * 失败
- */
- FAIL,
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java
deleted file mode 100644
index 3a9a71c..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/BusinessType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.common.log.enums;
-
-/**
- * 业务操作类型
- *
- * @author ruoyi
- */
-public enum BusinessType
-{
- /**
- * 其它
- */
- OTHER,
-
- /**
- * 新增
- */
- INSERT,
-
- /**
- * 修改
- */
- UPDATE,
-
- /**
- * 删除
- */
- DELETE,
-
- /**
- * 授权
- */
- GRANT,
-
- /**
- * 导出
- */
- EXPORT,
-
- /**
- * 导入
- */
- IMPORT,
-
- /**
- * 强退
- */
- FORCE,
-
- /**
- * 生成代码
- */
- GENCODE,
-
- /**
- * 清空数据
- */
- CLEAN,
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java
deleted file mode 100644
index b122f25..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/enums/OperatorType.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.log.enums;
-
-/**
- * 操作人类别
- *
- * @author ruoyi
- */
-public enum OperatorType
-{
- /**
- * 其它
- */
- OTHER,
-
- /**
- * 后台用户
- */
- MANAGE,
-
- /**
- * 手机端用户
- */
- MOBILE
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/filter/PropertyPreExcludeFilter.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/filter/PropertyPreExcludeFilter.java
deleted file mode 100644
index 5391993..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/filter/PropertyPreExcludeFilter.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.log.filter;
-
-import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
-
-/**
- * 排除JSON敏感属性
- *
- * @author ruoyi
- */
-public class PropertyPreExcludeFilter extends SimplePropertyPreFilter
-{
- public PropertyPreExcludeFilter()
- {
- }
-
- public PropertyPreExcludeFilter addExcludes(String... filters)
- {
- for (int i = 0; i < filters.length; i++)
- {
- this.getExcludes().add(filters[i]);
- }
- return this;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/service/AsyncLogService.java b/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/service/AsyncLogService.java
deleted file mode 100644
index eb9a13a..0000000
--- a/ruoyi-common/ruoyi-common-log/src/main/java/com/ruoyi/common/log/service/AsyncLogService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.common.log.service;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.system.api.RemoteLogService;
-import com.ruoyi.system.api.domain.SysOperLog;
-
-/**
- * 异步调用日志服务
- *
- * @author ruoyi
- */
-@Service
-public class AsyncLogService
-{
- @Autowired
- private RemoteLogService remoteLogService;
-
- /**
- * 保存系统日志记录
- */
- @Async
- public void saveSysLog(SysOperLog sysOperLog) throws Exception
- {
- remoteLogService.saveLog(sysOperLog, SecurityConstants.INNER);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java
deleted file mode 100644
index 7450399..0000000
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/FastJson2JsonRedisSerializer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.ruoyi.common.redis.configure;
-
-import java.nio.charset.Charset;
-import org.springframework.data.redis.serializer.RedisSerializer;
-import org.springframework.data.redis.serializer.SerializationException;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONReader;
-import com.alibaba.fastjson2.JSONWriter;
-import com.alibaba.fastjson2.filter.Filter;
-import com.ruoyi.common.core.constant.Constants;
-
-/**
- * Redis使用FastJson序列化
- *
- * @author ruoyi
- */
-public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
-{
- public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
-
- static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
-
- private Class<T> clazz;
-
- public FastJson2JsonRedisSerializer(Class<T> clazz)
- {
- super();
- this.clazz = clazz;
- }
-
- @Override
- public byte[] serialize(T t) throws SerializationException
- {
- if (t == null)
- {
- return new byte[0];
- }
- return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
- }
-
- @Override
- public T deserialize(byte[] bytes) throws SerializationException
- {
- if (bytes == null || bytes.length <= 0)
- {
- return null;
- }
- String str = new String(bytes, DEFAULT_CHARSET);
-
- return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java
deleted file mode 100644
index 3d1a57a..0000000
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/configure/RedisConfig.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.ruoyi.common.redis.configure;
-
-import org.springframework.cache.annotation.CachingConfigurerSupport;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-/**
- * redis配置
- *
- * @author ruoyi
- */
-@SuppressWarnings("deprecation")
-@Configuration
-@EnableCaching
-public class RedisConfig extends CachingConfigurerSupport
-{
- @Bean(name = "ruoyiRedisTemplate")
- @Primary
- @SuppressWarnings(value = { "unchecked", "rawtypes" })
- public RedisTemplate<Object, Object> ruoyiRedisTemplate(RedisConnectionFactory connectionFactory)
- {
- RedisTemplate<Object, Object> template = new RedisTemplate<>();
- template.setConnectionFactory(connectionFactory);
-
- FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
-
- // 使用StringRedisSerializer来序列化和反序列化redis的key值
- template.setKeySerializer(new StringRedisSerializer());
- template.setValueSerializer(serializer);
-
- // Hash的key也采用StringRedisSerializer的序列化方式
- template.setHashKeySerializer(new StringRedisSerializer());
- template.setHashValueSerializer(serializer);
-
- template.afterPropertiesSet();
- return template;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java b/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java
deleted file mode 100644
index 67ac6e3..0000000
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/com/ruoyi/common/redis/service/RedisService.java
+++ /dev/null
@@ -1,268 +0,0 @@
-package com.ruoyi.common.redis.service;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.BoundSetOperations;
-import org.springframework.data.redis.core.HashOperations;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.ValueOperations;
-import org.springframework.stereotype.Component;
-
-/**
- * spring redis 工具类
- *
- * @author ruoyi
- **/
-@SuppressWarnings(value = { "unchecked", "rawtypes" })
-@Component
-public class RedisService
-{
- @Autowired
- public RedisTemplate redisTemplate;
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- */
- public <T> void setCacheObject(final String key, final T value)
- {
- redisTemplate.opsForValue().set(key, value);
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- * @param timeout 时间
- * @param timeUnit 时间颗粒度
- */
- public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
- {
- redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout)
- {
- return expire(key, timeout, TimeUnit.SECONDS);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @param unit 时间单位
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout, final TimeUnit unit)
- {
- return redisTemplate.expire(key, timeout, unit);
- }
-
- /**
- * 获取有效时间
- *
- * @param key Redis键
- * @return 有效时间
- */
- public long getExpire(final String key)
- {
- return redisTemplate.getExpire(key);
- }
-
- /**
- * 判断 key是否存在
- *
- * @param key 键
- * @return true 存在 false不存在
- */
- public Boolean hasKey(String key)
- {
- return redisTemplate.hasKey(key);
- }
-
- /**
- * 获得缓存的基本对象。
- *
- * @param key 缓存键值
- * @return 缓存键值对应的数据
- */
- public <T> T getCacheObject(final String key)
- {
- ValueOperations<String, T> operation = redisTemplate.opsForValue();
- return operation.get(key);
- }
-
- /**
- * 删除单个对象
- *
- * @param key
- */
- public boolean deleteObject(final String key)
- {
- return redisTemplate.delete(key);
- }
-
- /**
- * 删除集合对象
- *
- * @param collection 多个对象
- * @return
- */
- public boolean deleteObject(final Collection collection)
- {
- return redisTemplate.delete(collection) > 0;
- }
-
- /**
- * 缓存List数据
- *
- * @param key 缓存的键值
- * @param dataList 待缓存的List数据
- * @return 缓存的对象
- */
- public <T> long setCacheList(final String key, final List<T> dataList)
- {
- Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
- return count == null ? 0 : count;
- }
-
- /**
- * 获得缓存的list对象
- *
- * @param key 缓存的键值
- * @return 缓存键值对应的数据
- */
- public <T> List<T> getCacheList(final String key)
- {
- return redisTemplate.opsForList().range(key, 0, -1);
- }
-
- /**
- * 缓存Set
- *
- * @param key 缓存键值
- * @param dataSet 缓存的数据
- * @return 缓存数据的对象
- */
- public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
- {
- BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
- Iterator<T> it = dataSet.iterator();
- while (it.hasNext())
- {
- setOperation.add(it.next());
- }
- return setOperation;
- }
-
- /**
- * 获得缓存的set
- *
- * @param key
- * @return
- */
- public <T> Set<T> getCacheSet(final String key)
- {
- return redisTemplate.opsForSet().members(key);
- }
-
- /**
- * 缓存Map
- *
- * @param key
- * @param dataMap
- */
- public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
- {
- if (dataMap != null) {
- redisTemplate.opsForHash().putAll(key, dataMap);
- }
- }
-
- /**
- * 获得缓存的Map
- *
- * @param key
- * @return
- */
- public <T> Map<String, T> getCacheMap(final String key)
- {
- return redisTemplate.opsForHash().entries(key);
- }
-
- /**
- * 往Hash中存入数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @param value 值
- */
- public <T> void setCacheMapValue(final String key, final String hKey, final T value)
- {
- redisTemplate.opsForHash().put(key, hKey, value);
- }
-
- /**
- * 获取Hash中的数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @return Hash中的对象
- */
- public <T> T getCacheMapValue(final String key, final String hKey)
- {
- HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
- return opsForHash.get(key, hKey);
- }
-
- /**
- * 获取多个Hash中的数据
- *
- * @param key Redis键
- * @param hKeys Hash键集合
- * @return Hash对象集合
- */
- public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
- {
- return redisTemplate.opsForHash().multiGet(key, hKeys);
- }
-
- /**
- * 删除Hash中的某条数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @return 是否成功
- */
- public boolean deleteCacheMapValue(final String key, final String hKey)
- {
- return redisTemplate.opsForHash().delete(key, hKey) > 0;
- }
-
- /**
- * 获得缓存的基本对象列表
- *
- * @param pattern 字符串前缀
- * @return 对象列表
- */
- public Collection<String> keys(final String pattern)
- {
- return redisTemplate.keys(pattern);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/annotation/Sensitive.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/annotation/Sensitive.java
deleted file mode 100644
index 538d7f1..0000000
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/annotation/Sensitive.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.sensitive.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
-import com.ruoyi.common.sensitive.config.SensitiveJsonSerializer;
-import com.ruoyi.common.sensitive.enums.DesensitizedType;
-import tools.jackson.databind.annotation.JsonSerialize;
-
-/**
- * 数据脱敏注解
- *
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.FIELD, ElementType.METHOD })
-@JacksonAnnotationsInside
-@JsonSerialize(using = SensitiveJsonSerializer.class)
-public @interface Sensitive
-{
- DesensitizedType desensitizedType();
-}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/config/SensitiveJsonSerializer.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/config/SensitiveJsonSerializer.java
deleted file mode 100644
index 265f30e..0000000
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/config/SensitiveJsonSerializer.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.ruoyi.common.sensitive.config;
-
-import java.util.Objects;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.context.SecurityContextHolder;
-import com.ruoyi.common.sensitive.annotation.Sensitive;
-import com.ruoyi.common.sensitive.enums.DesensitizedType;
-import tools.jackson.core.JacksonException;
-import tools.jackson.core.JsonGenerator;
-import tools.jackson.databind.BeanProperty;
-import tools.jackson.databind.DatabindException;
-import tools.jackson.databind.SerializationContext;
-import tools.jackson.databind.ValueSerializer;
-import tools.jackson.databind.ser.std.StdSerializer;
-
-/**
- * 数据脱敏序列化过滤
- *
- * @author ruoyi
- */
-public class SensitiveJsonSerializer extends StdSerializer<String>
-{
- private final DesensitizedType desensitizedType;
-
- public SensitiveJsonSerializer()
- {
- super(String.class);
- this.desensitizedType = null;
- }
-
- public SensitiveJsonSerializer(DesensitizedType desensitizedType)
- {
- super(String.class);
- this.desensitizedType = desensitizedType;
- }
-
- @Override
- public void serialize(String value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException
- {
- if (desensitizedType != null && desensitization())
- {
- gen.writeString(desensitizedType.desensitizer().apply(value));
- }
- else
- {
- gen.writeString(value);
- }
- }
-
- @Override
- public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) throws DatabindException
- {
- Sensitive annotation = property.getAnnotation(Sensitive.class);
- if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
- {
- return new SensitiveJsonSerializer(annotation.desensitizedType());
- }
- return ctxt.findValueSerializer(property.getType());
- }
-
- /**
- * 是否需要脱敏处理
- */
- private boolean desensitization()
- {
- try
- {
- Long userId = SecurityContextHolder.getUserId();
- // 管理员不脱敏
- return !UserConstants.isAdmin(userId);
- }
- catch (Exception e)
- {
- return true;
- }
- }
-}
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/enums/DesensitizedType.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/enums/DesensitizedType.java
deleted file mode 100644
index 9504b9d..0000000
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/enums/DesensitizedType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.ruoyi.common.sensitive.enums;
-
-import java.util.function.Function;
-import com.ruoyi.common.sensitive.utils.DesensitizedUtil;
-
-/**
- * 脱敏类型
- *
- * @author ruoyi
- */
-public enum DesensitizedType
-{
- /**
- * 姓名,第2位星号替换
- */
- USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
-
- /**
- * 密码,全部字符都用*代替
- */
- PASSWORD(DesensitizedUtil::password),
-
- /**
- * 身份证,中间10位星号替换
- */
- ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
-
- /**
- * 手机号,中间4位星号替换
- */
- PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
-
- /**
- * 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
- */
- EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
-
- /**
- * 银行卡号,保留最后4位,其他星号替换
- */
- BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
-
- /**
- * 车牌号码,包含普通车辆、新能源车辆
- */
- CAR_LICENSE(DesensitizedUtil::carLicense);
-
- private final Function<String, String> desensitizer;
-
- DesensitizedType(Function<String, String> desensitizer)
- {
- this.desensitizer = desensitizer;
- }
-
- public Function<String, String> desensitizer()
- {
- return desensitizer;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/utils/DesensitizedUtil.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/utils/DesensitizedUtil.java
deleted file mode 100644
index 9c542d6..0000000
--- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/com/ruoyi/common/sensitive/utils/DesensitizedUtil.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.ruoyi.common.sensitive.utils;
-
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 脱敏工具类
- *
- * @author ruoyi
- */
-public class DesensitizedUtil
-{
- /**
- * 密码的全部字符都用*代替,比如:******
- *
- * @param password 密码
- * @return 脱敏后的密码
- */
- public static String password(String password)
- {
- if (StringUtils.isBlank(password))
- {
- return StringUtils.EMPTY;
- }
- return StringUtils.repeat('*', password.length());
- }
-
- /**
- * 车牌中间用*代替,如果是错误的车牌,不处理
- *
- * @param carLicense 完整的车牌号
- * @return 脱敏后的车牌
- */
- public static String carLicense(String carLicense)
- {
- if (StringUtils.isBlank(carLicense))
- {
- return StringUtils.EMPTY;
- }
- // 普通车牌
- if (carLicense.length() == 7)
- {
- carLicense = StringUtils.hide(carLicense, 3, 6);
- }
- else if (carLicense.length() == 8)
- {
- // 新能源车牌
- carLicense = StringUtils.hide(carLicense, 3, 7);
- }
- return carLicense;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SpringDocAutoConfiguration.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SpringDocAutoConfiguration.java
deleted file mode 100644
index 77b6ee6..0000000
--- a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/SpringDocAutoConfiguration.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.ruoyi.common.swagger.config;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import com.ruoyi.common.swagger.config.properties.SpringDocProperties;
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-
-/**
- * Swagger 文档配置
- *
- * @author ruoyi
- */
-@EnableConfigurationProperties(SpringDocProperties.class)
-@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
-public class SpringDocAutoConfiguration
-{
- @Bean
- @ConditionalOnMissingBean(OpenAPI.class)
- public OpenAPI openApi(SpringDocProperties properties)
- {
- return new OpenAPI().components(new Components()
- // 设置认证的请求头
- .addSecuritySchemes("apikey", securityScheme()))
- .addSecurityItem(new SecurityRequirement().addList("apikey"))
- .info(convertInfo(properties.getInfo()))
- .servers(servers(properties.getGatewayUrl()));
- }
-
- public SecurityScheme securityScheme()
- {
- return new SecurityScheme().type(SecurityScheme.Type.APIKEY)
- .name("Authorization")
- .in(SecurityScheme.In.HEADER)
- .scheme("Bearer");
- }
-
- private Info convertInfo(SpringDocProperties.InfoProperties infoProperties)
- {
- Info info = new Info();
- info.setTitle(infoProperties.getTitle());
- info.setDescription(infoProperties.getDescription());
- info.setContact(infoProperties.getContact());
- info.setLicense(infoProperties.getLicense());
- info.setVersion(infoProperties.getVersion());
- return info;
- }
-
- public List<Server> servers(String gatewayUrl)
- {
- List<Server> serverList = new ArrayList<>();
- serverList.add(new Server().url(gatewayUrl));
- return serverList;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/properties/SpringDocProperties.java b/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/properties/SpringDocProperties.java
deleted file mode 100644
index fb892c2..0000000
--- a/ruoyi-common/ruoyi-common-swagger/src/main/java/com/ruoyi/common/swagger/config/properties/SpringDocProperties.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.ruoyi.common.swagger.config.properties;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
-import io.swagger.v3.oas.models.info.Contact;
-import io.swagger.v3.oas.models.info.License;
-
-/**
- * Swagger 配置属性
- *
- * @author ruoyi
- */
-@ConfigurationProperties(prefix = "springdoc")
-public class SpringDocProperties
-{
- /**
- * 网关
- */
- private String gatewayUrl;
-
- /**
- * 文档基本信息
- */
- @NestedConfigurationProperty
- private InfoProperties info = new InfoProperties();
-
- /**
- * <p>
- * 文档的基础属性信息
- * </p>
- *
- * @see io.swagger.v3.oas.models.info.Info
- *
- * 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来
- */
- public static class InfoProperties
- {
- /**
- * 标题
- */
- private String title = null;
-
- /**
- * 描述
- */
- private String description = null;
-
- /**
- * 联系人信息
- */
- @NestedConfigurationProperty
- private Contact contact = null;
-
- /**
- * 许可证
- */
- @NestedConfigurationProperty
- private License license = null;
-
- /**
- * 版本
- */
- private String version = null;
-
- public String getTitle()
- {
- return title;
- }
-
- public void setTitle(String title)
- {
- this.title = title;
- }
-
- public String getDescription()
- {
- return description;
- }
-
- public void setDescription(String description)
- {
- this.description = description;
- }
-
- public Contact getContact()
- {
- return contact;
- }
-
- public void setContact(Contact contact)
- {
- this.contact = contact;
- }
-
- public License getLicense()
- {
- return license;
- }
-
- public void setLicense(License license)
- {
- this.license = license;
- }
-
- public String getVersion()
- {
- return version;
- }
-
- public void setVersion(String version)
- {
- this.version = version;
- }
- }
-
- public String getGatewayUrl()
- {
- return gatewayUrl;
- }
-
- public void setGatewayUrl(String gatewayUrl)
- {
- this.gatewayUrl = gatewayUrl;
- }
-
- public InfoProperties getInfo()
- {
- return info;
- }
-
- public void setInfo(InfoProperties info)
- {
- this.info = info;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java
deleted file mode 100644
index bddc438..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.gateway;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
-
-/**
- * 网关启动程序
- *
- * @author ruoyi
- */
-@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
-public class RuoYiGatewayApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiGatewayApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 若依网关启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java
deleted file mode 100644
index 963425e..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.ruoyi.gateway.config;
-
-import java.util.Properties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import com.google.code.kaptcha.impl.DefaultKaptcha;
-import com.google.code.kaptcha.util.Config;
-import static com.google.code.kaptcha.Constants.*;
-
-/**
- * 验证码配置
- *
- * @author ruoyi
- */
-@Configuration
-public class CaptchaConfig
-{
- @Bean(name = "captchaProducer")
- public DefaultKaptcha getKaptchaBean()
- {
- DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
- Properties properties = new Properties();
- // 是否有边框 默认为true 我们可以自己设置yes,no
- properties.setProperty(KAPTCHA_BORDER, "yes");
- // 验证码文本字符颜色 默认为Color.BLACK
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
- // 验证码图片宽度 默认为200
- properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
- // 验证码图片高度 默认为50
- properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
- // 验证码文本字符大小 默认为40
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
- // KAPTCHA_SESSION_KEY
- properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
- // 验证码文本字符长度 默认为5
- properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
- // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
- // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
- properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
- Config config = new Config(properties);
- defaultKaptcha.setConfig(config);
- return defaultKaptcha;
- }
-
- @Bean(name = "captchaProducerMath")
- public DefaultKaptcha getKaptchaBeanMath()
- {
- DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
- Properties properties = new Properties();
- // 是否有边框 默认为true 我们可以自己设置yes,no
- properties.setProperty(KAPTCHA_BORDER, "yes");
- // 边框颜色 默认为Color.BLACK
- properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
- // 验证码文本字符颜色 默认为Color.BLACK
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
- // 验证码图片宽度 默认为200
- properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
- // 验证码图片高度 默认为50
- properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
- // 验证码文本字符大小 默认为40
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
- // KAPTCHA_SESSION_KEY
- properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
- // 验证码文本生成器
- properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
- // 验证码文本字符间距 默认为2
- properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
- // 验证码文本字符长度 默认为5
- properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
- // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
- properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
- // 验证码噪点颜色 默认为Color.BLACK
- properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
- // 干扰实现类
- properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
- // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
- properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
- Config config = new Config(properties);
- defaultKaptcha.setConfig(config);
- return defaultKaptcha;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java
deleted file mode 100644
index 8d0fee4..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.ruoyi.gateway.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.Ordered;
-import org.springframework.core.annotation.Order;
-import com.ruoyi.gateway.handler.SentinelFallbackHandler;
-
-/**
- * 网关限流配置
- *
- * @author ruoyi
- */
-@Configuration
-public class GatewayConfig
-{
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- public SentinelFallbackHandler sentinelGatewayExceptionHandler()
- {
- return new SentinelFallbackHandler();
- }
-}
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java
deleted file mode 100644
index ea65aef..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.ruoyi.gateway.config;
-
-import java.util.Random;
-import com.google.code.kaptcha.text.impl.DefaultTextCreator;
-
-/**
- * 验证码文本生成器
- *
- * @author ruoyi
- */
-public class KaptchaTextCreator extends DefaultTextCreator
-{
- private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
-
- @Override
- public String getText()
- {
- Integer result = 0;
- Random random = new Random();
- int x = random.nextInt(10);
- int y = random.nextInt(10);
- StringBuilder suChinese = new StringBuilder();
- int randomoperands = random.nextInt(3);
- if (randomoperands == 0)
- {
- result = x * y;
- suChinese.append(CNUMBERS[x]);
- suChinese.append("*");
- suChinese.append(CNUMBERS[y]);
- }
- else if (randomoperands == 1)
- {
- if ((x != 0) && y % x == 0)
- {
- result = y / x;
- suChinese.append(CNUMBERS[y]);
- suChinese.append("/");
- suChinese.append(CNUMBERS[x]);
- }
- else
- {
- result = x + y;
- suChinese.append(CNUMBERS[x]);
- suChinese.append("+");
- suChinese.append(CNUMBERS[y]);
- }
- }
- else if (randomoperands == 2)
- {
- if (x >= y)
- {
- result = x - y;
- suChinese.append(CNUMBERS[x]);
- suChinese.append("-");
- suChinese.append(CNUMBERS[y]);
- }
- else
- {
- result = y - x;
- suChinese.append(CNUMBERS[y]);
- suChinese.append("-");
- suChinese.append(CNUMBERS[x]);
- }
- }
- else
- {
- result = x + y;
- suChinese.append(CNUMBERS[x]);
- suChinese.append("+");
- suChinese.append(CNUMBERS[y]);
- }
- suChinese.append("=?@" + result);
- return suChinese.toString();
- }
-}
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java
deleted file mode 100644
index 7e4cdf2..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.ruoyi.gateway.config;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.MediaType;
-import org.springframework.web.reactive.function.server.RequestPredicates;
-import org.springframework.web.reactive.function.server.RouterFunction;
-import org.springframework.web.reactive.function.server.RouterFunctions;
-import com.ruoyi.gateway.handler.ValidateCodeHandler;
-
-/**
- * 路由配置信息
- *
- * @author ruoyi
- */
-@Configuration
-public class RouterFunctionConfiguration
-{
- @Autowired
- private ValidateCodeHandler validateCodeHandler;
-
- @SuppressWarnings("rawtypes")
- @Bean
- public RouterFunction routerFunction()
- {
- return RouterFunctions.route(
- RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
- validateCodeHandler);
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SpringDocConfig.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SpringDocConfig.java
deleted file mode 100644
index 65ccbe9..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SpringDocConfig.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.ruoyi.gateway.config;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.springdoc.core.properties.AbstractSwaggerUiConfigProperties;
-import org.springdoc.core.properties.SwaggerUiConfigProperties;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.cloud.client.discovery.DiscoveryClient;
-import org.springframework.context.annotation.Configuration;
-import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
-import com.alibaba.nacos.common.notify.Event;
-import com.alibaba.nacos.common.notify.NotifyCenter;
-import com.alibaba.nacos.common.notify.listener.Subscriber;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * SpringDoc配置类
- *
- * @author ruoyi
- */
-@Configuration(proxyBeanMethods = false)
-@ConditionalOnProperty(value = "springdoc.api-docs.enabled", matchIfMissing = true)
-public class SpringDocConfig implements InitializingBean
-{
- @Autowired
- private SwaggerUiConfigProperties swaggerUiConfigProperties;
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- /**
- * 在初始化后调用的方法
- */
- @Override
- public void afterPropertiesSet()
- {
- NotifyCenter.registerSubscriber(new SwaggerDocRegister(swaggerUiConfigProperties, discoveryClient));
- }
-}
-
-/**
- * Swagger文档注册器
- */
-class SwaggerDocRegister extends Subscriber<InstancesChangeEvent>
-{
- @Autowired
- private SwaggerUiConfigProperties swaggerUiConfigProperties;
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- private final static String[] EXCLUDE_ROUTES = new String[] { "ruoyi-gateway", "ruoyi-auth", "ruoyi-file", "ruoyi-monitor" };
-
- public SwaggerDocRegister(SwaggerUiConfigProperties swaggerUiConfigProperties, DiscoveryClient discoveryClient)
- {
- this.swaggerUiConfigProperties = swaggerUiConfigProperties;
- this.discoveryClient = discoveryClient;
- }
-
- /**
- * 事件回调方法,处理InstancesChangeEvent事件
- * @param event 事件对象
- */
- @Override
- public void onEvent(InstancesChangeEvent event)
- {
- Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrlSet = discoveryClient.getServices()
- .stream()
- .flatMap(serviceId -> discoveryClient.getInstances(serviceId).stream())
- .filter(instance -> !StringUtils.equalsAnyIgnoreCase(instance.getServiceId(), EXCLUDE_ROUTES))
- .map(instance -> {
- AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
- swaggerUrl.setName(instance.getServiceId());
- swaggerUrl.setUrl(String.format("/%s/v3/api-docs", instance.getServiceId()));
- return swaggerUrl;
- })
- .collect(Collectors.toSet());
-
- swaggerUiConfigProperties.setUrls(swaggerUrlSet);
- }
-
- /**
- * 订阅类型方法,返回订阅的事件类型
- * @return 订阅的事件类型
- */
- @Override
- public Class<? extends Event> subscribeType()
- {
- return InstancesChangeEvent.class;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java
deleted file mode 100644
index dea2e16..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.gateway.config.properties;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * 验证码配置
- *
- * @author ruoyi
- */
-@Configuration
-@RefreshScope
-@ConfigurationProperties(prefix = "security.captcha")
-public class CaptchaProperties
-{
- /**
- * 验证码开关
- */
- private Boolean enabled;
-
- /**
- * 验证码类型(math 数组计算 char 字符)
- */
- private String type;
-
- public Boolean getEnabled()
- {
- return enabled;
- }
-
- public void setEnabled(Boolean enabled)
- {
- this.enabled = enabled;
- }
-
- public String getType()
- {
- return type;
- }
-
- public void setType(String type)
- {
- this.type = type;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java
deleted file mode 100644
index 7df1171..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.gateway.config.properties;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * 放行白名单配置
- *
- * @author ruoyi
- */
-@Configuration
-@RefreshScope
-@ConfigurationProperties(prefix = "security.ignore")
-public class IgnoreWhiteProperties
-{
- /**
- * 放行白名单配置,网关不校验此处的白名单
- */
- private List<String> whites = new ArrayList<>();
-
- public List<String> getWhites()
- {
- return whites;
- }
-
- public void setWhites(List<String> whites)
- {
- this.whites = whites;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java
deleted file mode 100644
index 834188b..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.ruoyi.gateway.config.properties;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * XSS跨站脚本配置
- *
- * @author ruoyi
- */
-@Configuration
-@RefreshScope
-@ConfigurationProperties(prefix = "security.xss")
-public class XssProperties
-{
- /**
- * Xss开关
- */
- private Boolean enabled;
-
- /**
- * 排除路径
- */
- private List<String> excludeUrls = new ArrayList<>();
-
- public Boolean getEnabled()
- {
- return enabled;
- }
-
- public void setEnabled(Boolean enabled)
- {
- this.enabled = enabled;
- }
-
- public List<String> getExcludeUrls()
- {
- return excludeUrls;
- }
-
- public void setExcludeUrls(List<String> excludeUrls)
- {
- this.excludeUrls = excludeUrls;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
deleted file mode 100644
index 51d39ef..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.ruoyi.gateway.filter;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.gateway.filter.GatewayFilterChain;
-import org.springframework.cloud.gateway.filter.GlobalFilter;
-import org.springframework.core.Ordered;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.stereotype.Component;
-import org.springframework.web.server.ServerWebExchange;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.HttpStatus;
-import com.ruoyi.common.core.constant.SecurityConstants;
-import com.ruoyi.common.core.constant.TokenConstants;
-import com.ruoyi.common.core.utils.JwtUtils;
-import com.ruoyi.common.core.utils.ServletUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.gateway.config.properties.IgnoreWhiteProperties;
-import io.jsonwebtoken.Claims;
-import reactor.core.publisher.Mono;
-
-/**
- * 网关鉴权
- *
- * @author ruoyi
- */
-@Component
-public class AuthFilter implements GlobalFilter, Ordered
-{
- private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
-
- // 排除过滤的 uri 地址,nacos自行添加
- @Autowired
- private IgnoreWhiteProperties ignoreWhite;
-
- @Autowired
- private RedisService redisService;
-
-
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
- {
- ServerHttpRequest request = exchange.getRequest();
- ServerHttpRequest.Builder mutate = request.mutate();
-
- String url = request.getURI().getPath();
- // 跳过不需要验证的路径
- if (StringUtils.matches(url, ignoreWhite.getWhites()))
- {
- return chain.filter(exchange);
- }
- String token = getToken(request);
- if (StringUtils.isEmpty(token))
- {
- return unauthorizedResponse(exchange, "令牌不能为空");
- }
- Claims claims = JwtUtils.parseToken(token);
- if (claims == null)
- {
- return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
- }
- String userkey = JwtUtils.getUserKey(claims);
- boolean islogin = redisService.hasKey(getTokenKey(userkey));
- if (!islogin)
- {
- return unauthorizedResponse(exchange, "登录状态已过期");
- }
- String userid = JwtUtils.getUserId(claims);
- String username = JwtUtils.getUserName(claims);
- if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))
- {
- return unauthorizedResponse(exchange, "令牌验证失败");
- }
-
- // 设置用户信息到请求
- addHeader(mutate, SecurityConstants.USER_KEY, userkey);
- addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
- addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
- // 内部请求来源参数清除
- removeHeader(mutate, SecurityConstants.FROM_SOURCE);
- return chain.filter(exchange.mutate().request(mutate.build()).build());
- }
-
- private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
- {
- if (value == null)
- {
- return;
- }
- String valueStr = value.toString();
- String valueEncode = ServletUtils.urlEncode(valueStr);
- mutate.header(name, valueEncode);
- }
-
- private void removeHeader(ServerHttpRequest.Builder mutate, String name)
- {
- mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
- }
-
- private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
- {
- log.error("[鉴权异常处理]请求路径:{},错误信息:{}", exchange.getRequest().getPath(), msg);
- return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
- }
-
- /**
- * 获取缓存key
- */
- private String getTokenKey(String token)
- {
- return CacheConstants.LOGIN_TOKEN_KEY + token;
- }
-
- /**
- * 获取请求token
- */
- private String getToken(ServerHttpRequest request)
- {
- String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_HEADER);
- // 如果前端设置了令牌前缀,则裁剪掉前缀
- if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
- {
- token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
- }
- return token;
- }
-
- @Override
- public int getOrder()
- {
- return -200;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java
deleted file mode 100644
index ec7801b..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.gateway.filter;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-import org.springframework.cloud.gateway.filter.GatewayFilter;
-import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.utils.ServletUtils;
-
-/**
- * 黑名单过滤器
- *
- * @author ruoyi
- */
-@Component
-public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config>
-{
- @Override
- public GatewayFilter apply(Config config)
- {
- return (exchange, chain) -> {
-
- String url = exchange.getRequest().getURI().getPath();
- if (config.matchBlacklist(url))
- {
- return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
- }
-
- return chain.filter(exchange);
- };
- }
-
- public BlackListUrlFilter()
- {
- super(Config.class);
- }
-
- public static class Config
- {
- private List<String> blacklistUrl;
-
- private List<Pattern> blacklistUrlPattern = new ArrayList<>();
-
- public boolean matchBlacklist(String url)
- {
- return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
- }
-
- public List<String> getBlacklistUrl()
- {
- return blacklistUrl;
- }
-
- public void setBlacklistUrl(List<String> blacklistUrl)
- {
- this.blacklistUrl = blacklistUrl;
- this.blacklistUrlPattern.clear();
- this.blacklistUrl.forEach(url -> {
- this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
- });
- }
- }
-
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java
deleted file mode 100644
index 22de0d3..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.ruoyi.gateway.filter;
-
-import java.nio.CharBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.atomic.AtomicReference;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cloud.gateway.filter.GatewayFilter;
-import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.core.io.buffer.DataBufferUtils;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.stereotype.Component;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.core.utils.ServletUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.gateway.config.properties.CaptchaProperties;
-import com.ruoyi.gateway.service.ValidateCodeService;
-import reactor.core.publisher.Flux;
-
-/**
- * 验证码过滤器
- *
- * @author ruoyi
- */
-@Component
-public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
-{
- private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" };
-
- @Autowired
- private ValidateCodeService validateCodeService;
-
- @Autowired
- private CaptchaProperties captchaProperties;
-
- private static final String CODE = "code";
-
- private static final String UUID = "uuid";
-
- @Override
- public GatewayFilter apply(Object config)
- {
- return (exchange, chain) -> {
- ServerHttpRequest request = exchange.getRequest();
-
- // 非登录/注册请求或验证码关闭,不处理
- if (!StringUtils.equalsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled())
- {
- return chain.filter(exchange);
- }
-
- try
- {
- String rspStr = resolveBodyFromRequest(request);
- JSONObject obj = JSON.parseObject(rspStr);
- validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
- }
- catch (Exception e)
- {
- return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
- }
- return chain.filter(exchange);
- };
- }
-
- @SuppressWarnings("deprecation")
- private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
- {
- // 获取请求体
- Flux<DataBuffer> body = serverHttpRequest.getBody();
- AtomicReference<String> bodyRef = new AtomicReference<>();
- body.subscribe(buffer -> {
- CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
- DataBufferUtils.release(buffer);
- bodyRef.set(charBuffer.toString());
- });
- return bodyRef.get();
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java
deleted file mode 100644
index a82ee84..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.ruoyi.gateway.filter;
-
-import java.nio.charset.StandardCharsets;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.cloud.gateway.filter.GatewayFilterChain;
-import org.springframework.cloud.gateway.filter.GlobalFilter;
-import org.springframework.core.Ordered;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.core.io.buffer.DataBufferFactory;
-import org.springframework.core.io.buffer.DataBufferUtils;
-import org.springframework.core.io.buffer.DefaultDataBufferFactory;
-import org.springframework.core.io.buffer.NettyDataBufferFactory;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
-import org.springframework.stereotype.Component;
-import org.springframework.web.server.ServerWebExchange;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.html.EscapeUtil;
-import com.ruoyi.gateway.config.properties.XssProperties;
-import io.netty.buffer.ByteBufAllocator;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-/**
- * 跨站脚本过滤器
- *
- * @author ruoyi
- */
-@Component
-@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true")
-public class XssFilter implements GlobalFilter, Ordered
-{
- // 跨站脚本的 xss 配置,nacos自行添加
- @Autowired
- private XssProperties xss;
-
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
- {
- ServerHttpRequest request = exchange.getRequest();
- // xss开关未开启 或 通过nacos关闭,不过滤
- if (!xss.getEnabled())
- {
- return chain.filter(exchange);
- }
- // GET DELETE 不过滤
- HttpMethod method = request.getMethod();
- if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
- {
- return chain.filter(exchange);
- }
- // 非json类型,不过滤
- if (!isJsonRequest(exchange))
- {
- return chain.filter(exchange);
- }
- // excludeUrls 不过滤
- String url = request.getURI().getPath();
- if (StringUtils.matches(url, xss.getExcludeUrls()))
- {
- return chain.filter(exchange);
- }
- ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
- return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
-
- }
-
- private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange)
- {
- ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest())
- {
- @Override
- public Flux<DataBuffer> getBody()
- {
- Flux<DataBuffer> body = super.getBody();
- return body.buffer().map(dataBuffers -> {
- DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
- DataBuffer join = dataBufferFactory.join(dataBuffers);
- byte[] content = new byte[join.readableByteCount()];
- join.read(content);
- DataBufferUtils.release(join);
- String bodyStr = new String(content, StandardCharsets.UTF_8);
- // 防xss攻击过滤
- bodyStr = EscapeUtil.clean(bodyStr);
- // 转成字节
- byte[] bytes = bodyStr.getBytes(StandardCharsets.UTF_8);
- NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
- DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
- buffer.write(bytes);
- return buffer;
- });
- }
-
- @Override
- public HttpHeaders getHeaders()
- {
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.putAll(super.getHeaders());
- // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
- httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
- httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
- return httpHeaders;
- }
-
- };
- return serverHttpRequestDecorator;
- }
-
- /**
- * 是否是Json请求
- *
- * @param exchange HTTP请求
- */
- public boolean isJsonRequest(ServerWebExchange exchange)
- {
- String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
- return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
- }
-
- @Override
- public int getOrder()
- {
- return -100;
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java
deleted file mode 100644
index eaf38d9..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.ruoyi.gateway.handler;
-
-import org.springframework.cloud.gateway.support.NotFoundException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.web.server.ResponseStatusException;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.WebExceptionHandler;
-import com.ruoyi.common.core.utils.ServletUtils;
-import reactor.core.publisher.Mono;
-
-/**
- * 网关统一异常处理
- *
- * @author ruoyi
- */
-@Order(-1)
-@Configuration
-public class GatewayExceptionHandler implements WebExceptionHandler
-{
- private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
-
- @Override
- public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
- {
- ServerHttpResponse response = exchange.getResponse();
-
- if (exchange.getResponse().isCommitted())
- {
- return Mono.error(ex);
- }
-
- String msg;
-
- if (ex instanceof NotFoundException)
- {
- msg = "服务未找到";
- }
- else if (ex instanceof ResponseStatusException)
- {
- ResponseStatusException responseStatusException = (ResponseStatusException) ex;
- msg = responseStatusException.getMessage();
- }
- else
- {
- msg = "内部服务器错误";
- }
-
- log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
-
- return ServletUtils.webFluxResponseWriter(response, msg);
- }
-}
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java
deleted file mode 100644
index 1b496e2..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.gateway.handler;
-
-import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
-import com.alibaba.csp.sentinel.slots.block.BlockException;
-import com.ruoyi.common.core.utils.ServletUtils;
-import org.springframework.web.reactive.function.server.ServerResponse;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.WebExceptionHandler;
-import reactor.core.publisher.Mono;
-
-/**
- * 自定义限流异常处理
- *
- * @author ruoyi
- */
-public class SentinelFallbackHandler implements WebExceptionHandler
-{
- private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
- {
- return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
- }
-
- @Override
- public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
- {
- if (exchange.getResponse().isCommitted())
- {
- return Mono.error(ex);
- }
- if (!BlockException.isBlockException(ex))
- {
- return Mono.error(ex);
- }
- return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
- }
-
- private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable)
- {
- return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java
deleted file mode 100644
index ef197de..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.ruoyi.gateway.handler;
-
-import java.io.IOException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.server.HandlerFunction;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.reactive.function.server.ServerResponse;
-import com.ruoyi.common.core.exception.CaptchaException;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.gateway.service.ValidateCodeService;
-import reactor.core.publisher.Mono;
-
-/**
- * 验证码获取
- *
- * @author ruoyi
- */
-@Component
-public class ValidateCodeHandler implements HandlerFunction<ServerResponse>
-{
- @Autowired
- private ValidateCodeService validateCodeService;
-
- @Override
- public Mono<ServerResponse> handle(ServerRequest serverRequest)
- {
- AjaxResult ajax;
- try
- {
- ajax = validateCodeService.createCaptcha();
- }
- catch (CaptchaException | IOException e)
- {
- return Mono.error(e);
- }
- return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
- }
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java
deleted file mode 100644
index 615fb07..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.ruoyi.gateway.service;
-
-import java.io.IOException;
-import com.ruoyi.common.core.exception.CaptchaException;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-
-/**
- * 验证码处理
- *
- * @author ruoyi
- */
-public interface ValidateCodeService
-{
- /**
- * 生成验证码
- */
- public AjaxResult createCaptcha() throws IOException, CaptchaException;
-
- /**
- * 校验验证码
- */
- public void checkCaptcha(String key, String value) throws CaptchaException;
-}
diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java
deleted file mode 100644
index bee0a3f..0000000
--- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.ruoyi.gateway.service.impl;
-
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import jakarta.annotation.Resource;
-import javax.imageio.ImageIO;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.FastByteArrayOutputStream;
-import com.google.code.kaptcha.Producer;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.exception.CaptchaException;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.sign.Base64;
-import com.ruoyi.common.core.utils.uuid.IdUtils;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.gateway.config.properties.CaptchaProperties;
-import com.ruoyi.gateway.service.ValidateCodeService;
-
-/**
- * 验证码实现处理
- *
- * @author ruoyi
- */
-@Service
-public class ValidateCodeServiceImpl implements ValidateCodeService
-{
- @Resource(name = "captchaProducer")
- private Producer captchaProducer;
-
- @Resource(name = "captchaProducerMath")
- private Producer captchaProducerMath;
-
- @Autowired
- private RedisService redisService;
-
- @Autowired
- private CaptchaProperties captchaProperties;
-
- /**
- * 生成验证码
- */
- @Override
- public AjaxResult createCaptcha() throws IOException, CaptchaException
- {
- AjaxResult ajax = AjaxResult.success();
- boolean captchaEnabled = captchaProperties.getEnabled();
- ajax.put("captchaEnabled", captchaEnabled);
- if (!captchaEnabled)
- {
- return ajax;
- }
-
- // 保存验证码信息
- String uuid = IdUtils.simpleUUID();
- String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
-
- String capStr = null, code = null;
- BufferedImage image = null;
-
- String captchaType = captchaProperties.getType();
- // 生成验证码
- if ("math".equals(captchaType))
- {
- String capText = captchaProducerMath.createText();
- capStr = capText.substring(0, capText.lastIndexOf("@"));
- code = capText.substring(capText.lastIndexOf("@") + 1);
- image = captchaProducerMath.createImage(capStr);
- }
- else if ("char".equals(captchaType))
- {
- capStr = code = captchaProducer.createText();
- image = captchaProducer.createImage(capStr);
- }
-
- redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
- // 转换流信息写出
- FastByteArrayOutputStream os = new FastByteArrayOutputStream();
- try
- {
- ImageIO.write(image, "jpg", os);
- }
- catch (IOException e)
- {
- return AjaxResult.error(e.getMessage());
- }
-
- ajax.put("uuid", uuid);
- ajax.put("img", Base64.encode(os.toByteArray()));
- return ajax;
- }
-
- /**
- * 校验验证码
- */
- @Override
- public void checkCaptcha(String code, String uuid) throws CaptchaException
- {
- if (StringUtils.isEmpty(code))
- {
- throw new CaptchaException("验证码不能为空");
- }
- String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
- String captcha = redisService.getCacheObject(verifyKey);
- if (captcha == null)
- {
- throw new CaptchaException("验证码已失效");
- }
- redisService.deleteObject(verifyKey);
- if (!code.equalsIgnoreCase(captcha))
- {
- throw new CaptchaException("验证码错误");
- }
- }
-}
diff --git a/ruoyi-gateway/src/main/resources/banner.txt b/ruoyi-gateway/src/main/resources/banner.txt
deleted file mode 100644
index fc8e118..0000000
--- a/ruoyi-gateway/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _ _
- (_) | |
- _ __ _ _ ___ _ _ _ ______ __ _ __ _ | |_ ___ __ __ __ _ _ _
-| '__|| | | | / _ \ | | | || ||______| / _` | / _` || __| / _ \\ \ /\ / / / _` || | | |
-| | | |_| || (_) || |_| || | | (_| || (_| || |_ | __/ \ V V / | (_| || |_| |
-|_| \__,_| \___/ \__, ||_| \__, | \__,_| \__| \___| \_/\_/ \__,_| \__, |
- __/ | __/ | __/ |
- |___/ |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java
deleted file mode 100644
index 07b7dc4..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/RuoYiFileApplication.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.file;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
-
-/**
- * 文件服务
- *
- * @author ruoyi
- */
-@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
-public class RuoYiFileApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiFileApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 文件服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java
deleted file mode 100644
index 27c7997..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/FilterConfig.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.file.config;
-
-import java.util.HashMap;
-import java.util.Map;
-import jakarta.servlet.DispatcherType;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import com.ruoyi.file.filter.RefererFilter;
-
-/**
- * Filter配置
- *
- * @author ruoyi
- */
-@Configuration
-public class FilterConfig
-{
- /**
- * 资源映射路径 前缀
- */
- @Value("${file.prefix}")
- public String localFilePrefix;
-
- @Value("${referer.allowed-domains}")
- private String allowedDomains;
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Bean
- @ConditionalOnProperty(value = "referer.enabled", havingValue = "true")
- public FilterRegistrationBean refererFilterRegistration()
- {
- FilterRegistrationBean registration = new FilterRegistrationBean();
- registration.setDispatcherTypes(DispatcherType.REQUEST);
- registration.setFilter(new RefererFilter());
- registration.addUrlPatterns(localFilePrefix + "/*");
- registration.setName("refererFilter");
- registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
- Map<String, String> initParameters = new HashMap<String, String>();
- initParameters.put("allowedDomains", allowedDomains);
- registration.setInitParameters(initParameters);
- return registration;
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java
deleted file mode 100644
index ee3e14c..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/MinioConfig.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.ruoyi.file.config;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import io.minio.MinioClient;
-
-/**
- * Minio 配置信息
- *
- * @author ruoyi
- */
-@Configuration
-@ConfigurationProperties(prefix = "minio")
-public class MinioConfig
-{
- /**
- * 服务地址
- */
- private String url;
-
- /**
- * 用户名
- */
- private String accessKey;
-
- /**
- * 密码
- */
- private String secretKey;
-
- /**
- * 存储桶名称
- */
- private String bucketName;
-
- public String getUrl()
- {
- return url;
- }
-
- public void setUrl(String url)
- {
- this.url = url;
- }
-
- public String getAccessKey()
- {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey)
- {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey()
- {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey)
- {
- this.secretKey = secretKey;
- }
-
- public String getBucketName()
- {
- return bucketName;
- }
-
- public void setBucketName(String bucketName)
- {
- this.bucketName = bucketName;
- }
-
- @Bean
- public MinioClient getMinioClient()
- {
- return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java
deleted file mode 100644
index 3bca668..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/config/ResourcesConfig.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.ruoyi.file.config;
-
-import java.io.File;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-/**
- * 通用映射配置
- *
- * @author ruoyi
- */
-@Configuration
-public class ResourcesConfig implements WebMvcConfigurer
-{
- /**
- * 上传文件存储在本地的根路径
- */
- @Value("${file.path}")
- private String localFilePath;
-
- /**
- * 资源映射路径 前缀
- */
- @Value("${file.prefix}")
- public String localFilePrefix;
-
- @Override
- public void addResourceHandlers(ResourceHandlerRegistry registry)
- {
- /** 本地文件上传路径 */
- registry.addResourceHandler(localFilePrefix + "/**")
- .addResourceLocations("file:" + localFilePath + File.separator);
- }
-
- /**
- * 开启跨域
- */
- @Override
- public void addCorsMappings(CorsRegistry registry) {
- // 设置允许跨域的路由
- registry.addMapping(localFilePrefix + "/**")
- // 设置允许跨域请求的域名
- .allowedOrigins("*")
- // 设置允许的方法
- .allowedMethods("GET");
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java
deleted file mode 100644
index 82db19b..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/controller/SysFileController.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.ruoyi.file.controller;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.file.FileUtils;
-import com.ruoyi.file.service.ISysFileService;
-import com.ruoyi.system.api.domain.SysFile;
-
-/**
- * 文件请求处理
- *
- * @author ruoyi
- */
-@RestController
-public class SysFileController
-{
- private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
-
- @Autowired
- private ISysFileService sysFileService;
-
- /**
- * 文件上传请求
- */
- @PostMapping("upload")
- public R<SysFile> upload(MultipartFile file)
- {
- try
- {
- // 上传并返回访问地址
- String url = sysFileService.uploadFile(file);
- SysFile sysFile = new SysFile();
- sysFile.setName(FileUtils.getName(url));
- sysFile.setUrl(url);
- return R.ok(sysFile);
- }
- catch (Exception e)
- {
- log.error("上传文件失败", e);
- return R.fail(e.getMessage());
- }
- }
-
- /**
- * 文件删除请求
- */
- @DeleteMapping("delete")
- public R<Boolean> delete(String fileUrl)
- {
- try
- {
- if (!FileUtils.validateFilePath(fileUrl))
- {
- throw new Exception(StringUtils.format("资源文件({})非法,不允许删除。 ", fileUrl));
- }
- sysFileService.deleteFile(fileUrl);
- return R.ok();
- }
- catch (Exception e)
- {
- log.error("删除文件失败", e);
- return R.fail(e.getMessage());
- }
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java
deleted file mode 100644
index ea168f1..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/filter/RefererFilter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.ruoyi.file.filter;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import jakarta.servlet.Filter;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.FilterConfig;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.ServletResponse;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-/**
- * 防盗链过滤器
- *
- * @author ruoyi
- */
-public class RefererFilter implements Filter
-{
- /**
- * 允许的域名列表
- */
- public List<String> allowedDomains;
-
- @Override
- public void init(FilterConfig filterConfig) throws ServletException
- {
- String domains = filterConfig.getInitParameter("allowedDomains");
- this.allowedDomains = Arrays.asList(domains.split(","));
- }
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException
- {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpServletResponse resp = (HttpServletResponse) response;
-
- String referer = req.getHeader("Referer");
-
- // 如果Referer为空,拒绝访问
- if (referer == null || referer.isEmpty())
- {
- resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer header is required");
- return;
- }
-
- // 检查Referer是否在允许的域名列表中
- boolean allowed = false;
- for (String domain : allowedDomains)
- {
- if (referer.contains(domain))
- {
- allowed = true;
- break;
- }
- }
-
- // 根据检查结果决定是否放行
- if (allowed)
- {
- chain.doFilter(request, response);
- }
- else
- {
- resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer '" + referer + "' is not allowed");
- }
- }
-
- @Override
- public void destroy()
- {
-
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java
deleted file mode 100644
index d6119ef..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/ISysFileService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.file.service;
-
-import org.springframework.web.multipart.MultipartFile;
-
-/**
- * 文件上传接口
- *
- * @author ruoyi
- */
-public interface ISysFileService
-{
- /**
- * 文件上传接口
- *
- * @param file 上传的文件
- * @return 访问地址
- * @throws Exception
- */
- public String uploadFile(MultipartFile file) throws Exception;
-
- /**
- * 文件删除接口
- *
- * @param fileUrl 文件访问URL
- * @throws Exception
- */
- public void deleteFile(String fileUrl) throws Exception;
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java
deleted file mode 100644
index 56c6afd..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/LocalSysFileServiceImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.file.service;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Primary;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.file.FileUtils;
-import com.ruoyi.file.utils.FileUploadUtils;
-
-/**
- * 本地文件存储
- *
- * @author ruoyi
- */
-@Primary
-@Service
-public class LocalSysFileServiceImpl implements ISysFileService
-{
- /**
- * 资源映射路径 前缀
- */
- @Value("${file.prefix}")
- public String localFilePrefix;
-
- /**
- * 域名或本机访问地址
- */
- @Value("${file.domain}")
- public String domain;
-
- /**
- * 上传文件存储在本地的根路径
- */
- @Value("${file.path}")
- private String localFilePath;
-
- /**
- * 本地文件上传接口
- *
- * @param file 上传的文件
- * @return 访问地址
- * @throws Exception
- */
- @Override
- public String uploadFile(MultipartFile file) throws Exception
- {
- String name = FileUploadUtils.upload(localFilePath, file);
- String url = domain + localFilePrefix + name;
- return url;
- }
-
- /**
- * 本地文件删除接口
- *
- * @param fileUrl 文件访问URL
- * @throws Exception
- */
- @Override
- public void deleteFile(String fileUrl) throws Exception
- {
- String localFile = StringUtils.substringAfter(fileUrl, localFilePrefix);
- FileUtils.deleteFile(localFilePath + localFile);
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java
deleted file mode 100644
index 9afd291..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/service/MinioSysFileServiceImpl.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.ruoyi.file.service;
-
-import java.io.InputStream;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-import com.alibaba.nacos.common.utils.IoUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.file.config.MinioConfig;
-import com.ruoyi.file.utils.FileUploadUtils;
-import io.minio.MinioClient;
-import io.minio.PutObjectArgs;
-import io.minio.RemoveObjectArgs;
-
-/**
- * Minio 文件存储
- *
- * @author ruoyi
- */
-@Service
-public class MinioSysFileServiceImpl implements ISysFileService
-{
- @Autowired
- private MinioConfig minioConfig;
-
- @Autowired
- private MinioClient client;
-
- /**
- * Minio文件上传接口
- *
- * @param file 上传的文件
- * @return 访问地址
- * @throws Exception
- */
- @Override
- public String uploadFile(MultipartFile file) throws Exception
- {
- InputStream inputStream = null;
- try
- {
- String fileName = FileUploadUtils.extractFilename(file);
- inputStream = file.getInputStream();
- PutObjectArgs args = PutObjectArgs.builder()
- .bucket(minioConfig.getBucketName())
- .object(fileName)
- .stream(inputStream, file.getSize(), -1)
- .contentType(file.getContentType())
- .build();
- client.putObject(args);
- return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
- }
- catch (Exception e)
- {
- throw new RuntimeException("Minio Failed to upload file", e);
- }
- finally
- {
- IoUtils.closeQuietly(inputStream);
- }
- }
-
- /**
- * Minio文件删除接口
- *
- * @param fileUrl 文件访问URL
- * @throws Exception
- */
- @Override
- public void deleteFile(String fileUrl) throws Exception
- {
- try
- {
- String minioFile = StringUtils.substringAfter(fileUrl, minioConfig.getBucketName());
- client.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(minioFile).build());
- }
- catch (Exception e)
- {
- throw new RuntimeException("Minio Failed to delete file", e);
- }
- }
-}
diff --git a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java b/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java
deleted file mode 100644
index b53c3fa..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/java/com/ruoyi/file/utils/FileUploadUtils.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package com.ruoyi.file.utils;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.Objects;
-import org.apache.commons.io.FilenameUtils;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.exception.file.FileException;
-import com.ruoyi.common.core.exception.file.FileNameLengthLimitExceededException;
-import com.ruoyi.common.core.exception.file.FileSizeLimitExceededException;
-import com.ruoyi.common.core.exception.file.InvalidExtensionException;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.file.FileTypeUtils;
-import com.ruoyi.common.core.utils.file.MimeTypeUtils;
-import com.ruoyi.common.core.utils.uuid.Seq;
-
-/**
- * 文件上传工具类
- *
- * @author ruoyi
- */
-public class FileUploadUtils
-{
- /**
- * 默认大小 50M
- */
- public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
-
- /**
- * 默认的文件名最大长度 100
- */
- public static final int DEFAULT_FILE_NAME_LENGTH = 100;
-
- /**
- * 根据文件路径上传
- *
- * @param baseDir 相对应用的基目录
- * @param file 上传的文件
- * @return 文件名称
- * @throws IOException
- */
- public static final String upload(String baseDir, MultipartFile file) throws IOException
- {
- try
- {
- return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
- }
- catch (FileException fe)
- {
- throw new IOException(fe.getDefaultMessage(), fe);
- }
- catch (Exception e)
- {
- throw new IOException(e.getMessage(), e);
- }
- }
-
- /**
- * 文件上传
- *
- * @param baseDir 相对应用的基目录
- * @param file 上传的文件
- * @param allowedExtension 上传文件类型
- * @return 返回上传成功的文件名
- * @throws FileSizeLimitExceededException 如果超出最大大小
- * @throws FileNameLengthLimitExceededException 文件名太长
- * @throws IOException 比如读写文件出错时
- * @throws InvalidExtensionException 文件校验异常
- */
- public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
- throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
- InvalidExtensionException
- {
- int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
- if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
- {
- throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
- }
-
- assertAllowed(file, allowedExtension);
-
- String fileName = extractFilename(file);
-
- String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
- file.transferTo(Paths.get(absPath));
- return getPathFileName(fileName);
- }
-
- /**
- * 编码文件名
- */
- public static final String extractFilename(MultipartFile file)
- {
- return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
- FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file));
- }
-
- private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
- {
- File desc = new File(uploadDir + File.separator + fileName);
-
- if (!desc.exists())
- {
- if (!desc.getParentFile().exists())
- {
- desc.getParentFile().mkdirs();
- }
- }
- return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
- }
-
- private static final String getPathFileName(String fileName) throws IOException
- {
- String pathFileName = "/" + fileName;
- return pathFileName;
- }
-
- /**
- * 文件大小校验
- *
- * @param file 上传的文件
- * @throws FileSizeLimitExceededException 如果超出最大大小
- * @throws InvalidExtensionException 文件校验异常
- */
- public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
- throws FileSizeLimitExceededException, InvalidExtensionException
- {
- long size = file.getSize();
- if (size > DEFAULT_MAX_SIZE)
- {
- throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
- }
-
- String fileName = file.getOriginalFilename();
- String extension = FileTypeUtils.getExtension(file);
- if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
- {
- if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
- {
- throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
- fileName);
- }
- else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
- {
- throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
- fileName);
- }
- else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
- {
- throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
- fileName);
- }
- else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
- {
- throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
- fileName);
- }
- else
- {
- throw new InvalidExtensionException(allowedExtension, extension, fileName);
- }
- }
- }
-
- /**
- * 判断MIME类型是否是允许的MIME类型
- *
- * @param extension 上传文件类型
- * @param allowedExtension 允许上传文件类型
- * @return true/false
- */
- public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
- {
- for (String str : allowedExtension)
- {
- if (str.equalsIgnoreCase(extension))
- {
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt
deleted file mode 100644
index 12892dd..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _ __ _ _
- (_) / _|(_)| |
- _ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
-| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
-| | | |_| || (_) || |_| || | | | | || || __/
-|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
- __/ |
- |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml
deleted file mode 100644
index 9c38c7f..0000000
--- a/ruoyi-modules/ruoyi-file/src/main/resources/logback.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true" scanPeriod="60 seconds" debug="false">
- <!-- 日志存放路径 -->
- <property name="log.path" value="logs/ruoyi-file" />
- <!-- 日志输出格式 -->
- <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
-
- <!-- 控制台输出 -->
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- </appender>
-
- <!-- 系统日志输出 -->
- <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/info.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>INFO</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/error.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>ERROR</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 系统模块日志级别控制 -->
- <logger name="com.ruoyi" level="info" />
- <!-- Spring日志级别控制 -->
- <logger name="org.springframework" level="warn" />
-
- <root level="info">
- <appender-ref ref="console" />
- </root>
-
- <!--系统操作日志-->
- <root level="info">
- <appender-ref ref="file_info" />
- <appender-ref ref="file_error" />
- </root>
-</configuration>
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java
deleted file mode 100644
index 248ee76..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/RuoYiGenApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.ruoyi.gen;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import com.ruoyi.common.security.annotation.EnableCustomConfig;
-import com.ruoyi.common.security.annotation.EnableRyFeignClients;
-
-/**
- * 代码生成
- *
- * @author ruoyi
- */
-@EnableCustomConfig
-@EnableRyFeignClients
-@SpringBootApplication
-public class RuoYiGenApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiGenApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 代码生成模块启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java
deleted file mode 100644
index c365497..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/config/GenConfig.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.ruoyi.gen.config;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-/**
- * 代码生成相关配置
- *
- * @author ruoyi
- */
-@Component
-@ConfigurationProperties(prefix = "gen")
-public class GenConfig
-{
- /** 作者 */
- public static String author;
-
- /** 生成包路径 */
- public static String packageName;
-
- /** 自动去除表前缀 */
- public static boolean autoRemovePre;
-
- /** 表前缀 */
- public static String tablePrefix;
-
- /** 是否允许生成文件覆盖到本地(自定义路径) */
- public static boolean allowOverwrite;
-
- public static String getAuthor()
- {
- return author;
- }
-
- public void setAuthor(String author)
- {
- GenConfig.author = author;
- }
-
- public static String getPackageName()
- {
- return packageName;
- }
-
- public void setPackageName(String packageName)
- {
- GenConfig.packageName = packageName;
- }
-
- public static boolean getAutoRemovePre()
- {
- return autoRemovePre;
- }
-
- public void setAutoRemovePre(boolean autoRemovePre)
- {
- GenConfig.autoRemovePre = autoRemovePre;
- }
-
- public static String getTablePrefix()
- {
- return tablePrefix;
- }
-
- public void setTablePrefix(String tablePrefix)
- {
- GenConfig.tablePrefix = tablePrefix;
- }
-
- public static boolean isAllowOverwrite()
- {
- return allowOverwrite;
- }
-
- public void setAllowOverwrite(boolean allowOverwrite)
- {
- GenConfig.allowOverwrite = allowOverwrite;
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java
deleted file mode 100644
index 0bad3c8..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/controller/GenController.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package com.ruoyi.gen.controller;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.gen.config.GenConfig;
-import com.ruoyi.gen.domain.GenTable;
-import com.ruoyi.gen.domain.GenTableColumn;
-import com.ruoyi.gen.service.IGenTableColumnService;
-import com.ruoyi.gen.service.IGenTableService;
-
-/**
- * 代码生成 操作处理
- *
- * @author ruoyi
- */
-@RequestMapping("/gen")
-@RestController
-public class GenController extends BaseController
-{
- @Autowired
- private IGenTableService genTableService;
-
- @Autowired
- private IGenTableColumnService genTableColumnService;
-
- /**
- * 查询代码生成列表
- */
- @RequiresPermissions("tool:gen:list")
- @GetMapping("/list")
- public TableDataInfo genList(GenTable genTable)
- {
- startPage();
- List<GenTable> list = genTableService.selectGenTableList(genTable);
- return getDataTable(list);
- }
-
- /**
- * 获取代码生成信息
- */
- @RequiresPermissions("tool:gen:query")
- @GetMapping(value = "/{tableId}")
- public AjaxResult getInfo(@PathVariable Long tableId)
- {
- GenTable table = genTableService.selectGenTableById(tableId);
- List<GenTable> tables = genTableService.selectGenTableAll();
- List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("info", table);
- map.put("rows", list);
- map.put("tables", tables);
- return success(map);
- }
-
- /**
- * 查询数据库列表
- */
- @RequiresPermissions("tool:gen:list")
- @GetMapping("/db/list")
- public TableDataInfo dataList(GenTable genTable)
- {
- startPage();
- List<GenTable> list = genTableService.selectDbTableList(genTable);
- return getDataTable(list);
- }
-
- /**
- * 查询数据表字段列表
- */
- @GetMapping(value = "/column/{tableId}")
- public TableDataInfo columnList(Long tableId)
- {
- TableDataInfo dataInfo = new TableDataInfo();
- List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
- dataInfo.setRows(list);
- dataInfo.setTotal(list.size());
- return dataInfo;
- }
-
- /**
- * 导入表结构(保存)
- */
- @RequiresPermissions("tool:gen:import")
- @Log(title = "代码生成", businessType = BusinessType.IMPORT)
- @PostMapping("/importTable")
- public AjaxResult importTableSave(@RequestParam("tables") String tables, @RequestParam("tplWebType") String tplWebType)
- {
- String[] tableNames = Convert.toStrArray(tables);
- // 查询表信息
- List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
- genTableService.importGenTable(tableList, tplWebType);
- return success();
- }
-
- /**
- * 修改保存代码生成业务
- */
- @RequiresPermissions("tool:gen:edit")
- @Log(title = "代码生成", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
- {
- genTableService.validateEdit(genTable);
- genTableService.updateGenTable(genTable);
- return success();
- }
-
- /**
- * 删除代码生成
- */
- @RequiresPermissions("tool:gen:remove")
- @Log(title = "代码生成", businessType = BusinessType.DELETE)
- @DeleteMapping("/{tableIds}")
- public AjaxResult remove(@PathVariable Long[] tableIds)
- {
- genTableService.deleteGenTableByIds(tableIds);
- return success();
- }
-
- /**
- * 预览代码
- */
- @RequiresPermissions("tool:gen:preview")
- @GetMapping("/preview/{tableId}")
- public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
- {
- Map<String, String> dataMap = genTableService.previewCode(tableId);
- return success(dataMap);
- }
-
- /**
- * 生成代码(下载方式)
- */
- @RequiresPermissions("tool:gen:code")
- @Log(title = "代码生成", businessType = BusinessType.GENCODE)
- @GetMapping("/download/{tableName}")
- public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
- {
- byte[] data = genTableService.downloadCode(tableName);
- genCode(response, data);
- }
-
- /**
- * 生成代码(自定义路径)
- */
- @RequiresPermissions("tool:gen:code")
- @Log(title = "代码生成", businessType = BusinessType.GENCODE)
- @GetMapping("/genCode/{tableName}")
- public AjaxResult genCode(@PathVariable("tableName") String tableName)
- {
- if (!GenConfig.isAllowOverwrite())
- {
- return AjaxResult.error("【系统预设】不允许生成文件覆盖到本地");
- }
- genTableService.generatorCode(tableName);
- return success();
- }
-
- /**
- * 同步数据库
- */
- @RequiresPermissions("tool:gen:edit")
- @Log(title = "代码生成", businessType = BusinessType.UPDATE)
- @GetMapping("/synchDb/{tableName}")
- public AjaxResult synchDb(@PathVariable("tableName") String tableName)
- {
- genTableService.synchDb(tableName);
- return success();
- }
-
- /**
- * 批量生成代码
- */
- @RequiresPermissions("tool:gen:code")
- @Log(title = "代码生成", businessType = BusinessType.GENCODE)
- @GetMapping("/batchGenCode")
- public void batchGenCode(HttpServletResponse response, String tables) throws IOException
- {
- String[] tableNames = Convert.toStrArray(tables);
- byte[] data = genTableService.downloadCode(tableNames);
- genCode(response, data);
- }
-
- /**
- * 生成zip文件
- */
- private void genCode(HttpServletResponse response, byte[] data) throws IOException
- {
- response.reset();
- response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
- response.addHeader("Content-Length", "" + data.length);
- response.setContentType("application/octet-stream; charset=UTF-8");
- IOUtils.write(data, response.getOutputStream());
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java
deleted file mode 100644
index 1d46fc4..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java
+++ /dev/null
@@ -1,411 +0,0 @@
-package com.ruoyi.gen.domain;
-
-import java.util.List;
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotBlank;
-import org.apache.commons.lang3.ArrayUtils;
-import com.ruoyi.common.core.constant.GenConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 业务表 gen_table
- *
- * @author ruoyi
- */
-public class GenTable extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 编号 */
- private Long tableId;
-
- /** 表名称 */
- @NotBlank(message = "表名称不能为空")
- private String tableName;
-
- /** 表描述 */
- @NotBlank(message = "表描述不能为空")
- private String tableComment;
-
- /** 关联父表的表名 */
- private String subTableName;
-
- /** 本表关联父表的外键名 */
- private String subTableFkName;
-
- /** 实体类名称(首字母大写) */
- @NotBlank(message = "实体类名称不能为空")
- private String className;
-
- /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */
- private String tplCategory;
-
- /** 前端类型(element-ui模版 element-plus模版 element-plus-typescript模版) */
- private String tplWebType;
-
- /** 生成包路径 */
- @NotBlank(message = "生成包路径不能为空")
- private String packageName;
-
- /** 生成模块名 */
- @NotBlank(message = "生成模块名不能为空")
- private String moduleName;
-
- /** 生成业务名 */
- @NotBlank(message = "生成业务名不能为空")
- private String businessName;
-
- /** 生成功能名 */
- @NotBlank(message = "生成功能名不能为空")
- private String functionName;
-
- /** 生成作者 */
- @NotBlank(message = "作者不能为空")
- private String functionAuthor;
-
- /** 表单布局(单列 双列 三列) */
- private Integer formColNum;
-
- /** 生成代码方式(0zip压缩包 1自定义路径) */
- private String genType;
-
- /** 生成路径(不填默认项目路径) */
- private String genPath;
-
- /** 主键信息 */
- private GenTableColumn pkColumn;
-
- /** 子表信息 */
- private GenTable subTable;
-
- /** 表列信息 */
- @Valid
- private List<GenTableColumn> columns;
-
- /** 其它生成选项 */
- private String options;
-
- /** 树编码字段 */
- private String treeCode;
-
- /** 树父编码字段 */
- private String treeParentCode;
-
- /** 树名称字段 */
- private String treeName;
-
- /** 上级菜单ID字段 */
- private Long parentMenuId;
-
- /** 上级菜单名称字段 */
- private String parentMenuName;
-
- /** 是否生成详情页 */
- private boolean isView;
-
- public Long getTableId()
- {
- return tableId;
- }
-
- public void setTableId(Long tableId)
- {
- this.tableId = tableId;
- }
-
- public String getTableName()
- {
- return tableName;
- }
-
- public void setTableName(String tableName)
- {
- this.tableName = tableName;
- }
-
- public String getTableComment()
- {
- return tableComment;
- }
-
- public void setTableComment(String tableComment)
- {
- this.tableComment = tableComment;
- }
-
- public String getSubTableName()
- {
- return subTableName;
- }
-
- public void setSubTableName(String subTableName)
- {
- this.subTableName = subTableName;
- }
-
- public String getSubTableFkName()
- {
- return subTableFkName;
- }
-
- public void setSubTableFkName(String subTableFkName)
- {
- this.subTableFkName = subTableFkName;
- }
-
- public String getClassName()
- {
- return className;
- }
-
- public void setClassName(String className)
- {
- this.className = className;
- }
-
- public String getTplCategory()
- {
- return tplCategory;
- }
-
- public void setTplCategory(String tplCategory)
- {
- this.tplCategory = tplCategory;
- }
-
- public String getTplWebType()
- {
- return tplWebType;
- }
-
- public void setTplWebType(String tplWebType)
- {
- this.tplWebType = tplWebType;
- }
-
- public String getPackageName()
- {
- return packageName;
- }
-
- public void setPackageName(String packageName)
- {
- this.packageName = packageName;
- }
-
- public String getModuleName()
- {
- return moduleName;
- }
-
- public void setModuleName(String moduleName)
- {
- this.moduleName = moduleName;
- }
-
- public String getBusinessName()
- {
- return businessName;
- }
-
- public void setBusinessName(String businessName)
- {
- this.businessName = businessName;
- }
-
- public String getFunctionName()
- {
- return functionName;
- }
-
- public void setFunctionName(String functionName)
- {
- this.functionName = functionName;
- }
-
- public String getFunctionAuthor()
- {
- return functionAuthor;
- }
-
- public void setFunctionAuthor(String functionAuthor)
- {
- this.functionAuthor = functionAuthor;
- }
-
- public Integer getFormColNum()
- {
- return formColNum;
- }
-
- public void setFormColNum(Integer formColNum)
- {
- this.formColNum = formColNum;
- }
-
- public String getGenType()
- {
- return genType;
- }
-
- public void setGenType(String genType)
- {
- this.genType = genType;
- }
-
- public String getGenPath()
- {
- return genPath;
- }
-
- public void setGenPath(String genPath)
- {
- this.genPath = genPath;
- }
-
- public GenTableColumn getPkColumn()
- {
- return pkColumn;
- }
-
- public void setPkColumn(GenTableColumn pkColumn)
- {
- this.pkColumn = pkColumn;
- }
-
- public GenTable getSubTable()
- {
- return subTable;
- }
-
- public void setSubTable(GenTable subTable)
- {
- this.subTable = subTable;
- }
-
- public List<GenTableColumn> getColumns()
- {
- return columns;
- }
-
- public void setColumns(List<GenTableColumn> columns)
- {
- this.columns = columns;
- }
-
- public String getOptions()
- {
- return options;
- }
-
- public void setOptions(String options)
- {
- this.options = options;
- }
-
- public String getTreeCode()
- {
- return treeCode;
- }
-
- public void setTreeCode(String treeCode)
- {
- this.treeCode = treeCode;
- }
-
- public String getTreeParentCode()
- {
- return treeParentCode;
- }
-
- public void setTreeParentCode(String treeParentCode)
- {
- this.treeParentCode = treeParentCode;
- }
-
- public String getTreeName()
- {
- return treeName;
- }
-
- public void setTreeName(String treeName)
- {
- this.treeName = treeName;
- }
-
- public Long getParentMenuId()
- {
- return parentMenuId;
- }
-
- public void setParentMenuId(Long parentMenuId)
- {
- this.parentMenuId = parentMenuId;
- }
-
- public String getParentMenuName()
- {
- return parentMenuName;
- }
-
- public void setParentMenuName(String parentMenuName)
- {
- this.parentMenuName = parentMenuName;
- }
-
- public boolean isView()
- {
- return isView;
- }
-
- public void setView(boolean isView)
- {
- this.isView = isView;
- }
-
- public boolean isSub()
- {
- return isSub(this.tplCategory);
- }
-
- public static boolean isSub(String tplCategory)
- {
- return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
- }
-
- public boolean isTree()
- {
- return isTree(this.tplCategory);
- }
-
- public static boolean isTree(String tplCategory)
- {
- return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
- }
-
- public boolean isCrud()
- {
- return isCrud(this.tplCategory);
- }
-
- public static boolean isCrud(String tplCategory)
- {
- return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
- }
-
- public boolean isSuperColumn(String javaField)
- {
- return isSuperColumn(this.tplCategory, javaField);
- }
-
- public static boolean isSuperColumn(String tplCategory, String javaField)
- {
- if (isTree(tplCategory))
- {
- return StringUtils.equalsAnyIgnoreCase(javaField,
- ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
- }
- return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java
deleted file mode 100644
index 659f2b6..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTableColumn.java
+++ /dev/null
@@ -1,373 +0,0 @@
-package com.ruoyi.gen.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 代码生成业务字段表 gen_table_column
- *
- * @author ruoyi
- */
-public class GenTableColumn extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 编号 */
- private Long columnId;
-
- /** 归属表编号 */
- private Long tableId;
-
- /** 列名称 */
- private String columnName;
-
- /** 列描述 */
- private String columnComment;
-
- /** 列类型 */
- private String columnType;
-
- /** JAVA类型 */
- private String javaType;
-
- /** JAVA字段名 */
- @NotBlank(message = "Java属性不能为空")
- private String javaField;
-
- /** 是否主键(1是) */
- private String isPk;
-
- /** 是否自增(1是) */
- private String isIncrement;
-
- /** 是否必填(1是) */
- private String isRequired;
-
- /** 是否为插入字段(1是) */
- private String isInsert;
-
- /** 是否编辑字段(1是) */
- private String isEdit;
-
- /** 是否列表字段(1是) */
- private String isList;
-
- /** 是否查询字段(1是) */
- private String isQuery;
-
- /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */
- private String queryType;
-
- /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) */
- private String htmlType;
-
- /** 字典类型 */
- private String dictType;
-
- /** 排序 */
- private Integer sort;
-
- public void setColumnId(Long columnId)
- {
- this.columnId = columnId;
- }
-
- public Long getColumnId()
- {
- return columnId;
- }
-
- public void setTableId(Long tableId)
- {
- this.tableId = tableId;
- }
-
- public Long getTableId()
- {
- return tableId;
- }
-
- public void setColumnName(String columnName)
- {
- this.columnName = columnName;
- }
-
- public String getColumnName()
- {
- return columnName;
- }
-
- public void setColumnComment(String columnComment)
- {
- this.columnComment = columnComment;
- }
-
- public String getColumnComment()
- {
- return columnComment;
- }
-
- public void setColumnType(String columnType)
- {
- this.columnType = columnType;
- }
-
- public String getColumnType()
- {
- return columnType;
- }
-
- public void setJavaType(String javaType)
- {
- this.javaType = javaType;
- }
-
- public String getJavaType()
- {
- return javaType;
- }
-
- public void setJavaField(String javaField)
- {
- this.javaField = javaField;
- }
-
- public String getJavaField()
- {
- return javaField;
- }
-
- public String getCapJavaField()
- {
- return StringUtils.capitalize(javaField);
- }
-
- public void setIsPk(String isPk)
- {
- this.isPk = isPk;
- }
-
- public String getIsPk()
- {
- return isPk;
- }
-
- public boolean isPk()
- {
- return isPk(this.isPk);
- }
-
- public boolean isPk(String isPk)
- {
- return isPk != null && StringUtils.equals("1", isPk);
- }
-
- public String getIsIncrement()
- {
- return isIncrement;
- }
-
- public void setIsIncrement(String isIncrement)
- {
- this.isIncrement = isIncrement;
- }
-
- public boolean isIncrement()
- {
- return isIncrement(this.isIncrement);
- }
-
- public boolean isIncrement(String isIncrement)
- {
- return isIncrement != null && StringUtils.equals("1", isIncrement);
- }
-
- public void setIsRequired(String isRequired)
- {
- this.isRequired = isRequired;
- }
-
- public String getIsRequired()
- {
- return isRequired;
- }
-
- public boolean isRequired()
- {
- return isRequired(this.isRequired);
- }
-
- public boolean isRequired(String isRequired)
- {
- return isRequired != null && StringUtils.equals("1", isRequired);
- }
-
- public void setIsInsert(String isInsert)
- {
- this.isInsert = isInsert;
- }
-
- public String getIsInsert()
- {
- return isInsert;
- }
-
- public boolean isInsert()
- {
- return isInsert(this.isInsert);
- }
-
- public boolean isInsert(String isInsert)
- {
- return isInsert != null && StringUtils.equals("1", isInsert);
- }
-
- public void setIsEdit(String isEdit)
- {
- this.isEdit = isEdit;
- }
-
- public String getIsEdit()
- {
- return isEdit;
- }
-
- public boolean isEdit()
- {
- return isInsert(this.isEdit);
- }
-
- public boolean isEdit(String isEdit)
- {
- return isEdit != null && StringUtils.equals("1", isEdit);
- }
-
- public void setIsList(String isList)
- {
- this.isList = isList;
- }
-
- public String getIsList()
- {
- return isList;
- }
-
- public boolean isList()
- {
- return isList(this.isList);
- }
-
- public boolean isList(String isList)
- {
- return isList != null && StringUtils.equals("1", isList);
- }
-
- public void setIsQuery(String isQuery)
- {
- this.isQuery = isQuery;
- }
-
- public String getIsQuery()
- {
- return isQuery;
- }
-
- public boolean isQuery()
- {
- return isQuery(this.isQuery);
- }
-
- public boolean isQuery(String isQuery)
- {
- return isQuery != null && StringUtils.equals("1", isQuery);
- }
-
- public void setQueryType(String queryType)
- {
- this.queryType = queryType;
- }
-
- public String getQueryType()
- {
- return queryType;
- }
-
- public String getHtmlType()
- {
- return htmlType;
- }
-
- public void setHtmlType(String htmlType)
- {
- this.htmlType = htmlType;
- }
-
- public void setDictType(String dictType)
- {
- this.dictType = dictType;
- }
-
- public String getDictType()
- {
- return dictType;
- }
-
- public void setSort(Integer sort)
- {
- this.sort = sort;
- }
-
- public Integer getSort()
- {
- return sort;
- }
-
- public boolean isSuperColumn()
- {
- return isSuperColumn(this.javaField);
- }
-
- public static boolean isSuperColumn(String javaField)
- {
- return StringUtils.equalsAnyIgnoreCase(javaField,
- // BaseEntity
- "createBy", "createTime", "updateBy", "updateTime", "remark",
- // TreeEntity
- "parentName", "parentId", "orderNum", "ancestors");
- }
-
- public boolean isUsableColumn()
- {
- return isUsableColumn(javaField);
- }
-
- public static boolean isUsableColumn(String javaField)
- {
- // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
- return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
- }
-
- public String readConverterExp()
- {
- String remarks = StringUtils.substringBetween(this.columnComment, "(", ")");
- StringBuffer sb = new StringBuffer();
- if (StringUtils.isNotEmpty(remarks))
- {
- for (String value : remarks.split(" "))
- {
- if (StringUtils.isNotEmpty(value))
- {
- Object startStr = value.subSequence(0, 1);
- String endStr = value.substring(1);
- sb.append("").append(startStr).append("=").append(endStr).append(",");
- }
- }
- return sb.deleteCharAt(sb.length() - 1).toString();
- }
- else
- {
- return this.columnComment;
- }
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java
deleted file mode 100644
index e5df002..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableColumnMapper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.gen.mapper;
-
-import java.util.List;
-import com.ruoyi.gen.domain.GenTableColumn;
-
-/**
- * 业务字段 数据层
- *
- * @author ruoyi
- */
-public interface GenTableColumnMapper
-{
- /**
- * 根据表名称查询列信息
- *
- * @param tableName 表名称
- * @return 列信息
- */
- public List<GenTableColumn> selectDbTableColumnsByName(String tableName);
-
- /**
- * 查询业务字段列表
- *
- * @param tableId 业务字段编号
- * @return 业务字段集合
- */
- public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
-
- /**
- * 新增业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- public int insertGenTableColumn(GenTableColumn genTableColumn);
-
- /**
- * 修改业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- public int updateGenTableColumn(GenTableColumn genTableColumn);
-
- /**
- * 删除业务字段
- *
- * @param genTableColumns 列数据
- * @return 结果
- */
- public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);
-
- /**
- * 批量删除业务字段
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteGenTableColumnByIds(Long[] ids);
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java
deleted file mode 100644
index 3d36d88..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/mapper/GenTableMapper.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.ruoyi.gen.mapper;
-
-import java.util.List;
-import com.ruoyi.gen.domain.GenTable;
-
-/**
- * 业务 数据层
- *
- * @author ruoyi
- */
-public interface GenTableMapper
-{
- /**
- * 查询业务列表
- *
- * @param genTable 业务信息
- * @return 业务集合
- */
- public List<GenTable> selectGenTableList(GenTable genTable);
-
- /**
- * 查询据库列表
- *
- * @param genTable 业务信息
- * @return 数据库表集合
- */
- public List<GenTable> selectDbTableList(GenTable genTable);
-
- /**
- * 查询据库列表
- *
- * @param tableNames 表名称组
- * @return 数据库表集合
- */
- public List<GenTable> selectDbTableListByNames(String[] tableNames);
-
- /**
- * 查询所有表信息
- *
- * @return 表信息集合
- */
- public List<GenTable> selectGenTableAll();
-
- /**
- * 查询表ID业务信息
- *
- * @param id 业务ID
- * @return 业务信息
- */
- public GenTable selectGenTableById(Long id);
-
- /**
- * 查询表名称业务信息
- *
- * @param tableName 表名称
- * @return 业务信息
- */
- public GenTable selectGenTableByName(String tableName);
-
- /**
- * 新增业务
- *
- * @param genTable 业务信息
- * @return 结果
- */
- public int insertGenTable(GenTable genTable);
-
- /**
- * 修改业务
- *
- * @param genTable 业务信息
- * @return 结果
- */
- public int updateGenTable(GenTable genTable);
-
- /**
- * 批量删除业务
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteGenTableByIds(Long[] ids);
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java
deleted file mode 100644
index 8aac0e4..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableColumnServiceImpl.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.ruoyi.gen.service;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.gen.domain.GenTableColumn;
-import com.ruoyi.gen.mapper.GenTableColumnMapper;
-
-/**
- * 业务字段 服务层实现
- *
- * @author ruoyi
- */
-@Service
-public class GenTableColumnServiceImpl implements IGenTableColumnService
-{
- @Autowired
- private GenTableColumnMapper genTableColumnMapper;
-
- /**
- * 查询业务字段列表
- *
- * @param tableId 业务字段编号
- * @return 业务字段集合
- */
- @Override
- public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId)
- {
- return genTableColumnMapper.selectGenTableColumnListByTableId(tableId);
- }
-
- /**
- * 新增业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- @Override
- public int insertGenTableColumn(GenTableColumn genTableColumn)
- {
- return genTableColumnMapper.insertGenTableColumn(genTableColumn);
- }
-
- /**
- * 修改业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- @Override
- public int updateGenTableColumn(GenTableColumn genTableColumn)
- {
- return genTableColumnMapper.updateGenTableColumn(genTableColumn);
- }
-
- /**
- * 删除业务字段对象
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- @Override
- public int deleteGenTableColumnByIds(String ids)
- {
- return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java
deleted file mode 100644
index 4498e13..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java
+++ /dev/null
@@ -1,554 +0,0 @@
-package com.ruoyi.gen.service;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.Velocity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.GenConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.text.CharsetKit;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.gen.domain.GenTable;
-import com.ruoyi.gen.domain.GenTableColumn;
-import com.ruoyi.gen.mapper.GenTableColumnMapper;
-import com.ruoyi.gen.mapper.GenTableMapper;
-import com.ruoyi.gen.util.GenUtils;
-import com.ruoyi.gen.util.VelocityInitializer;
-import com.ruoyi.gen.util.VelocityUtils;
-
-/**
- * 业务 服务层实现
- *
- * @author ruoyi
- */
-@Service
-public class GenTableServiceImpl implements IGenTableService
-{
- private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
-
- @Autowired
- private GenTableMapper genTableMapper;
-
- @Autowired
- private GenTableColumnMapper genTableColumnMapper;
-
- /**
- * 查询业务信息
- *
- * @param id 业务ID
- * @return 业务信息
- */
- @Override
- public GenTable selectGenTableById(Long id)
- {
- GenTable genTable = genTableMapper.selectGenTableById(id);
- setTableFromOptions(genTable);
- return genTable;
- }
-
- /**
- * 查询业务列表
- *
- * @param genTable 业务信息
- * @return 业务集合
- */
- @Override
- public List<GenTable> selectGenTableList(GenTable genTable)
- {
- return genTableMapper.selectGenTableList(genTable);
- }
-
- /**
- * 查询据库列表
- *
- * @param genTable 业务信息
- * @return 数据库表集合
- */
- @Override
- public List<GenTable> selectDbTableList(GenTable genTable)
- {
- return genTableMapper.selectDbTableList(genTable);
- }
-
- /**
- * 查询据库列表
- *
- * @param tableNames 表名称组
- * @return 数据库表集合
- */
- @Override
- public List<GenTable> selectDbTableListByNames(String[] tableNames)
- {
- return genTableMapper.selectDbTableListByNames(tableNames);
- }
-
- /**
- * 查询所有表信息
- *
- * @return 表信息集合
- */
- @Override
- public List<GenTable> selectGenTableAll()
- {
- return genTableMapper.selectGenTableAll();
- }
-
- /**
- * 修改业务
- *
- * @param genTable 业务信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateGenTable(GenTable genTable)
- {
- String options = JSON.toJSONString(genTable.getParams());
- genTable.setOptions(options);
- int row = genTableMapper.updateGenTable(genTable);
- if (row > 0)
- {
- for (GenTableColumn genTableColumn : genTable.getColumns())
- {
- genTableColumnMapper.updateGenTableColumn(genTableColumn);
- }
- }
- }
-
- /**
- * 删除业务对象
- *
- * @param tableIds 需要删除的数据ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void deleteGenTableByIds(Long[] tableIds)
- {
- genTableMapper.deleteGenTableByIds(tableIds);
- genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
- }
-
- /**
- * 导入表结构
- *
- * @param tableList 导入表列表
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void importGenTable(List<GenTable> tableList, String tplWebType)
- {
- String operName = SecurityUtils.getUsername();
- try
- {
- for (GenTable table : tableList)
- {
- String tableName = table.getTableName();
- table.setTplWebType(tplWebType);
- GenUtils.initTable(table, operName);
- int row = genTableMapper.insertGenTable(table);
- if (row > 0)
- {
- // 保存列信息
- List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
- for (GenTableColumn column : genTableColumns)
- {
- GenUtils.initColumnField(column, table);
- genTableColumnMapper.insertGenTableColumn(column);
- }
- }
- }
- }
- catch (Exception e)
- {
- throw new ServiceException("导入失败:" + e.getMessage());
- }
- }
-
- /**
- * 预览代码
- *
- * @param tableId 表编号
- * @return 预览数据列表
- */
- @Override
- public Map<String, String> previewCode(Long tableId)
- {
- Map<String, String> dataMap = new LinkedHashMap<>();
- // 查询表信息
- GenTable table = genTableMapper.selectGenTableById(tableId);
- // 设置主子表信息
- setSubTable(table);
- // 设置主键列信息
- setPkColumn(table);
- VelocityInitializer.initVelocity();
-
- VelocityContext context = VelocityUtils.prepareContext(table);
-
- // 获取模板列表
- List<String> templates = VelocityUtils.getTemplateList(table);
- for (String template : templates)
- {
- // 渲染模板
- StringWriter sw = new StringWriter();
- Template tpl = Velocity.getTemplate(template, Constants.UTF8);
- tpl.merge(context, sw);
- dataMap.put(template, sw.toString());
- }
- return dataMap;
- }
-
- /**
- * 生成代码(下载方式)
- *
- * @param tableName 表名称
- * @return 数据
- */
- @Override
- public byte[] downloadCode(String tableName)
- {
- return downloadCode(new String[] { tableName });
- }
-
- /**
- * 生成代码(自定义路径)
- *
- * @param tableName 表名称
- */
- @Override
- public void generatorCode(String tableName)
- {
- // 查询表信息
- GenTable table = genTableMapper.selectGenTableByName(tableName);
- // 设置主子表信息
- setSubTable(table);
- // 设置主键列信息
- setPkColumn(table);
-
- VelocityInitializer.initVelocity();
-
- VelocityContext context = VelocityUtils.prepareContext(table);
-
- // 获取模板列表
- List<String> templates = VelocityUtils.getTemplateList(table);
- for (String template : templates)
- {
- if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "api.ts.vm", "type.ts.vm", "index.ts.vm", "index.vue.vm", "index-tree.vue.vm", "view.vue.vm"))
- {
- // 渲染模板
- StringWriter sw = new StringWriter();
- Template tpl = Velocity.getTemplate(template, Constants.UTF8);
- tpl.merge(context, sw);
- try
- {
- String path = getGenPath(table, template);
- FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
- }
- catch (IOException e)
- {
- throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
- }
- }
- }
- }
-
- /**
- * 同步数据库
- *
- * @param tableName 表名称
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void synchDb(String tableName)
- {
- GenTable table = genTableMapper.selectGenTableByName(tableName);
- List<GenTableColumn> tableColumns = table.getColumns();
- Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
-
- List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
- if (StringUtils.isEmpty(dbTableColumns))
- {
- throw new ServiceException("同步数据失败,原表结构不存在");
- }
- List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
-
- dbTableColumns.forEach(column -> {
- GenUtils.initColumnField(column, table);
- if (tableColumnMap.containsKey(column.getColumnName()))
- {
- GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
- column.setColumnId(prevColumn.getColumnId());
- if (column.isList())
- {
- // 如果是列表,继续保留查询方式/字典类型选项
- column.setDictType(prevColumn.getDictType());
- column.setQueryType(prevColumn.getQueryType());
- }
- if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
- && (column.isInsert() || column.isEdit())
- && ((column.isUsableColumn()) || (!column.isSuperColumn())))
- {
- // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
- column.setIsRequired(prevColumn.getIsRequired());
- column.setHtmlType(prevColumn.getHtmlType());
- }
- genTableColumnMapper.updateGenTableColumn(column);
- }
- else
- {
- genTableColumnMapper.insertGenTableColumn(column);
- }
- });
-
- List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
- if (StringUtils.isNotEmpty(delColumns))
- {
- genTableColumnMapper.deleteGenTableColumns(delColumns);
- }
- }
-
- /**
- * 批量生成代码(下载方式)
- *
- * @param tableNames 表数组
- * @return 数据
- */
- @Override
- public byte[] downloadCode(String[] tableNames)
- {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- ZipOutputStream zip = new ZipOutputStream(outputStream);
- Map<String, StringBuffer> typeFiles = new HashMap<>();
- for (String tableName : tableNames)
- {
- generatorCode(tableName, zip, typeFiles);
- }
- for (Map.Entry<String, StringBuffer> entry : typeFiles.entrySet())
- {
- writeToZip(zip, entry.getKey(), entry.getValue().toString());
- }
- IOUtils.closeQuietly(zip);
- return outputStream.toByteArray();
- }
-
- /**
- * 查询表信息并生成代码
- */
- private void generatorCode(String tableName, ZipOutputStream zip, Map<String, StringBuffer> typeFiles)
- {
- // 查询表信息
- GenTable table = genTableMapper.selectGenTableByName(tableName);
- // 设置主子表信息
- setSubTable(table);
- // 设置主键列信息
- setPkColumn(table);
-
- VelocityInitializer.initVelocity();
-
- VelocityContext context = VelocityUtils.prepareContext(table);
-
- // 获取模板列表
- List<String> templates = VelocityUtils.getTemplateList(table);
- for (String template : templates)
- {
- // 渲染模板
- StringWriter sw = new StringWriter();
- Template tpl = Velocity.getTemplate(template, Constants.UTF8);
- tpl.merge(context, sw);
- String fileName = VelocityUtils.getFileName(template, table);
- // index-bak.ts 模版,追加内容
- if (fileName.contains("index-bak.ts"))
- {
- if (!typeFiles.containsKey(fileName))
- {
- typeFiles.put(fileName, new StringBuffer(sw.toString()));
- }
- else
- {
- Arrays.stream(sw.toString().split("\n")).filter(line -> line.startsWith("export * from")).forEach(line -> typeFiles.get(fileName).append("\n").append(line));
- }
- }
- else
- {
- // 其他文件正常添加
- writeToZip(zip, fileName, sw.toString());
- }
- }
- }
-
- /**
- * 将字符串内容写入ZIP输出流
- *
- * @param zip ZIP输出流
- * @param fileName ZIP条目名称(即文件名)
- * @param content 要写入的内容
- */
- private void writeToZip(ZipOutputStream zip, String fileName, String content)
- {
- try
- {
- zip.putNextEntry(new ZipEntry(fileName));
- IOUtils.write(content, zip, Constants.UTF8);
- zip.flush();
- zip.closeEntry();
- }
- catch (IOException e)
- {
- log.error("写入ZIP文件失败,文件名: " + fileName, e);
- }
- }
-
- /**
- * 修改保存参数校验
- *
- * @param genTable 业务信息
- */
- @Override
- public void validateEdit(GenTable genTable)
- {
- if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
- {
- String options = JSON.toJSONString(genTable.getParams());
- JSONObject paramsObj = JSON.parseObject(options);
- if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
- {
- throw new ServiceException("树编码字段不能为空");
- }
- else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
- {
- throw new ServiceException("树父编码字段不能为空");
- }
- else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
- {
- throw new ServiceException("树名称字段不能为空");
- }
- }
- else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
- {
- if (StringUtils.isEmpty(genTable.getSubTableName()))
- {
- throw new ServiceException("关联子表的表名不能为空");
- }
- else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
- {
- throw new ServiceException("子表关联的外键名不能为空");
- }
- }
- }
-
- /**
- * 设置主键列信息
- *
- * @param table 业务表信息
- */
- public void setPkColumn(GenTable table)
- {
- for (GenTableColumn column : table.getColumns())
- {
- if (column.isPk())
- {
- table.setPkColumn(column);
- break;
- }
- }
- if (StringUtils.isNull(table.getPkColumn()))
- {
- table.setPkColumn(table.getColumns().get(0));
- }
- if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
- {
- for (GenTableColumn column : table.getSubTable().getColumns())
- {
- if (column.isPk())
- {
- table.getSubTable().setPkColumn(column);
- break;
- }
- }
- if (StringUtils.isNull(table.getSubTable().getPkColumn()))
- {
- table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
- }
- }
- }
-
- /**
- * 设置主子表信息
- *
- * @param table 业务表信息
- */
- public void setSubTable(GenTable table)
- {
- String subTableName = table.getSubTableName();
- if (StringUtils.isNotEmpty(subTableName))
- {
- table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
- }
- }
-
- /**
- * 设置代码生成其他选项值
- *
- * @param genTable 设置后的生成对象
- */
- public void setTableFromOptions(GenTable genTable)
- {
- JSONObject paramsObj = JSON.parseObject(genTable.getOptions());
- if (StringUtils.isNotNull(paramsObj))
- {
- String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
- String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
- String treeName = paramsObj.getString(GenConstants.TREE_NAME);
- Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID);
- String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
- boolean isView = paramsObj.getBooleanValue(GenConstants.GEN_VIEW);
-
- genTable.setTreeCode(treeCode);
- genTable.setTreeParentCode(treeParentCode);
- genTable.setTreeName(treeName);
- genTable.setParentMenuId(parentMenuId);
- genTable.setParentMenuName(parentMenuName);
- genTable.setView(isView);
- }
- }
-
- /**
- * 获取代码生成地址
- *
- * @param table 业务表信息
- * @param template 模板文件路径
- * @return 生成地址
- */
- public static String getGenPath(GenTable table, String template)
- {
- String genPath = table.getGenPath();
- if (StringUtils.equals(genPath, "/"))
- {
- return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
- }
- return genPath + File.separator + VelocityUtils.getFileName(template, table);
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java
deleted file mode 100644
index f7dec84..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableColumnService.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.ruoyi.gen.service;
-
-import java.util.List;
-import com.ruoyi.gen.domain.GenTableColumn;
-
-/**
- * 业务字段 服务层
- *
- * @author ruoyi
- */
-public interface IGenTableColumnService
-{
- /**
- * 查询业务字段列表
- *
- * @param tableId 业务字段编号
- * @return 业务字段集合
- */
- public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
-
- /**
- * 新增业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- public int insertGenTableColumn(GenTableColumn genTableColumn);
-
- /**
- * 修改业务字段
- *
- * @param genTableColumn 业务字段信息
- * @return 结果
- */
- public int updateGenTableColumn(GenTableColumn genTableColumn);
-
- /**
- * 删除业务字段信息
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteGenTableColumnByIds(String ids);
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java
deleted file mode 100644
index 3237b11..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/IGenTableService.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.ruoyi.gen.service;
-
-import java.util.List;
-import java.util.Map;
-import com.ruoyi.gen.domain.GenTable;
-
-/**
- * 业务 服务层
- *
- * @author ruoyi
- */
-public interface IGenTableService
-{
- /**
- * 查询业务列表
- *
- * @param genTable 业务信息
- * @return 业务集合
- */
- public List<GenTable> selectGenTableList(GenTable genTable);
-
- /**
- * 查询据库列表
- *
- * @param genTable 业务信息
- * @return 数据库表集合
- */
- public List<GenTable> selectDbTableList(GenTable genTable);
-
- /**
- * 查询据库列表
- *
- * @param tableNames 表名称组
- * @return 数据库表集合
- */
- public List<GenTable> selectDbTableListByNames(String[] tableNames);
-
- /**
- * 查询所有表信息
- *
- * @return 表信息集合
- */
- public List<GenTable> selectGenTableAll();
-
- /**
- * 查询业务信息
- *
- * @param id 业务ID
- * @return 业务信息
- */
- public GenTable selectGenTableById(Long id);
-
- /**
- * 修改业务
- *
- * @param genTable 业务信息
- * @return 结果
- */
- public void updateGenTable(GenTable genTable);
-
- /**
- * 删除业务信息
- *
- * @param tableIds 需要删除的表数据ID
- * @return 结果
- */
- public void deleteGenTableByIds(Long[] tableIds);
-
- /**
- * 导入表结构
- *
- * @param tableList 导入表列表
- * @param tplWebType 前端类型
- */
- public void importGenTable(List<GenTable> tableList, String tplWebType);
-
- /**
- * 预览代码
- *
- * @param tableId 表编号
- * @return 预览数据列表
- */
- public Map<String, String> previewCode(Long tableId);
-
- /**
- * 生成代码(下载方式)
- *
- * @param tableName 表名称
- * @return 数据
- */
- public byte[] downloadCode(String tableName);
-
- /**
- * 生成代码(自定义路径)
- *
- * @param tableName 表名称
- * @return 数据
- */
- public void generatorCode(String tableName);
-
- /**
- * 同步数据库
- *
- * @param tableName 表名称
- */
- public void synchDb(String tableName);
-
- /**
- * 批量生成代码(下载方式)
- *
- * @param tableNames 表数组
- * @return 数据
- */
- public byte[] downloadCode(String[] tableNames);
-
- /**
- * 修改保存参数校验
- *
- * @param genTable 业务信息
- */
- public void validateEdit(GenTable genTable);
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java
deleted file mode 100644
index 2c1c531..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package com.ruoyi.gen.util;
-
-import java.util.Arrays;
-import org.apache.commons.lang3.RegExUtils;
-import com.ruoyi.common.core.constant.GenConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.gen.config.GenConfig;
-import com.ruoyi.gen.domain.GenTable;
-import com.ruoyi.gen.domain.GenTableColumn;
-
-/**
- * 代码生成器 工具类
- *
- * @author ruoyi
- */
-public class GenUtils
-{
- /**
- * 初始化表信息
- */
- public static void initTable(GenTable genTable, String operName)
- {
- genTable.setClassName(convertClassName(genTable.getTableName()));
- genTable.setPackageName(GenConfig.getPackageName());
- genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
- genTable.setBusinessName(getBusinessName(genTable.getTableName()));
- genTable.setFunctionName(replaceText(genTable.getTableComment()));
- genTable.setFunctionAuthor(GenConfig.getAuthor());
- genTable.setCreateBy(operName);
- }
-
- /**
- * 初始化列属性字段
- */
- public static void initColumnField(GenTableColumn column, GenTable table)
- {
- String dataType = getDbType(column.getColumnType());
- String columnName = column.getColumnName();
- column.setTableId(table.getTableId());
- column.setCreateBy(table.getCreateBy());
- // 设置java字段名
- column.setJavaField(StringUtils.toCamelCase(columnName));
- // 设置默认类型
- column.setJavaType(GenConstants.TYPE_STRING);
- column.setQueryType(GenConstants.QUERY_EQ);
-
- if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
- {
- // 字符串长度超过500设置为文本域
- Integer columnLength = getColumnLength(column.getColumnType());
- String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
- column.setHtmlType(htmlType);
- }
- else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
- {
- column.setJavaType(GenConstants.TYPE_DATE);
- column.setHtmlType(GenConstants.HTML_DATETIME);
- }
- else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))
- {
- column.setHtmlType(GenConstants.HTML_INPUT);
-
- // 如果是浮点型 统一用BigDecimal
- String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
- if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
- {
- column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
- }
- // 如果是整形
- else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
- {
- column.setJavaType(GenConstants.TYPE_INTEGER);
- }
- // 长整形
- else
- {
- column.setJavaType(GenConstants.TYPE_LONG);
- }
- }
-
- // 插入字段(默认所有字段都需要插入)
- column.setIsInsert(GenConstants.REQUIRE);
-
- // 编辑字段
- if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
- {
- column.setIsEdit(GenConstants.REQUIRE);
- }
- // 列表字段
- if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
- {
- column.setIsList(GenConstants.REQUIRE);
- }
- // 查询字段
- if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
- {
- column.setIsQuery(GenConstants.REQUIRE);
- }
-
- // 查询字段类型
- if (StringUtils.endsWithIgnoreCase(columnName, "name"))
- {
- column.setQueryType(GenConstants.QUERY_LIKE);
- }
- // 状态字段设置单选框
- if (StringUtils.endsWithIgnoreCase(columnName, "status"))
- {
- column.setHtmlType(GenConstants.HTML_RADIO);
- }
- // 类型&性别字段设置下拉框
- else if (StringUtils.endsWithIgnoreCase(columnName, "type")
- || StringUtils.endsWithIgnoreCase(columnName, "sex"))
- {
- column.setHtmlType(GenConstants.HTML_SELECT);
- }
- // 图片字段设置图片上传控件
- else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
- {
- column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
- }
- // 文件字段设置文件上传控件
- else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
- {
- column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
- }
- // 内容字段设置富文本控件
- else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
- {
- column.setHtmlType(GenConstants.HTML_EDITOR);
- }
- }
-
- /**
- * 校验数组是否包含指定值
- *
- * @param arr 数组
- * @param targetValue 值
- * @return 是否包含
- */
- public static boolean arraysContains(String[] arr, String targetValue)
- {
- return Arrays.asList(arr).contains(targetValue);
- }
-
- /**
- * 获取模块名
- *
- * @param packageName 包名
- * @return 模块名
- */
- public static String getModuleName(String packageName)
- {
- int lastIndex = packageName.lastIndexOf(".");
- int nameLength = packageName.length();
- return StringUtils.substring(packageName, lastIndex + 1, nameLength);
- }
-
- /**
- * 获取业务名
- *
- * @param tableName 表名
- * @return 业务名
- */
- public static String getBusinessName(String tableName)
- {
- int lastIndex = tableName.lastIndexOf("_");
- int nameLength = tableName.length();
- return StringUtils.substring(tableName, lastIndex + 1, nameLength);
- }
-
- /**
- * 表名转换成Java类名
- *
- * @param tableName 表名称
- * @return 类名
- */
- public static String convertClassName(String tableName)
- {
- boolean autoRemovePre = GenConfig.getAutoRemovePre();
- String tablePrefix = GenConfig.getTablePrefix();
- if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
- {
- String[] searchList = StringUtils.split(tablePrefix, ",");
- tableName = replaceFirst(tableName, searchList);
- }
- return StringUtils.convertToCamelCase(tableName);
- }
-
- /**
- * 批量替换前缀
- *
- * @param replacementm 替换值
- * @param searchList 替换列表
- * @return
- */
- public static String replaceFirst(String replacementm, String[] searchList)
- {
- String text = replacementm;
- for (String searchString : searchList)
- {
- if (replacementm.startsWith(searchString))
- {
- text = replacementm.replaceFirst(searchString, "");
- break;
- }
- }
- return text;
- }
-
- /**
- * 关键字替换
- *
- * @param text 需要被替换的名字
- * @return 替换后的名字
- */
- public static String replaceText(String text)
- {
- return RegExUtils.replaceAll(text, "(?:表|若依)", "");
- }
-
- /**
- * 获取数据库类型字段
- *
- * @param columnType 列类型
- * @return 截取后的列类型
- */
- public static String getDbType(String columnType)
- {
- if (StringUtils.indexOf(columnType, "(") > 0)
- {
- return StringUtils.substringBefore(columnType, "(");
- }
- else
- {
- return columnType;
- }
- }
-
- /**
- * 获取字段长度
- *
- * @param columnType 列类型
- * @return 截取后的列类型
- */
- public static Integer getColumnLength(String columnType)
- {
- if (StringUtils.indexOf(columnType, "(") > 0)
- {
- String length = StringUtils.substringBetween(columnType, "(", ")");
- return Integer.valueOf(length);
- }
- else
- {
- return 0;
- }
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java
deleted file mode 100644
index c073662..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityInitializer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.ruoyi.gen.util;
-
-import java.util.Properties;
-import org.apache.velocity.app.Velocity;
-import com.ruoyi.common.core.constant.Constants;
-
-/**
- * VelocityEngine工厂
- *
- * @author ruoyi
- */
-public class VelocityInitializer
-{
- /**
- * 初始化vm方法
- */
- public static void initVelocity()
- {
- Properties p = new Properties();
- try
- {
- // 加载classpath目录下的vm文件
- p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
- // 定义字符集
- p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
- // 初始化Velocity引擎,指定配置Properties
- Velocity.init(p);
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java
deleted file mode 100644
index 5704b07..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java
+++ /dev/null
@@ -1,492 +0,0 @@
-package com.ruoyi.gen.util;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.apache.velocity.VelocityContext;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.core.constant.GenConstants;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.gen.domain.GenTable;
-import com.ruoyi.gen.domain.GenTableColumn;
-
-/**
- * 模板处理工具类
- *
- * @author ruoyi
- */
-public class VelocityUtils
-{
- /** 项目空间路径 */
- private static final String PROJECT_PATH = "main/java";
-
- /** mybatis空间路径 */
- private static final String MYBATIS_PATH = "main/resources/mapper";
-
- /** 默认上级菜单,系统工具 */
- private static final String DEFAULT_PARENT_MENU_ID = "3";
-
- /** Vue3 Element Plus 模版 */
- private static final String ELEMENT_PLUS = "element-plus";
-
- /** Vue3 Element Plus TypeScript 模版 */
- private static final String ELEMENT_PLUS_TYPESSRIPT = "element-plus-typescript";
-
- /**
- * 设置模板变量信息
- *
- * @return 模板列表
- */
- public static VelocityContext prepareContext(GenTable genTable)
- {
- String moduleName = genTable.getModuleName();
- String businessName = genTable.getBusinessName();
- String packageName = genTable.getPackageName();
- String tplCategory = genTable.getTplCategory();
- String functionName = genTable.getFunctionName();
-
- VelocityContext velocityContext = new VelocityContext();
- velocityContext.put("tplCategory", genTable.getTplCategory());
- velocityContext.put("tableName", genTable.getTableName());
- velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
- velocityContext.put("ClassName", genTable.getClassName());
- velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
- velocityContext.put("moduleName", genTable.getModuleName());
- velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
- velocityContext.put("businessName", genTable.getBusinessName());
- velocityContext.put("basePackage", getPackagePrefix(packageName));
- velocityContext.put("packageName", packageName);
- velocityContext.put("author", genTable.getFunctionAuthor());
- velocityContext.put("colSpan", getColSpan(genTable.getFormColNum()));
- velocityContext.put("datetime", DateUtils.getDate());
- velocityContext.put("pkColumn", genTable.getPkColumn());
- velocityContext.put("importList", getImportList(genTable));
- velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
- velocityContext.put("columns", genTable.getColumns());
- velocityContext.put("table", genTable);
- velocityContext.put("dicts", getDicts(genTable));
- setExtensionsContext(velocityContext, genTable.getOptions());
- setMenuVelocityContext(velocityContext, genTable);
- if (GenConstants.TPL_TREE.equals(tplCategory))
- {
- setTreeVelocityContext(velocityContext, genTable);
- }
- if (GenConstants.TPL_SUB.equals(tplCategory))
- {
- setSubVelocityContext(velocityContext, genTable);
- }
- return velocityContext;
- }
-
- public static void setExtensionsContext(VelocityContext context, String options)
- {
- JSONObject paramsObj = JSONObject.parseObject(options);
- boolean genView = genView(paramsObj);
- context.put("genView", genView);
- }
-
- public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
- {
- String options = genTable.getOptions();
- JSONObject paramsObj = JSON.parseObject(options);
- String parentMenuId = getParentMenuId(paramsObj);
- context.put("parentMenuId", parentMenuId);
- }
-
- public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
- {
- String options = genTable.getOptions();
- JSONObject paramsObj = JSON.parseObject(options);
- String treeCode = getTreecode(paramsObj);
- String treeParentCode = getTreeParentCode(paramsObj);
- String treeName = getTreeName(paramsObj);
-
- context.put("treeCode", treeCode);
- context.put("treeParentCode", treeParentCode);
- context.put("treeName", treeName);
- context.put("expandColumn", getExpandColumn(genTable));
- if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
- {
- context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
- }
- if (paramsObj.containsKey(GenConstants.TREE_NAME))
- {
- context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
- }
- }
-
- public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
- {
- GenTable subTable = genTable.getSubTable();
- String subTableName = genTable.getSubTableName();
- String subTableFkName = genTable.getSubTableFkName();
- String subClassName = genTable.getSubTable().getClassName();
- String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
-
- context.put("subTable", subTable);
- context.put("subTableName", subTableName);
- context.put("subTableFkName", subTableFkName);
- context.put("subTableFkClassName", subTableFkClassName);
- context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
- context.put("subClassName", subClassName);
- context.put("subclassName", StringUtils.uncapitalize(subClassName));
- context.put("subImportList", getImportList(genTable.getSubTable()));
- }
-
- /**
- * 获取模板信息
- * @param tplCategory 生成的模板
- * @param tplWebType 前端类型
- * @return 模板列表
- */
- public static List<String> getTemplateList(GenTable table)
- {
- String tplWebType = table.getTplWebType();
- String tplCategory = table.getTplCategory();
- JSONObject paramsObj = JSONObject.parseObject(table.getOptions());
- boolean isView = genView(paramsObj);
- String useWebType = "vm/vue";
- String apiTemplate = "vm/js/api.js.vm";
- if (StringUtils.equals(ELEMENT_PLUS, tplWebType))
- {
- useWebType = "vm/vue/v3";
- }
- else if (StringUtils.equals(ELEMENT_PLUS_TYPESSRIPT, tplWebType))
- {
- useWebType = "vm/vue/v3ts";
- apiTemplate = "vm/ts/api.ts.vm";
- }
- List<String> templates = new ArrayList<String>();
- templates.add("vm/java/domain.java.vm");
- templates.add("vm/java/mapper.java.vm");
- templates.add("vm/java/service.java.vm");
- templates.add("vm/java/serviceImpl.java.vm");
- templates.add("vm/java/controller.java.vm");
- templates.add("vm/xml/mapper.xml.vm");
- templates.add("vm/sql/sql.vm");
- templates.add(apiTemplate);
- if (StringUtils.equals(ELEMENT_PLUS_TYPESSRIPT, tplWebType))
- {
- templates.add("vm/ts/type.ts.vm");
- templates.add("vm/ts/index.ts.vm");
- }
- if (GenConstants.TPL_CRUD.equals(tplCategory))
- {
- templates.add(useWebType + "/index.vue.vm");
- }
- else if (GenConstants.TPL_TREE.equals(tplCategory))
- {
- templates.add(useWebType + "/index-tree.vue.vm");
- }
- else if (GenConstants.TPL_SUB.equals(tplCategory))
- {
- templates.add(useWebType + "/index.vue.vm");
- templates.add("vm/java/sub-domain.java.vm");
- }
- if (isView)
- {
- templates.add(useWebType + "/view.vue.vm");
- }
- return templates;
- }
-
- /**
- * 获取文件名
- */
- public static String getFileName(String template, GenTable genTable)
- {
- // 文件名称
- String fileName = "";
- // 包路径
- String packageName = genTable.getPackageName();
- // 模块名
- String moduleName = genTable.getModuleName();
- // 大写类名
- String className = genTable.getClassName();
- // 业务名称
- String businessName = genTable.getBusinessName();
-
- String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
- String mybatisPath = MYBATIS_PATH + "/" + moduleName;
- String vuePath = "vue";
-
- if (template.contains("domain.java.vm"))
- {
- fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
- }
- if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
- {
- fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
- }
- else if (template.contains("mapper.java.vm"))
- {
- fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
- }
- else if (template.contains("service.java.vm"))
- {
- fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
- }
- else if (template.contains("serviceImpl.java.vm"))
- {
- fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
- }
- else if (template.contains("controller.java.vm"))
- {
- fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
- }
- else if (template.contains("mapper.xml.vm"))
- {
- fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
- }
- else if (template.contains("sql.vm"))
- {
- fileName = businessName + "Menu.sql";
- }
- else if (template.contains("api.js.vm"))
- {
- fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
- }
- else if (template.contains("api.ts.vm"))
- {
- fileName = StringUtils.format("{}/api/{}/{}.ts", vuePath, moduleName, businessName);
- }
- else if (template.contains("type.ts.vm"))
- {
- fileName = StringUtils.format("{}/types/api/{}/{}.ts", vuePath, moduleName, businessName);
- }
- else if (template.contains("index.ts.vm"))
- {
- fileName = StringUtils.format("{}/types/api/index-bak.ts", vuePath);
- }
- else if (template.contains("index.vue.vm"))
- {
- fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
- }
- else if (template.contains("index-tree.vue.vm"))
- {
- fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
- }
- else if (template.contains("view.vue.vm"))
- {
- fileName = StringUtils.format("{}/views/{}/{}/view.vue", vuePath, moduleName, businessName);
- }
- return fileName;
- }
-
- /**
- * 获取包前缀
- *
- * @param packageName 包名称
- * @return 包前缀名称
- */
- public static String getPackagePrefix(String packageName)
- {
- int lastIndex = packageName.lastIndexOf(".");
- return StringUtils.substring(packageName, 0, lastIndex);
- }
-
- /**
- * 根据列类型获取导入包
- *
- * @param genTable 业务表对象
- * @return 返回需要导入的包列表
- */
- public static HashSet<String> getImportList(GenTable genTable)
- {
- List<GenTableColumn> columns = genTable.getColumns();
- GenTable subGenTable = genTable.getSubTable();
- HashSet<String> importList = new HashSet<String>();
- if (StringUtils.isNotNull(subGenTable))
- {
- importList.add("java.util.List");
- }
- for (GenTableColumn column : columns)
- {
- if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))
- {
- importList.add("java.util.Date");
- importList.add("com.fasterxml.jackson.annotation.JsonFormat");
- }
- else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))
- {
- importList.add("java.math.BigDecimal");
- }
- }
- return importList;
- }
-
- /**
- * 根据列类型获取字典组
- *
- * @param genTable 业务表对象
- * @return 返回字典组
- */
- public static String getDicts(GenTable genTable)
- {
- List<GenTableColumn> columns = genTable.getColumns();
- Set<String> dicts = new HashSet<String>();
- addDicts(dicts, columns);
- if (StringUtils.isNotNull(genTable.getSubTable()))
- {
- List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
- addDicts(dicts, subColumns);
- }
- return StringUtils.join(dicts, ", ");
- }
-
- /**
- * 添加字典列表
- *
- * @param dicts 字典列表
- * @param columns 列集合
- */
- public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
- {
- for (GenTableColumn column : columns)
- {
- if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
- column.getHtmlType(),
- new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX }))
- {
- dicts.add("'" + column.getDictType() + "'");
- }
- }
- }
-
- /**
- * 获取权限前缀
- *
- * @param moduleName 模块名称
- * @param businessName 业务名称
- * @return 返回权限前缀
- */
- public static String getPermissionPrefix(String moduleName, String businessName)
- {
- return StringUtils.format("{}:{}", moduleName, businessName);
- }
-
- /**
- * 获取上级菜单ID字段
- *
- * @param paramsObj 生成其他选项
- * @return 上级菜单ID字段
- */
- public static String getParentMenuId(JSONObject paramsObj)
- {
- if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
- && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
- {
- return paramsObj.getString(GenConstants.PARENT_MENU_ID);
- }
- return DEFAULT_PARENT_MENU_ID;
- }
-
- /**
- * 获取树编码
- *
- * @param paramsObj 生成其他选项
- * @return 树编码
- */
- public static String getTreecode(JSONObject paramsObj)
- {
- if (paramsObj.containsKey(GenConstants.TREE_CODE))
- {
- return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
- }
- return StringUtils.EMPTY;
- }
-
- /**
- * 获取树父编码
- *
- * @param paramsObj 生成其他选项
- * @return 树父编码
- */
- public static String getTreeParentCode(JSONObject paramsObj)
- {
- if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
- {
- return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
- }
- return StringUtils.EMPTY;
- }
-
- /**
- * 扩展功能/生成详情页
- *
- * @param paramsObj 生成其他选项
- * @return 是否生成详细页
- */
- public static boolean genView(JSONObject paramsObj)
- {
- if (StringUtils.isNotNull(paramsObj) && paramsObj.containsKey(GenConstants.GEN_VIEW))
- {
- return paramsObj.getBoolean(GenConstants.GEN_VIEW);
- }
- return false;
- }
-
- /**
- * 获取树名称
- *
- * @param paramsObj 生成其他选项
- * @return 树名称
- */
- public static String getTreeName(JSONObject paramsObj)
- {
- if (paramsObj.containsKey(GenConstants.TREE_NAME))
- {
- return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
- }
- return StringUtils.EMPTY;
- }
-
- /**
- * 获取需要在哪一列上面显示展开按钮
- *
- * @param genTable 业务表对象
- * @return 展开按钮列序号
- */
- public static int getExpandColumn(GenTable genTable)
- {
- String options = genTable.getOptions();
- JSONObject paramsObj = JSON.parseObject(options);
- String treeName = paramsObj.getString(GenConstants.TREE_NAME);
- int num = 0;
- for (GenTableColumn column : genTable.getColumns())
- {
- if (column.isList())
- {
- num++;
- String columnName = column.getColumnName();
- if (columnName.equals(treeName))
- {
- break;
- }
- }
- }
- return num;
- }
-
- /**
- * 获取表单 el-col span
- *
- * @param formColNum 表单布局方式(1单列 2双列 3三列)
- * @return span 数值字符串
- */
- public static String getColSpan(int formColNum)
- {
- if (formColNum == 2)
- {
- return "12";
- }
- else if (formColNum == 3)
- {
- return "8";
- }
- return "24";
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt
deleted file mode 100644
index a66e8b8..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _
- (_)
- _ __ _ _ ___ _ _ _ ______ __ _ ___ _ __
-| '__|| | | | / _ \ | | | || ||______| / _` | / _ \| '_ \
-| | | |_| || (_) || |_| || | | (_| || __/| | | |
-|_| \__,_| \___/ \__, ||_| \__, | \___||_| |_|
- __/ | __/ |
- |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml
deleted file mode 100644
index 250c080..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/logback.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true" scanPeriod="60 seconds" debug="false">
- <!-- 日志存放路径 -->
- <property name="log.path" value="logs/ruoyi-gen" />
- <!-- 日志输出格式 -->
- <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
-
- <!-- 控制台输出 -->
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- </appender>
-
- <!-- 系统日志输出 -->
- <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/info.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>INFO</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/error.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>ERROR</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 系统模块日志级别控制 -->
- <logger name="com.ruoyi" level="info" />
- <!-- Spring日志级别控制 -->
- <logger name="org.springframework" level="warn" />
-
- <root level="info">
- <appender-ref ref="console" />
- </root>
-
- <!--系统操作日志-->
- <root level="info">
- <appender-ref ref="file_info" />
- <appender-ref ref="file_error" />
- </root>
-</configuration>
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm
deleted file mode 100644
index db2ce45..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm
+++ /dev/null
@@ -1,115 +0,0 @@
-package ${packageName}.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import ${packageName}.domain.${ClassName};
-import ${packageName}.service.I${ClassName}Service;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-#if($table.crud || $table.sub)
-import com.ruoyi.common.core.web.page.TableDataInfo;
-#elseif($table.tree)
-#end
-
-/**
- * ${functionName}Controller
- *
- * @author ${author}
- * @date ${datetime}
- */
-@RestController
-@RequestMapping("/${businessName}")
-public class ${ClassName}Controller extends BaseController
-{
- @Autowired
- private I${ClassName}Service ${className}Service;
-
- /**
- * 查询${functionName}列表
- */
- @RequiresPermissions("${permissionPrefix}:list")
- @GetMapping("/list")
-#if($table.crud || $table.sub)
- public TableDataInfo list(${ClassName} ${className})
- {
- startPage();
- List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
- return getDataTable(list);
- }
-#elseif($table.tree)
- public AjaxResult list(${ClassName} ${className})
- {
- List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
- return success(list);
- }
-#end
-
- /**
- * 导出${functionName}列表
- */
- @RequiresPermissions("${permissionPrefix}:export")
- @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
- @PostMapping("/export")
- public void export(HttpServletResponse response, ${ClassName} ${className})
- {
- List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
- ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
- util.exportExcel(response, list, "${functionName}数据");
- }
-
- /**
- * 获取${functionName}详细信息
- */
- @RequiresPermissions("${permissionPrefix}:query")
- @GetMapping(value = "/{${pkColumn.javaField}}")
- public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
- {
- return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
- }
-
- /**
- * 新增${functionName}
- */
- @RequiresPermissions("${permissionPrefix}:add")
- @Log(title = "${functionName}", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@RequestBody ${ClassName} ${className})
- {
- return toAjax(${className}Service.insert${ClassName}(${className}));
- }
-
- /**
- * 修改${functionName}
- */
- @RequiresPermissions("${permissionPrefix}:edit")
- @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@RequestBody ${ClassName} ${className})
- {
- return toAjax(${className}Service.update${ClassName}(${className}));
- }
-
- /**
- * 删除${functionName}
- */
- @RequiresPermissions("${permissionPrefix}:remove")
- @Log(title = "${functionName}", businessType = BusinessType.DELETE)
- @DeleteMapping("/{${pkColumn.javaField}s}")
- public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
- {
- return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm
deleted file mode 100644
index af7e7ab..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm
+++ /dev/null
@@ -1,105 +0,0 @@
-package ${packageName}.domain;
-
-#foreach ($import in $importList)
-import ${import};
-#end
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-#if($table.crud || $table.sub)
-import com.ruoyi.common.core.web.domain.BaseEntity;
-#elseif($table.tree)
-import com.ruoyi.common.core.web.domain.TreeEntity;
-#end
-
-/**
- * ${functionName}对象 ${tableName}
- *
- * @author ${author}
- * @date ${datetime}
- */
-#if($table.crud || $table.sub)
-#set($Entity="BaseEntity")
-#elseif($table.tree)
-#set($Entity="TreeEntity")
-#end
-public class ${ClassName} extends ${Entity}
-{
- private static final long serialVersionUID = 1L;
-
-#foreach ($column in $columns)
-#if(!$table.isSuperColumn($column.javaField))
- /** $column.columnComment */
-#if($column.list)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($parentheseIndex != -1)
- @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
-#elseif($column.javaType == 'Date')
- @JsonFormat(pattern = "yyyy-MM-dd")
- @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
-#else
- @Excel(name = "${comment}")
-#end
-#end
- private $column.javaType $column.javaField;
-
-#end
-#end
-#if($table.sub)
- /** $table.subTable.functionName信息 */
- private List<${subClassName}> ${subclassName}List;
-
-#end
-#foreach ($column in $columns)
-#if(!$table.isSuperColumn($column.javaField))
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
- public void set${AttrName}($column.javaType $column.javaField)
- {
- this.$column.javaField = $column.javaField;
- }
-
- public $column.javaType get${AttrName}()
- {
- return $column.javaField;
- }
-
-#end
-#end
-#if($table.sub)
- public List<${subClassName}> get${subClassName}List()
- {
- return ${subclassName}List;
- }
-
- public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
- {
- this.${subclassName}List = ${subclassName}List;
- }
-
-#end
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-#foreach ($column in $columns)
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
- .append("${column.javaField}", get${AttrName}())
-#end
-#if($table.sub)
- .append("${subclassName}List", get${subClassName}List())
-#end
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm
deleted file mode 100644
index 6f03179..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm
+++ /dev/null
@@ -1,91 +0,0 @@
-package ${packageName}.mapper;
-
-import java.util.List;
-import ${packageName}.domain.${ClassName};
-#if($table.sub)
-import ${packageName}.domain.${subClassName};
-#end
-
-/**
- * ${functionName}Mapper接口
- *
- * @author ${author}
- * @date ${datetime}
- */
-public interface ${ClassName}Mapper
-{
- /**
- * 查询${functionName}
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return ${functionName}
- */
- public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-
- /**
- * 查询${functionName}列表
- *
- * @param ${className} ${functionName}
- * @return ${functionName}集合
- */
- public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
-
- /**
- * 新增${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
- public int insert${ClassName}(${ClassName} ${className});
-
- /**
- * 修改${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
- public int update${ClassName}(${ClassName} ${className});
-
- /**
- * 删除${functionName}
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return 结果
- */
- public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-
- /**
- * 批量删除${functionName}
- *
- * @param ${pkColumn.javaField}s 需要删除的数据主键集合
- * @return 结果
- */
- public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
-#if($table.sub)
-
- /**
- * 批量删除${subTable.functionName}
- *
- * @param ${pkColumn.javaField}s 需要删除的数据主键集合
- * @return 结果
- */
- public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
-
- /**
- * 批量新增${subTable.functionName}
- *
- * @param ${subclassName}List ${subTable.functionName}列表
- * @return 结果
- */
- public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
-
-
- /**
- * 通过${functionName}主键删除${subTable.functionName}信息
- *
- * @param ${pkColumn.javaField} ${functionName}ID
- * @return 结果
- */
- public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
-#end
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm
deleted file mode 100644
index 250f68c..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm
+++ /dev/null
@@ -1,61 +0,0 @@
-package ${packageName}.service;
-
-import java.util.List;
-import ${packageName}.domain.${ClassName};
-
-/**
- * ${functionName}Service接口
- *
- * @author ${author}
- * @date ${datetime}
- */
-public interface I${ClassName}Service
-{
- /**
- * 查询${functionName}
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return ${functionName}
- */
- public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-
- /**
- * 查询${functionName}列表
- *
- * @param ${className} ${functionName}
- * @return ${functionName}集合
- */
- public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
-
- /**
- * 新增${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
- public int insert${ClassName}(${ClassName} ${className});
-
- /**
- * 修改${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
- public int update${ClassName}(${ClassName} ${className});
-
- /**
- * 批量删除${functionName}
- *
- * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
- * @return 结果
- */
- public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
-
- /**
- * 删除${functionName}信息
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return 结果
- */
- public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm
deleted file mode 100644
index 9cd8534..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm
+++ /dev/null
@@ -1,169 +0,0 @@
-package ${packageName}.service.impl;
-
-import java.util.List;
-#foreach ($column in $columns)
-#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
-import com.ruoyi.common.core.utils.DateUtils;
-#break
-#end
-#end
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-#if($table.sub)
-import java.util.ArrayList;
-import com.ruoyi.common.core.utils.StringUtils;
-import org.springframework.transaction.annotation.Transactional;
-import ${packageName}.domain.${subClassName};
-#end
-import ${packageName}.mapper.${ClassName}Mapper;
-import ${packageName}.domain.${ClassName};
-import ${packageName}.service.I${ClassName}Service;
-
-/**
- * ${functionName}Service业务层处理
- *
- * @author ${author}
- * @date ${datetime}
- */
-@Service
-public class ${ClassName}ServiceImpl implements I${ClassName}Service
-{
- @Autowired
- private ${ClassName}Mapper ${className}Mapper;
-
- /**
- * 查询${functionName}
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return ${functionName}
- */
- @Override
- public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
- {
- return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
- }
-
- /**
- * 查询${functionName}列表
- *
- * @param ${className} ${functionName}
- * @return ${functionName}
- */
- @Override
- public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
- {
- return ${className}Mapper.select${ClassName}List(${className});
- }
-
- /**
- * 新增${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
-#if($table.sub)
- @Transactional
-#end
- @Override
- public int insert${ClassName}(${ClassName} ${className})
- {
-#foreach ($column in $columns)
-#if($column.javaField == 'createTime')
- ${className}.setCreateTime(DateUtils.getNowDate());
-#end
-#end
-#if($table.sub)
- int rows = ${className}Mapper.insert${ClassName}(${className});
- insert${subClassName}(${className});
- return rows;
-#else
- return ${className}Mapper.insert${ClassName}(${className});
-#end
- }
-
- /**
- * 修改${functionName}
- *
- * @param ${className} ${functionName}
- * @return 结果
- */
-#if($table.sub)
- @Transactional
-#end
- @Override
- public int update${ClassName}(${ClassName} ${className})
- {
-#foreach ($column in $columns)
-#if($column.javaField == 'updateTime')
- ${className}.setUpdateTime(DateUtils.getNowDate());
-#end
-#end
-#if($table.sub)
- ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
- insert${subClassName}(${className});
-#end
- return ${className}Mapper.update${ClassName}(${className});
- }
-
- /**
- * 批量删除${functionName}
- *
- * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
- * @return 结果
- */
-#if($table.sub)
- @Transactional
-#end
- @Override
- public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
- {
-#if($table.sub)
- ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
-#end
- return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
- }
-
- /**
- * 删除${functionName}信息
- *
- * @param ${pkColumn.javaField} ${functionName}主键
- * @return 结果
- */
-#if($table.sub)
- @Transactional
-#end
- @Override
- public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
- {
-#if($table.sub)
- ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
-#end
- return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
- }
-#if($table.sub)
-
- /**
- * 新增${subTable.functionName}信息
- *
- * @param ${className} ${functionName}对象
- */
- public void insert${subClassName}(${ClassName} ${className})
- {
- List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
- ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
- if (StringUtils.isNotNull(${subclassName}List))
- {
- List<${subClassName}> list = new ArrayList<${subClassName}>();
- for (${subClassName} ${subclassName} : ${subclassName}List)
- {
- ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
- list.add(${subclassName});
- }
- if (list.size() > 0)
- {
- ${className}Mapper.batch${subClassName}(list);
- }
- }
- }
-#end
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm
deleted file mode 100644
index d78cd2f..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/js/api.js.vm
+++ /dev/null
@@ -1,44 +0,0 @@
-import request from '@/utils/request'
-
-// 查询${functionName}列表
-export function list${BusinessName}(query) {
- return request({
- url: '/${moduleName}/${businessName}/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询${functionName}详细
-export function get${BusinessName}(${pkColumn.javaField}) {
- return request({
- url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
- method: 'get'
- })
-}
-
-// 新增${functionName}
-export function add${BusinessName}(data) {
- return request({
- url: '/${moduleName}/${businessName}',
- method: 'post',
- data: data
- })
-}
-
-// 修改${functionName}
-export function update${BusinessName}(data) {
- return request({
- url: '/${moduleName}/${businessName}',
- method: 'put',
- data: data
- })
-}
-
-// 删除${functionName}
-export function del${BusinessName}(${pkColumn.javaField}) {
- return request({
- url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
- method: 'delete'
- })
-}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm
deleted file mode 100644
index b50ef21..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm
+++ /dev/null
@@ -1,22 +0,0 @@
--- 菜单 SQL
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
-
--- 按钮父菜单ID
-SELECT @parentId := LAST_INSERT_ID();
-
--- 按钮 SQL
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, '');
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
deleted file mode 100644
index b26d70d..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
+++ /dev/null
@@ -1,565 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-#foreach($column in $columns)
-#if($column.query)
-#set($dictType=$column.dictType)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.htmlType == "input")
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-input
- v-model="queryParams.${column.javaField}"
- placeholder="请输入${comment}"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
- <el-option
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
- <el-option label="请选择字典生成" value="" />
- </el-select>
- </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-date-picker clearable
- v-model="queryParams.${column.javaField}"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="选择${comment}">
- </el-date-picker>
- </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
- <el-form-item label="${comment}">
- <el-date-picker
- v-model="daterange${AttrName}"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
-#end
-#end
-#end
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['${permissionPrefix}:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="info"
- plain
- icon="el-icon-sort"
- size="mini"
- @click="toggleExpandAll"
- >展开/折叠</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table
- v-if="refreshTable"
- v-loading="loading"
- :data="${businessName}List"
- row-key="${treeCode}"
- :default-expand-all="isExpandAll"
- :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
- >
-#foreach($column in $columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk)
-#elseif($column.list && $column.htmlType == "datetime")
- <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
- </template>
- </el-table-column>
-#elseif($column.list && $column.htmlType == "imageUpload")
- <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
- <template slot-scope="scope">
- <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
- </template>
- </el-table-column>
-#elseif($column.list && "" != $column.dictType)
- <el-table-column label="${comment}" align="center" prop="${javaField}">
- <template slot-scope="scope">
-#if($column.htmlType == "checkbox")
- <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
-#else
- <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
-#end
- </template>
- </el-table-column>
-#elseif($column.list && "" != $javaField)
-#if(${foreach.index} == 1)
- <el-table-column label="${comment}" prop="${javaField}" />
-#else
- <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#end
-#end
-#end
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
-#if($genView)
- <el-button
- size="mini"
- type="text"
- icon="el-icon-view"
- @click="handleViewData(scope.row)"
- v-hasPermi="['${permissionPrefix}:query']"
- >详情</el-button>
-#end
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['${permissionPrefix}:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-plus"
- @click="handleAdd(scope.row)"
- v-hasPermi="['${permissionPrefix}:add']"
- >新增</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['${permissionPrefix}:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
-#if($genView)
- <!-- ${functionName}详情抽屉 -->
- <${businessName}-view-drawer ref="${businessName}ViewRef" />
-#end
- <!-- 添加或修改${functionName}对话框 -->
-#if($table.formColNum == 2)
-#set($dialogWidth = "800px")
-#elseif($table.formColNum == 3)
-#set($dialogWidth = "1100px")
-#else
-#set($dialogWidth = "500px")
-#end
- <el-dialog :title="title" :visible.sync="open" width="${dialogWidth}" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <el-row>
-#foreach($column in $columns)
-#set($field=$column.javaField)
-#if($column.insert && !$column.pk)
-#if(($column.usableColumn) || (!$column.superColumn))
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#set($dictType=$column.dictType)
-#if("" != $treeParentCode && $column.javaField == $treeParentCode)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${treeParentCode}">
- <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="请选择${comment}" />
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "input")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-input v-model="form.${field}" placeholder="请输入${comment}" />
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "imageUpload")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <image-upload v-model="form.${field}"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "fileUpload")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <file-upload v-model="form.${field}"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "editor")
- <el-col :span="24">
- <el-form-item label="${comment}">
- <editor v-model="form.${field}" :min-height="192"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "select" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-select v-model="form.${field}" placeholder="请选择${comment}">
- <el-option
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.label"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
- :value="parseInt(dict.value)"
-#else
- :value="dict.value"
-#end
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "select" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-select v-model="form.${field}" placeholder="请选择${comment}">
- <el-option label="请选择字典生成" value="" />
- </el-select>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "checkbox" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-checkbox-group v-model="form.${field}">
- <el-checkbox
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.value">
- {{dict.label}}
- </el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "checkbox" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-checkbox-group v-model="form.${field}">
- <el-checkbox>请选择字典生成</el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "radio" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-radio-group v-model="form.${field}">
- <el-radio
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
- :label="parseInt(dict.value)"
-#else
- :label="dict.value"
-#end
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "radio" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-radio-group v-model="form.${field}">
- <el-radio label="1">请选择字典生成</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "datetime")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-date-picker clearable
- v-model="form.${field}"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="选择${comment}">
- </el-date-picker>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "textarea")
- <el-col :span="24">
- <el-form-item label="${comment}" prop="${field}">
- <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
- </el-form-item>
- </el-col>
-#end
-#end
-#end
-#end
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
-#if($genView)
-import ${BusinessName}ViewDrawer from "./view"
-#end
-import Treeselect from "@riophae/vue-treeselect"
-import "@riophae/vue-treeselect/dist/vue-treeselect.css"
-
-export default {
- name: "${BusinessName}",
-#if(${dicts} != '')
- dicts: [${dicts}],
-#end
- components: {
-#if($genView)
- ${BusinessName}ViewDrawer,
-#end
- Treeselect
- },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 显示搜索条件
- showSearch: true,
- // ${functionName}表格数据
- ${businessName}List: [],
- // ${functionName}树选项
- ${businessName}Options: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 是否展开,默认全部展开
- isExpandAll: true,
- // 重新渲染表格状态
- refreshTable: true,
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- // $comment时间范围
- daterange${AttrName}: [],
-#end
-#end
- // 查询参数
- queryParams: {
-#foreach ($column in $columns)
-#if($column.query)
- $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
-#foreach ($column in $columns)
-#if($column.required)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
- $column.javaField: [
- { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
- ]#if($foreach.count != $columns.size()),#end
-#end
-#end
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询${functionName}列表 */
- getList() {
- this.loading = true
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
- this.queryParams.params = {}
-#break
-#end
-#end
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
- this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
- this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
- }
-#end
-#end
- list${BusinessName}(this.queryParams).then(response => {
- this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
- this.loading = false
- })
- },
- /** 转换${functionName}数据结构 */
- normalizer(node) {
- if (node.children && !node.children.length) {
- delete node.children
- }
- return {
- id: node.${treeCode},
- label: node.${treeName},
- children: node.children
- }
- },
- /** 查询${functionName}下拉树结构 */
- getTreeselect() {
- list${BusinessName}().then(response => {
- this.${businessName}Options = []
- const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
- data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
- this.${businessName}Options.push(data)
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- $column.javaField: []#if($foreach.count != $columns.size()),#end
-#else
- $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- this.daterange${AttrName} = []
-#end
-#end
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd(row) {
- this.reset()
- this.getTreeselect()
- if (row != null && row.${treeCode}) {
- this.form.${treeParentCode} = row.${treeCode}
- } else {
- this.form.${treeParentCode} = 0
- }
- this.open = true
- this.title = "添加${functionName}"
- },
- /** 展开/折叠操作 */
- toggleExpandAll() {
- this.refreshTable = false
- this.isExpandAll = !this.isExpandAll
- this.$nextTick(() => {
- this.refreshTable = true
- })
- },
-#if($genView)
- /** 详情按钮操作 */
- handleViewData(row) {
- this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
- },
-#end
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- this.getTreeselect()
- if (row != null) {
- this.form.${treeParentCode} = row.${treeParentCode}
- }
- get${BusinessName}(row.${pkColumn.javaField}).then(response => {
- this.form = response.data
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- this.form.$column.javaField = this.form.${column.javaField}.split(",")
-#end
-#end
- this.open = true
- this.title = "修改${functionName}"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.#[[$]]#refs["form"].validate(valid => {
- if (valid) {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- this.form.$column.javaField = this.form.${column.javaField}.join(",")
-#end
-#end
- if (this.form.${pkColumn.javaField} != null) {
- update${BusinessName}(this.form).then(response => {
- this.#[[$modal]]#.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- add${BusinessName}(this.form).then(response => {
- this.#[[$modal]]#.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
- return del${BusinessName}(row.${pkColumn.javaField})
- }).then(() => {
- this.getList()
- this.#[[$modal]]#.msgSuccess("删除成功")
- }).catch(() => {})
- }
- }
-}
-</script>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm
deleted file mode 100644
index 007c545..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm
+++ /dev/null
@@ -1,660 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-#foreach($column in $columns)
-#if($column.query)
-#set($dictType=$column.dictType)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.htmlType == "input")
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-input
- v-model="queryParams.${column.javaField}"
- placeholder="请输入${comment}"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
- <el-option
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
- <el-option label="请选择字典生成" value="" />
- </el-select>
- </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
- <el-form-item label="${comment}" prop="${column.javaField}">
- <el-date-picker clearable
- v-model="queryParams.${column.javaField}"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="请选择${comment}">
- </el-date-picker>
- </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
- <el-form-item label="${comment}">
- <el-date-picker
- v-model="daterange${AttrName}"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
-#end
-#end
-#end
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['${permissionPrefix}:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['${permissionPrefix}:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['${permissionPrefix}:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['${permissionPrefix}:export']"
- >导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
-#foreach($column in $columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk)
- <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#elseif($column.list && $column.htmlType == "datetime")
- <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
- </template>
- </el-table-column>
-#elseif($column.list && $column.htmlType == "imageUpload")
- <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
- <template slot-scope="scope">
- <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
- </template>
- </el-table-column>
-#elseif($column.list && "" != $column.dictType)
- <el-table-column label="${comment}" align="center" prop="${javaField}">
- <template slot-scope="scope">
-#if($column.htmlType == "checkbox")
- <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
-#else
- <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
-#end
- </template>
- </el-table-column>
-#elseif($column.list && "" != $javaField)
- <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#end
-#end
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
-#if($genView)
- <el-button
- size="mini"
- type="text"
- icon="el-icon-view"
- @click="handleViewData(scope.row)"
- v-hasPermi="['${permissionPrefix}:query']"
- >详情</el-button>
-#end
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['${permissionPrefix}:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['${permissionPrefix}:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
-#if($genView)
- <!-- ${functionName}详情抽屉 -->
- <${businessName}-view-drawer ref="${businessName}ViewRef" />
-#end
- <!-- 添加或修改${functionName}对话框 -->
-#if($table.formColNum == 2)
-#set($dialogWidth = "800px")
-#elseif($table.formColNum == 3)
-#set($dialogWidth = "1100px")
-#else
-#set($dialogWidth = "500px")
-#end
- <el-dialog :title="title" :visible.sync="open" width="${dialogWidth}" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <el-row>
-#foreach($column in $columns)
-#set($field=$column.javaField)
-#if($column.insert && !$column.pk)
-#if(($column.usableColumn) || (!$column.superColumn))
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#set($dictType=$column.dictType)
-#if($column.htmlType == "input")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-input v-model="form.${field}" placeholder="请输入${comment}" />
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "imageUpload")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <image-upload v-model="form.${field}"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "fileUpload")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <file-upload v-model="form.${field}"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "editor")
- <el-col :span="24">
- <el-form-item label="${comment}">
- <editor v-model="form.${field}" :min-height="192"/>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "select" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-select v-model="form.${field}" placeholder="请选择${comment}">
- <el-option
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.label"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
- :value="parseInt(dict.value)"
-#else
- :value="dict.value"
-#end
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "select" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-select v-model="form.${field}" placeholder="请选择${comment}">
- <el-option label="请选择字典生成" value="" />
- </el-select>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "checkbox" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-checkbox-group v-model="form.${field}">
- <el-checkbox
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
- :label="dict.value">
- {{dict.label}}
- </el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "checkbox" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-checkbox-group v-model="form.${field}">
- <el-checkbox>请选择字典生成</el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "radio" && "" != $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-radio-group v-model="form.${field}">
- <el-radio
- v-for="dict in dict.type.${dictType}"
- :key="dict.value"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
- :label="parseInt(dict.value)"
-#else
- :label="dict.value"
-#end
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "radio" && $dictType)
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-radio-group v-model="form.${field}">
- <el-radio label="1">请选择字典生成</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "datetime")
- <el-col :span="${colSpan}">
- <el-form-item label="${comment}" prop="${field}">
- <el-date-picker clearable
- v-model="form.${field}"
- type="date"
- value-format="yyyy-MM-dd"
- placeholder="请选择${comment}">
- </el-date-picker>
- </el-form-item>
- </el-col>
-#elseif($column.htmlType == "textarea")
- <el-col :span="24">
- <el-form-item label="${comment}" prop="${field}">
- <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
- </el-form-item>
- </el-col>
-#end
-#end
-#end
-#end
- </el-row>
-#if($table.sub)
- <el-divider content-position="center">${subTable.functionName}信息</el-divider>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
- </el-col>
- </el-row>
- <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
- <el-table-column type="selection" width="50" align="center" />
- <el-table-column label="序号" align="center" prop="index" width="50"/>
-#foreach($column in $subTable.columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk || $javaField == ${subTableFkclassName})
-#elseif($column.list && $column.htmlType == "input")
- <el-table-column label="$comment" prop="${javaField}" width="150">
- <template slot-scope="scope">
- <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
- </template>
- </el-table-column>
-#elseif($column.list && $column.htmlType == "datetime")
- <el-table-column label="$comment" prop="${javaField}" width="240">
- <template slot-scope="scope">
- <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
- </template>
- </el-table-column>
-#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
- <el-table-column label="$comment" prop="${javaField}" width="150">
- <template slot-scope="scope">
- <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
- <el-option
- v-for="dict in dict.type.$column.dictType"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- ></el-option>
- </el-select>
- </template>
- </el-table-column>
-#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
- <el-table-column label="$comment" prop="${javaField}" width="150">
- <template slot-scope="scope">
- <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
- <el-option label="请选择字典生成" value="" />
- </el-select>
- </template>
- </el-table-column>
-#end
-#end
- </el-table>
-#end
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
-#if($genView)
-import ${BusinessName}ViewDrawer from "./view"
-#end
-
-export default {
- name: "${BusinessName}",
-#if($genView)
- components: { ${BusinessName}ViewDrawer },
-#end
-#if(${dicts} != '')
- dicts: [${dicts}],
-#end
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
-#if($table.sub)
- // 子表选中数据
- checked${subClassName}: [],
-#end
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // ${functionName}表格数据
- ${businessName}List: [],
-#if($table.sub)
- // ${subTable.functionName}表格数据
- ${subclassName}List: [],
-#end
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- // $comment时间范围
- daterange${AttrName}: [],
-#end
-#end
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
-#foreach ($column in $columns)
-#if($column.query)
- $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
-#foreach ($column in $columns)
-#if($column.required)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
- $column.javaField: [
- { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
- ]#if($foreach.count != $columns.size()),#end
-#end
-#end
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询${functionName}列表 */
- getList() {
- this.loading = true
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
- this.queryParams.params = {}
-#break
-#end
-#end
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
- this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
- this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
- }
-#end
-#end
- list${BusinessName}(this.queryParams).then(response => {
- this.${businessName}List = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- $column.javaField: []#if($foreach.count != $columns.size()),#end
-#else
- $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
- }
-#if($table.sub)
- this.${subclassName}List = []
-#end
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
- this.daterange${AttrName} = []
-#end
-#end
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.${pkColumn.javaField})
- this.single = selection.length !== 1
- this.multiple = !selection.length
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加${functionName}"
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
- get${BusinessName}(${pkColumn.javaField}).then(response => {
- this.form = response.data
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- this.form.$column.javaField = this.form.${column.javaField}.split(",")
-#end
-#end
-#if($table.sub)
- this.${subclassName}List = response.data.${subclassName}List
-#end
- this.open = true
- this.title = "修改${functionName}"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.#[[$]]#refs["form"].validate(valid => {
- if (valid) {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
- this.form.$column.javaField = this.form.${column.javaField}.join(",")
-#end
-#end
-#if($table.sub)
- this.form.${subclassName}List = this.${subclassName}List
-#end
- if (this.form.${pkColumn.javaField} != null) {
- update${BusinessName}(this.form).then(response => {
- this.#[[$modal]]#.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- add${BusinessName}(this.form).then(response => {
- this.#[[$modal]]#.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
- this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
- return del${BusinessName}(${pkColumn.javaField}s)
- }).then(() => {
- this.getList()
- this.#[[$modal]]#.msgSuccess("删除成功")
- }).catch(() => {})
- },
-#if($table.sub)
- /** ${subTable.functionName}序号 */
- row${subClassName}Index({ row, rowIndex }) {
- row.index = rowIndex + 1
- },
- /** ${subTable.functionName}添加按钮操作 */
- handleAdd${subClassName}() {
- let obj = {}
-#foreach($column in $subTable.columns)
-#if($column.pk || $column.javaField == ${subTableFkclassName})
-#elseif($column.list && "" != $javaField)
- obj.$column.javaField = ""
-#end
-#end
- this.${subclassName}List.push(obj)
- },
- /** ${subTable.functionName}删除按钮操作 */
- handleDelete${subClassName}() {
- if (this.checked${subClassName}.length == 0) {
- this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
- } else {
- const ${subclassName}List = this.${subclassName}List
- const checked${subClassName} = this.checked${subClassName}
- this.${subclassName}List = ${subclassName}List.filter(function(item) {
- return checked${subClassName}.indexOf(item.index) == -1
- })
- }
- },
- /** 复选框选中数据 */
- handle${subClassName}SelectionChange(selection) {
- this.checked${subClassName} = selection.map(item => item.index)
- },
-#end
-#if($genView)
- /** 详情按钮操作 */
- handleViewData(row) {
- this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
- },
-#end
- /** 导出按钮操作 */
- handleExport() {
- this.download('${moduleName}/${businessName}/export', {
- ...this.queryParams
- }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
- }
- }
-}
-</script>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm
deleted file mode 100644
index 84ce337..0000000
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm
+++ /dev/null
@@ -1,140 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
-
- <resultMap type="${ClassName}" id="${ClassName}Result">
-#foreach ($column in $columns)
- <result property="${column.javaField}" column="${column.columnName}" />
-#end
- </resultMap>
-#if($table.sub)
-
- <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
- <collection property="${subclassName}List" ofType="${subClassName}" column="${pkColumn.columnName}" select="select${subClassName}List" />
- </resultMap>
-
- <resultMap type="${subClassName}" id="${subClassName}Result">
-#foreach ($column in $subTable.columns)
- <result property="${column.javaField}" column="${column.columnName}" />
-#end
- </resultMap>
-#end
-
- <sql id="select${ClassName}Vo">
- select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
- </sql>
-
- <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
- <include refid="select${ClassName}Vo"/>
- <where>
-#foreach($column in $columns)
-#set($queryType=$column.queryType)
-#set($javaField=$column.javaField)
-#set($javaType=$column.javaType)
-#set($columnName=$column.columnName)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#if($column.query)
-#if($column.queryType == "EQ")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if>
-#elseif($queryType == "NE")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if>
-#elseif($queryType == "GT")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName > #{$javaField}</if>
-#elseif($queryType == "GTE")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName >= #{$javaField}</if>
-#elseif($queryType == "LT")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName < #{$javaField}</if>
-#elseif($queryType == "LTE")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName <= #{$javaField}</if>
-#elseif($queryType == "LIKE")
- <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if>
-#elseif($queryType == "BETWEEN")
- <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>
-#end
-#end
-#end
- </where>
- </select>
-
- <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
-#if($table.crud || $table.tree)
- <include refid="select${ClassName}Vo"/>
- where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-#elseif($table.sub)
- select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end
- from ${tableName}
- where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-#end
- </select>
-#if($table.sub)
-
- <select id="select${subClassName}List" resultMap="${subClassName}Result">
- select#foreach ($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end
- from ${subTableName}
- where ${subTableFkName} = #{${subTableFkName}}
- </select>
-#end
-
- <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
- insert into ${tableName}
- <trim prefix="(" suffix=")" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
- <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if>
-#end
-#end
- </trim>
- <trim prefix="values (" suffix=")" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
- <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if>
-#end
-#end
- </trim>
- </insert>
-
- <update id="update${ClassName}" parameterType="${ClassName}">
- update ${tableName}
- <trim prefix="SET" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName)
- <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if>
-#end
-#end
- </trim>
- where ${pkColumn.columnName} = #{${pkColumn.javaField}}
- </update>
-
- <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
- delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
- </delete>
-
- <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
- delete from ${tableName} where ${pkColumn.columnName} in
- <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
- #{${pkColumn.javaField}}
- </foreach>
- </delete>
-#if($table.sub)
-
- <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
- delete from ${subTableName} where ${subTableFkName} in
- <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
- #{${subTableFkclassName}}
- </foreach>
- </delete>
-
- <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}">
- delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
- </delete>
-
- <insert id="batch${subClassName}">
- insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
- <foreach item="item" index="index" collection="list" separator=",">
- (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
- </foreach>
- </insert>
-#end
-</mapper>
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java
deleted file mode 100644
index a5869e6..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/RuoYiJobApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.ruoyi.job;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import com.ruoyi.common.security.annotation.EnableCustomConfig;
-import com.ruoyi.common.security.annotation.EnableRyFeignClients;
-
-/**
- * 定时任务
- *
- * @author ruoyi
- */
-@EnableCustomConfig
-@EnableRyFeignClients
-@SpringBootApplication
-public class RuoYiJobApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiJobApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 定时任务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java
deleted file mode 100644
index ce86f2c..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/config/ScheduleConfig.java
+++ /dev/null
@@ -1,57 +0,0 @@
-//package com.ruoyi.job.config;
-//
-//import java.util.Properties;
-//import javax.sql.DataSource;
-//import org.springframework.context.annotation.Bean;
-//import org.springframework.context.annotation.Configuration;
-//import org.springframework.scheduling.quartz.SchedulerFactoryBean;
-//
-///**
-// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效)
-// *
-// * @author ruoyi
-// */
-//@Configuration
-//public class ScheduleConfig
-//{
-// @Bean
-// public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
-// {
-// SchedulerFactoryBean factory = new SchedulerFactoryBean();
-// factory.setDataSource(dataSource);
-//
-// // quartz参数
-// Properties prop = new Properties();
-// prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
-// prop.put("org.quartz.scheduler.instanceId", "AUTO");
-// // 线程池配置
-// prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
-// prop.put("org.quartz.threadPool.threadCount", "20");
-// prop.put("org.quartz.threadPool.threadPriority", "5");
-// // JobStore配置
-// prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
-// // 集群配置
-// prop.put("org.quartz.jobStore.isClustered", "true");
-// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
-// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
-// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
-//
-// // sqlserver 启用
-// // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
-// prop.put("org.quartz.jobStore.misfireThreshold", "12000");
-// prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
-// factory.setQuartzProperties(prop);
-//
-// factory.setSchedulerName("RuoyiScheduler");
-// // 延时启动
-// factory.setStartupDelay(1);
-// factory.setApplicationContextSchedulerContextKey("applicationContextKey");
-// // 可选,QuartzScheduler
-// // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
-// factory.setOverwriteExistingJobs(true);
-// // 设置自动启动,默认为true
-// factory.setAutoStartup(true);
-//
-// return factory;
-// }
-//}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java
deleted file mode 100644
index c1d4ad7..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobController.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.ruoyi.job.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.quartz.SchedulerException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.exception.job.TaskException;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.job.domain.SysJob;
-import com.ruoyi.job.service.ISysJobService;
-import com.ruoyi.job.util.CronUtils;
-import com.ruoyi.job.util.ScheduleUtils;
-
-/**
- * 调度任务信息操作处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/job")
-public class SysJobController extends BaseController
-{
- @Autowired
- private ISysJobService jobService;
-
- /**
- * 查询定时任务列表
- */
- @RequiresPermissions("monitor:job:list")
- @GetMapping("/list")
- public TableDataInfo list(SysJob sysJob)
- {
- startPage();
- List<SysJob> list = jobService.selectJobList(sysJob);
- return getDataTable(list);
- }
-
- /**
- * 导出定时任务列表
- */
- @RequiresPermissions("monitor:job:export")
- @Log(title = "定时任务", businessType = BusinessType.EXPORT)
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysJob sysJob)
- {
- List<SysJob> list = jobService.selectJobList(sysJob);
- ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
- util.exportExcel(response, list, "定时任务");
- }
-
- /**
- * 获取定时任务详细信息
- */
- @RequiresPermissions("monitor:job:query")
- @GetMapping(value = "/{jobId}")
- public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
- {
- return success(jobService.selectJobById(jobId));
- }
-
- /**
- * 新增定时任务
- */
- @RequiresPermissions("monitor:job:add")
- @Log(title = "定时任务", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
- {
- if (!CronUtils.isValid(job.getCronExpression()))
- {
- return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
- }
- else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
- {
- return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
- {
- return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
- {
- return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
- {
- return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
- }
- else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
- {
- return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
- }
- job.setCreateBy(SecurityUtils.getUsername());
- return toAjax(jobService.insertJob(job));
- }
-
- /**
- * 修改定时任务
- */
- @RequiresPermissions("monitor:job:edit")
- @Log(title = "定时任务", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
- {
- if (!CronUtils.isValid(job.getCronExpression()))
- {
- return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
- }
- else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
- {
- return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
- {
- return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
- {
- return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
- }
- else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
- {
- return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
- }
- else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
- {
- return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
- }
- job.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(jobService.updateJob(job));
- }
-
- /**
- * 定时任务状态修改
- */
- @RequiresPermissions("monitor:job:changeStatus")
- @Log(title = "定时任务", businessType = BusinessType.UPDATE)
- @PutMapping("/changeStatus")
- public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
- {
- SysJob newJob = jobService.selectJobById(job.getJobId());
- newJob.setStatus(job.getStatus());
- return toAjax(jobService.changeStatus(newJob));
- }
-
- /**
- * 定时任务立即执行一次
- */
- @RequiresPermissions("monitor:job:changeStatus")
- @Log(title = "定时任务", businessType = BusinessType.UPDATE)
- @PutMapping("/run")
- public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
- {
- boolean result = jobService.run(job);
- return result ? success() : error("任务不存在或已过期!");
- }
-
- /**
- * 删除定时任务
- */
- @RequiresPermissions("monitor:job:remove")
- @Log(title = "定时任务", businessType = BusinessType.DELETE)
- @DeleteMapping("/{jobIds}")
- public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException
- {
- jobService.deleteJobByIds(jobIds);
- return success();
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java
deleted file mode 100644
index 6c2f43c..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/controller/SysJobLogController.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.ruoyi.job.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.job.domain.SysJobLog;
-import com.ruoyi.job.service.ISysJobLogService;
-
-/**
- * 调度日志操作处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/job/log")
-public class SysJobLogController extends BaseController
-{
- @Autowired
- private ISysJobLogService jobLogService;
-
- /**
- * 查询定时任务调度日志列表
- */
- @RequiresPermissions("monitor:job:list")
- @GetMapping("/list")
- public TableDataInfo list(SysJobLog sysJobLog)
- {
- startPage();
- List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
- return getDataTable(list);
- }
-
- /**
- * 导出定时任务调度日志列表
- */
- @RequiresPermissions("monitor:job:export")
- @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysJobLog sysJobLog)
- {
- List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
- ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
- util.exportExcel(response, list, "调度日志");
- }
-
- /**
- * 根据调度编号获取详细信息
- */
- @RequiresPermissions("monitor:job:query")
- @GetMapping(value = "/{jobLogId}")
- public AjaxResult getInfo(@PathVariable Long jobLogId)
- {
- return success(jobLogService.selectJobLogById(jobLogId));
- }
-
- /**
- * 删除定时任务调度日志
- */
- @RequiresPermissions("monitor:job:remove")
- @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE)
- @DeleteMapping("/{jobLogIds}")
- public AjaxResult remove(@PathVariable Long[] jobLogIds)
- {
- return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
- }
-
- /**
- * 清空定时任务调度日志
- */
- @RequiresPermissions("monitor:job:remove")
- @Log(title = "调度日志", businessType = BusinessType.CLEAN)
- @DeleteMapping("/clean")
- public AjaxResult clean()
- {
- jobLogService.cleanJobLog();
- return success();
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java
deleted file mode 100644
index 5199ec6..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJob.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package com.ruoyi.job.domain;
-
-import java.util.Date;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.constant.ScheduleConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-import com.ruoyi.job.util.CronUtils;
-
-/**
- * 定时任务调度表 sys_job
- *
- * @author ruoyi
- */
-public class SysJob extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 任务ID */
- @Excel(name = "任务序号", cellType = ColumnType.NUMERIC)
- private Long jobId;
-
- /** 任务名称 */
- @Excel(name = "任务名称")
- private String jobName;
-
- /** 任务组名 */
- @Excel(name = "任务组名")
- private String jobGroup;
-
- /** 调用目标字符串 */
- @Excel(name = "调用目标字符串")
- private String invokeTarget;
-
- /** cron执行表达式 */
- @Excel(name = "执行表达式 ")
- private String cronExpression;
-
- /** cron计划策略 */
- @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
- private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
-
- /** 是否并发执行(0允许 1禁止) */
- @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止")
- private String concurrent;
-
- /** 任务状态(0正常 1暂停) */
- @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停")
- private String status;
-
- public Long getJobId()
- {
- return jobId;
- }
-
- public void setJobId(Long jobId)
- {
- this.jobId = jobId;
- }
-
- @NotBlank(message = "任务名称不能为空")
- @Size(min = 0, max = 64, message = "任务名称不能超过64个字符")
- public String getJobName()
- {
- return jobName;
- }
-
- public void setJobName(String jobName)
- {
- this.jobName = jobName;
- }
-
- public String getJobGroup()
- {
- return jobGroup;
- }
-
- public void setJobGroup(String jobGroup)
- {
- this.jobGroup = jobGroup;
- }
-
- @NotBlank(message = "调用目标字符串不能为空")
- @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符")
- public String getInvokeTarget()
- {
- return invokeTarget;
- }
-
- public void setInvokeTarget(String invokeTarget)
- {
- this.invokeTarget = invokeTarget;
- }
-
- @NotBlank(message = "Cron执行表达式不能为空")
- @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符")
- public String getCronExpression()
- {
- return cronExpression;
- }
-
- public void setCronExpression(String cronExpression)
- {
- this.cronExpression = cronExpression;
- }
-
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- public Date getNextValidTime()
- {
- if (StringUtils.isNotEmpty(cronExpression))
- {
- return CronUtils.getNextExecution(cronExpression);
- }
- return null;
- }
-
- public String getMisfirePolicy()
- {
- return misfirePolicy;
- }
-
- public void setMisfirePolicy(String misfirePolicy)
- {
- this.misfirePolicy = misfirePolicy;
- }
-
- public String getConcurrent()
- {
- return concurrent;
- }
-
- public void setConcurrent(String concurrent)
- {
- this.concurrent = concurrent;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("jobId", getJobId())
- .append("jobName", getJobName())
- .append("jobGroup", getJobGroup())
- .append("cronExpression", getCronExpression())
- .append("nextValidTime", getNextValidTime())
- .append("misfirePolicy", getMisfirePolicy())
- .append("concurrent", getConcurrent())
- .append("status", getStatus())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java
deleted file mode 100644
index 03445d6..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/domain/SysJobLog.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.ruoyi.job.domain;
-
-import java.util.Date;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 定时任务调度日志表 sys_job_log
- *
- * @author ruoyi
- */
-public class SysJobLog extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** ID */
- @Excel(name = "日志序号")
- private Long jobLogId;
-
- /** 任务名称 */
- @Excel(name = "任务名称")
- private String jobName;
-
- /** 任务组名 */
- @Excel(name = "任务组名")
- private String jobGroup;
-
- /** 调用目标字符串 */
- @Excel(name = "调用目标字符串")
- private String invokeTarget;
-
- /** 日志信息 */
- @Excel(name = "日志信息")
- private String jobMessage;
-
- /** 执行状态(0正常 1失败) */
- @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败")
- private String status;
-
- /** 异常信息 */
- @Excel(name = "异常信息")
- private String exceptionInfo;
-
- /** 开始时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date startTime;
-
- /** 结束时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date endTime;
-
- public Long getJobLogId()
- {
- return jobLogId;
- }
-
- public void setJobLogId(Long jobLogId)
- {
- this.jobLogId = jobLogId;
- }
-
- public String getJobName()
- {
- return jobName;
- }
-
- public void setJobName(String jobName)
- {
- this.jobName = jobName;
- }
-
- public String getJobGroup()
- {
- return jobGroup;
- }
-
- public void setJobGroup(String jobGroup)
- {
- this.jobGroup = jobGroup;
- }
-
- public String getInvokeTarget()
- {
- return invokeTarget;
- }
-
- public void setInvokeTarget(String invokeTarget)
- {
- this.invokeTarget = invokeTarget;
- }
-
- public String getJobMessage()
- {
- return jobMessage;
- }
-
- public void setJobMessage(String jobMessage)
- {
- this.jobMessage = jobMessage;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getExceptionInfo()
- {
- return exceptionInfo;
- }
-
- public void setExceptionInfo(String exceptionInfo)
- {
- this.exceptionInfo = exceptionInfo;
- }
-
- public Date getStartTime()
- {
- return startTime;
- }
-
- public void setStartTime(Date startTime)
- {
- this.startTime = startTime;
- }
-
- public Date getEndTime()
- {
- return endTime;
- }
-
- public void setEndTime(Date endTime)
- {
- this.endTime = endTime;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("jobLogId", getJobLogId())
- .append("jobName", getJobName())
- .append("jobGroup", getJobGroup())
- .append("jobMessage", getJobMessage())
- .append("status", getStatus())
- .append("exceptionInfo", getExceptionInfo())
- .append("startTime", getStartTime())
- .append("stopTime", getEndTime())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java
deleted file mode 100644
index 742eba5..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobLogMapper.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.ruoyi.job.mapper;
-
-import java.util.List;
-import com.ruoyi.job.domain.SysJobLog;
-
-/**
- * 调度任务日志信息 数据层
- *
- * @author ruoyi
- */
-public interface SysJobLogMapper
-{
- /**
- * 获取quartz调度器日志的计划任务
- *
- * @param jobLog 调度日志信息
- * @return 调度任务日志集合
- */
- public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
-
- /**
- * 查询所有调度任务日志
- *
- * @return 调度任务日志列表
- */
- public List<SysJobLog> selectJobLogAll();
-
- /**
- * 通过调度任务日志ID查询调度信息
- *
- * @param jobLogId 调度任务日志ID
- * @return 调度任务日志对象信息
- */
- public SysJobLog selectJobLogById(Long jobLogId);
-
- /**
- * 新增任务日志
- *
- * @param jobLog 调度日志信息
- * @return 结果
- */
- public int insertJobLog(SysJobLog jobLog);
-
- /**
- * 批量删除调度日志信息
- *
- * @param logIds 需要删除的数据ID
- * @return 结果
- */
- public int deleteJobLogByIds(Long[] logIds);
-
- /**
- * 删除任务日志
- *
- * @param jobId 调度日志ID
- * @return 结果
- */
- public int deleteJobLogById(Long jobId);
-
- /**
- * 清空任务日志
- */
- public void cleanJobLog();
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java
deleted file mode 100644
index 352fa87..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/mapper/SysJobMapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.ruoyi.job.mapper;
-
-import java.util.List;
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 调度任务信息 数据层
- *
- * @author ruoyi
- */
-public interface SysJobMapper
-{
- /**
- * 查询调度任务日志集合
- *
- * @param job 调度信息
- * @return 操作日志集合
- */
- public List<SysJob> selectJobList(SysJob job);
-
- /**
- * 查询所有调度任务
- *
- * @return 调度任务列表
- */
- public List<SysJob> selectJobAll();
-
- /**
- * 通过调度ID查询调度任务信息
- *
- * @param jobId 调度ID
- * @return 角色对象信息
- */
- public SysJob selectJobById(Long jobId);
-
- /**
- * 通过调度ID删除调度任务信息
- *
- * @param jobId 调度ID
- * @return 结果
- */
- public int deleteJobById(Long jobId);
-
- /**
- * 批量删除调度任务信息
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteJobByIds(Long[] ids);
-
- /**
- * 修改调度任务信息
- *
- * @param job 调度任务信息
- * @return 结果
- */
- public int updateJob(SysJob job);
-
- /**
- * 新增调度任务信息
- *
- * @param job 调度任务信息
- * @return 结果
- */
- public int insertJob(SysJob job);
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java
deleted file mode 100644
index 0e804e2..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobLogService.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.ruoyi.job.service;
-
-import java.util.List;
-import com.ruoyi.job.domain.SysJobLog;
-
-/**
- * 定时任务调度日志信息信息 服务层
- *
- * @author ruoyi
- */
-public interface ISysJobLogService
-{
- /**
- * 获取quartz调度器日志的计划任务
- *
- * @param jobLog 调度日志信息
- * @return 调度任务日志集合
- */
- public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
-
- /**
- * 通过调度任务日志ID查询调度信息
- *
- * @param jobLogId 调度任务日志ID
- * @return 调度任务日志对象信息
- */
- public SysJobLog selectJobLogById(Long jobLogId);
-
- /**
- * 新增任务日志
- *
- * @param jobLog 调度日志信息
- */
- public void addJobLog(SysJobLog jobLog);
-
- /**
- * 批量删除调度日志信息
- *
- * @param logIds 需要删除的日志ID
- * @return 结果
- */
- public int deleteJobLogByIds(Long[] logIds);
-
- /**
- * 删除任务日志
- *
- * @param jobId 调度日志ID
- * @return 结果
- */
- public int deleteJobLogById(Long jobId);
-
- /**
- * 清空任务日志
- */
- public void cleanJobLog();
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java
deleted file mode 100644
index ac43c71..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/ISysJobService.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.ruoyi.job.service;
-
-import java.util.List;
-import org.quartz.SchedulerException;
-import com.ruoyi.common.core.exception.job.TaskException;
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 定时任务调度信息信息 服务层
- *
- * @author ruoyi
- */
-public interface ISysJobService
-{
- /**
- * 获取quartz调度器的计划任务
- *
- * @param job 调度信息
- * @return 调度任务集合
- */
- public List<SysJob> selectJobList(SysJob job);
-
- /**
- * 通过调度任务ID查询调度信息
- *
- * @param jobId 调度任务ID
- * @return 调度任务对象信息
- */
- public SysJob selectJobById(Long jobId);
-
- /**
- * 暂停任务
- *
- * @param job 调度信息
- * @return 结果
- */
- public int pauseJob(SysJob job) throws SchedulerException;
-
- /**
- * 恢复任务
- *
- * @param job 调度信息
- * @return 结果
- */
- public int resumeJob(SysJob job) throws SchedulerException;
-
- /**
- * 删除任务后,所对应的trigger也将被删除
- *
- * @param job 调度信息
- * @return 结果
- */
- public int deleteJob(SysJob job) throws SchedulerException;
-
- /**
- * 批量删除调度信息
- *
- * @param jobIds 需要删除的任务ID
- * @return 结果
- */
- public void deleteJobByIds(Long[] jobIds) throws SchedulerException;
-
- /**
- * 任务调度状态修改
- *
- * @param job 调度信息
- * @return 结果
- */
- public int changeStatus(SysJob job) throws SchedulerException;
-
- /**
- * 立即运行任务
- *
- * @param job 调度信息
- * @return 结果
- */
- public boolean run(SysJob job) throws SchedulerException;
-
- /**
- * 新增任务
- *
- * @param job 调度信息
- * @return 结果
- */
- public int insertJob(SysJob job) throws SchedulerException, TaskException;
-
- /**
- * 更新任务
- *
- * @param job 调度信息
- * @return 结果
- */
- public int updateJob(SysJob job) throws SchedulerException, TaskException;
-
- /**
- * 校验cron表达式是否有效
- *
- * @param cronExpression 表达式
- * @return 结果
- */
- public boolean checkCronExpressionIsValid(String cronExpression);
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java
deleted file mode 100644
index 0886f31..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobLogServiceImpl.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.ruoyi.job.service;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.job.domain.SysJobLog;
-import com.ruoyi.job.mapper.SysJobLogMapper;
-
-/**
- * 定时任务调度日志信息 服务层
- *
- * @author ruoyi
- */
-@Service
-public class SysJobLogServiceImpl implements ISysJobLogService
-{
- @Autowired
- private SysJobLogMapper jobLogMapper;
-
- /**
- * 获取quartz调度器日志的计划任务
- *
- * @param jobLog 调度日志信息
- * @return 调度任务日志集合
- */
- @Override
- public List<SysJobLog> selectJobLogList(SysJobLog jobLog)
- {
- return jobLogMapper.selectJobLogList(jobLog);
- }
-
- /**
- * 通过调度任务日志ID查询调度信息
- *
- * @param jobLogId 调度任务日志ID
- * @return 调度任务日志对象信息
- */
- @Override
- public SysJobLog selectJobLogById(Long jobLogId)
- {
- return jobLogMapper.selectJobLogById(jobLogId);
- }
-
- /**
- * 新增任务日志
- *
- * @param jobLog 调度日志信息
- */
- @Override
- public void addJobLog(SysJobLog jobLog)
- {
- jobLogMapper.insertJobLog(jobLog);
- }
-
- /**
- * 批量删除调度日志信息
- *
- * @param logIds 需要删除的数据ID
- * @return 结果
- */
- @Override
- public int deleteJobLogByIds(Long[] logIds)
- {
- return jobLogMapper.deleteJobLogByIds(logIds);
- }
-
- /**
- * 删除任务日志
- *
- * @param jobId 调度日志ID
- */
- @Override
- public int deleteJobLogById(Long jobId)
- {
- return jobLogMapper.deleteJobLogById(jobId);
- }
-
- /**
- * 清空任务日志
- */
- @Override
- public void cleanJobLog()
- {
- jobLogMapper.cleanJobLog();
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java
deleted file mode 100644
index 45ad397..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/service/SysJobServiceImpl.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.ruoyi.job.service;
-
-import java.util.List;
-import jakarta.annotation.PostConstruct;
-import org.quartz.JobDataMap;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.core.constant.ScheduleConstants;
-import com.ruoyi.common.core.exception.job.TaskException;
-import com.ruoyi.job.domain.SysJob;
-import com.ruoyi.job.mapper.SysJobMapper;
-import com.ruoyi.job.util.CronUtils;
-import com.ruoyi.job.util.ScheduleUtils;
-
-/**
- * 定时任务调度信息 服务层
- *
- * @author ruoyi
- */
-@Service
-public class SysJobServiceImpl implements ISysJobService
-{
- @Autowired
- private Scheduler scheduler;
-
- @Autowired
- private SysJobMapper jobMapper;
-
- /**
- * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
- */
- @PostConstruct
- public void init() throws SchedulerException, TaskException
- {
- scheduler.clear();
- List<SysJob> jobList = jobMapper.selectJobAll();
- for (SysJob job : jobList)
- {
- ScheduleUtils.createScheduleJob(scheduler, job);
- }
- }
-
- /**
- * 获取quartz调度器的计划任务列表
- *
- * @param job 调度信息
- * @return
- */
- @Override
- public List<SysJob> selectJobList(SysJob job)
- {
- return jobMapper.selectJobList(job);
- }
-
- /**
- * 通过调度任务ID查询调度信息
- *
- * @param jobId 调度任务ID
- * @return 调度任务对象信息
- */
- @Override
- public SysJob selectJobById(Long jobId)
- {
- return jobMapper.selectJobById(jobId);
- }
-
- /**
- * 暂停任务
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int pauseJob(SysJob job) throws SchedulerException
- {
- Long jobId = job.getJobId();
- String jobGroup = job.getJobGroup();
- job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
- int rows = jobMapper.updateJob(job);
- if (rows > 0)
- {
- scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
- }
- return rows;
- }
-
- /**
- * 恢复任务
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int resumeJob(SysJob job) throws SchedulerException
- {
- Long jobId = job.getJobId();
- String jobGroup = job.getJobGroup();
- job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
- int rows = jobMapper.updateJob(job);
- if (rows > 0)
- {
- scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
- }
- return rows;
- }
-
- /**
- * 删除任务后,所对应的trigger也将被删除
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int deleteJob(SysJob job) throws SchedulerException
- {
- Long jobId = job.getJobId();
- String jobGroup = job.getJobGroup();
- int rows = jobMapper.deleteJobById(jobId);
- if (rows > 0)
- {
- scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
- }
- return rows;
- }
-
- /**
- * 批量删除调度信息
- *
- * @param jobIds 需要删除的任务ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void deleteJobByIds(Long[] jobIds) throws SchedulerException
- {
- for (Long jobId : jobIds)
- {
- SysJob job = jobMapper.selectJobById(jobId);
- deleteJob(job);
- }
- }
-
- /**
- * 任务调度状态修改
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int changeStatus(SysJob job) throws SchedulerException
- {
- int rows = 0;
- String status = job.getStatus();
- if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
- {
- rows = resumeJob(job);
- }
- else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
- {
- rows = pauseJob(job);
- }
- return rows;
- }
-
- /**
- * 立即运行任务
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public boolean run(SysJob job) throws SchedulerException
- {
- boolean result = false;
- Long jobId = job.getJobId();
- String jobGroup = job.getJobGroup();
- SysJob properties = selectJobById(job.getJobId());
- // 参数
- JobDataMap dataMap = new JobDataMap();
- dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
- JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
- if (scheduler.checkExists(jobKey))
- {
- result = true;
- scheduler.triggerJob(jobKey, dataMap);
- }
- return result;
- }
-
- /**
- * 新增任务
- *
- * @param job 调度信息 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int insertJob(SysJob job) throws SchedulerException, TaskException
- {
- job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
- int rows = jobMapper.insertJob(job);
- if (rows > 0)
- {
- ScheduleUtils.createScheduleJob(scheduler, job);
- }
- return rows;
- }
-
- /**
- * 更新任务的时间表达式
- *
- * @param job 调度信息
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int updateJob(SysJob job) throws SchedulerException, TaskException
- {
- SysJob properties = selectJobById(job.getJobId());
- int rows = jobMapper.updateJob(job);
- if (rows > 0)
- {
- updateSchedulerJob(job, properties.getJobGroup());
- }
- return rows;
- }
-
- /**
- * 更新任务
- *
- * @param job 任务对象
- * @param jobGroup 任务组名
- */
- public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException
- {
- Long jobId = job.getJobId();
- // 判断是否存在
- JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
- if (scheduler.checkExists(jobKey))
- {
- // 防止创建时存在数据问题 先移除,然后在执行创建操作
- scheduler.deleteJob(jobKey);
- }
- ScheduleUtils.createScheduleJob(scheduler, job);
- }
-
- /**
- * 校验cron表达式是否有效
- *
- * @param cronExpression 表达式
- * @return 结果
- */
- @Override
- public boolean checkCronExpressionIsValid(String cronExpression)
- {
- return CronUtils.isValid(cronExpression);
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java
deleted file mode 100644
index 01bd14a..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/task/RyTask.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.job.task;
-
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 定时任务调度测试
- *
- * @author ruoyi
- */
-@Component("ryTask")
-public class RyTask
-{
- public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
- {
- System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
- }
-
- public void ryParams(String params)
- {
- System.out.println("执行有参方法:" + params);
- }
-
- public void ryNoParams()
- {
- System.out.println("执行无参方法");
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java
deleted file mode 100644
index 5c6afa1..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/AbstractQuartzJob.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.ruoyi.job.util;
-
-import java.util.Date;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.core.constant.ScheduleConstants;
-import com.ruoyi.common.core.utils.ExceptionUtil;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.bean.BeanUtils;
-import com.ruoyi.job.domain.SysJob;
-import com.ruoyi.job.domain.SysJobLog;
-import com.ruoyi.job.service.ISysJobLogService;
-
-/**
- * 抽象quartz调用
- *
- * @author ruoyi
- */
-public abstract class AbstractQuartzJob implements Job
-{
- private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
-
- /**
- * 线程本地变量
- */
- private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
-
- @Override
- public void execute(JobExecutionContext context)
- {
- SysJob sysJob = new SysJob();
- BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
- try
- {
- before(context, sysJob);
- if (sysJob != null)
- {
- doExecute(context, sysJob);
- }
- after(context, sysJob, null);
- }
- catch (Exception e)
- {
- log.error("任务执行异常 - :", e);
- after(context, sysJob, e);
- }
- }
-
- /**
- * 执行前
- *
- * @param context 工作执行上下文对象
- * @param sysJob 系统计划任务
- */
- protected void before(JobExecutionContext context, SysJob sysJob)
- {
- threadLocal.set(new Date());
- }
-
- /**
- * 执行后
- *
- * @param context 工作执行上下文对象
- * @param sysJob 系统计划任务
- */
- protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
- {
- Date startTime = threadLocal.get();
- threadLocal.remove();
-
- final SysJobLog sysJobLog = new SysJobLog();
- sysJobLog.setJobName(sysJob.getJobName());
- sysJobLog.setJobGroup(sysJob.getJobGroup());
- sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
- sysJobLog.setStartTime(startTime);
- sysJobLog.setEndTime(new Date());
- long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime();
- sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
- if (e != null)
- {
- sysJobLog.setStatus("1");
- String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
- sysJobLog.setExceptionInfo(errorMsg);
- }
- else
- {
- sysJobLog.setStatus("0");
- }
-
- // 写入数据库当中
- SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
- }
-
- /**
- * 执行方法,由子类重载
- *
- * @param context 工作执行上下文对象
- * @param sysJob 系统计划任务
- * @throws Exception 执行过程中的异常
- */
- protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java
deleted file mode 100644
index 98a4147..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/CronUtils.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.ruoyi.job.util;
-
-import java.text.ParseException;
-import java.util.Date;
-import org.quartz.CronExpression;
-
-/**
- * cron表达式工具类
- *
- * @author ruoyi
- *
- */
-public class CronUtils
-{
- /**
- * 返回一个布尔值代表一个给定的Cron表达式的有效性
- *
- * @param cronExpression Cron表达式
- * @return boolean 表达式是否有效
- */
- public static boolean isValid(String cronExpression)
- {
- return CronExpression.isValidExpression(cronExpression);
- }
-
- /**
- * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
- *
- * @param cronExpression Cron表达式
- * @return String 无效时返回表达式错误描述,如果有效返回null
- */
- public static String getInvalidMessage(String cronExpression)
- {
- try
- {
- new CronExpression(cronExpression);
- return null;
- }
- catch (ParseException pe)
- {
- return pe.getMessage();
- }
- }
-
- /**
- * 返回下一个执行时间根据给定的Cron表达式
- *
- * @param cronExpression Cron表达式
- * @return Date 下次Cron表达式执行时间
- */
- public static Date getNextExecution(String cronExpression)
- {
- try
- {
- CronExpression cron = new CronExpression(cronExpression);
- return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
- }
- catch (ParseException e)
- {
- throw new IllegalArgumentException(e.getMessage());
- }
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java
deleted file mode 100644
index f1fda6e..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/JobInvokeUtil.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package com.ruoyi.job.util;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.List;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 任务执行工具
- *
- * @author ruoyi
- */
-public class JobInvokeUtil
-{
- /**
- * 执行方法
- *
- * @param sysJob 系统任务
- */
- public static void invokeMethod(SysJob sysJob) throws Exception
- {
- String invokeTarget = sysJob.getInvokeTarget();
- String beanName = getBeanName(invokeTarget);
- String methodName = getMethodName(invokeTarget);
- List<Object[]> methodParams = getMethodParams(invokeTarget);
-
- if (!isValidClassName(beanName))
- {
- Object bean = SpringUtils.getBean(beanName);
- invokeMethod(bean, methodName, methodParams);
- }
- else
- {
- Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
- invokeMethod(bean, methodName, methodParams);
- }
- }
-
- /**
- * 调用任务方法
- *
- * @param bean 目标对象
- * @param methodName 方法名称
- * @param methodParams 方法参数
- */
- private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
- throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
- InvocationTargetException
- {
- if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0)
- {
- Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
- method.invoke(bean, getMethodParamsValue(methodParams));
- }
- else
- {
- Method method = bean.getClass().getMethod(methodName);
- method.invoke(bean);
- }
- }
-
- /**
- * 校验是否为为class包名
- *
- * @param invokeTarget 名称
- * @return true是 false否
- */
- public static boolean isValidClassName(String invokeTarget)
- {
- return StringUtils.countMatches(invokeTarget, ".") > 1;
- }
-
- /**
- * 获取bean名称
- *
- * @param invokeTarget 目标字符串
- * @return bean名称
- */
- public static String getBeanName(String invokeTarget)
- {
- String beanName = StringUtils.substringBefore(invokeTarget, "(");
- return StringUtils.substringBeforeLast(beanName, ".");
- }
-
- /**
- * 获取bean方法
- *
- * @param invokeTarget 目标字符串
- * @return method方法
- */
- public static String getMethodName(String invokeTarget)
- {
- String methodName = StringUtils.substringBefore(invokeTarget, "(");
- return StringUtils.substringAfterLast(methodName, ".");
- }
-
- /**
- * 获取method方法参数相关列表
- *
- * @param invokeTarget 目标字符串
- * @return method方法相关参数列表
- */
- public static List<Object[]> getMethodParams(String invokeTarget)
- {
- String methodStr = StringUtils.substringBetweenLast(invokeTarget, "(", ")");
- if (StringUtils.isEmpty(methodStr))
- {
- return null;
- }
- String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
- List<Object[]> classs = new LinkedList<>();
- for (int i = 0; i < methodParams.length; i++)
- {
- String str = StringUtils.trimToEmpty(methodParams[i]);
- // String字符串类型,以'或"开头
- if (StringUtils.startsWithAny(str, "'", "\""))
- {
- classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });
- }
- // boolean布尔类型,等于true或者false
- else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
- {
- classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
- }
- // long长整形,以L结尾
- else if (StringUtils.endsWith(str, "L"))
- {
- classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
- }
- // double浮点类型,以D结尾
- else if (StringUtils.endsWith(str, "D"))
- {
- classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });
- }
- // 其他类型归类为整形
- else
- {
- classs.add(new Object[] { Integer.valueOf(str), Integer.class });
- }
- }
- return classs;
- }
-
- /**
- * 获取参数类型
- *
- * @param methodParams 参数相关列表
- * @return 参数类型列表
- */
- public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
- {
- Class<?>[] classs = new Class<?>[methodParams.size()];
- int index = 0;
- for (Object[] os : methodParams)
- {
- classs[index] = (Class<?>) os[1];
- index++;
- }
- return classs;
- }
-
- /**
- * 获取参数值
- *
- * @param methodParams 参数相关列表
- * @return 参数值列表
- */
- public static Object[] getMethodParamsValue(List<Object[]> methodParams)
- {
- Object[] classs = new Object[methodParams.size()];
- int index = 0;
- for (Object[] os : methodParams)
- {
- classs[index] = (Object) os[0];
- index++;
- }
- return classs;
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java
deleted file mode 100644
index 88e27d3..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzDisallowConcurrentExecution.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.job.util;
-
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.JobExecutionContext;
-
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 定时任务处理(禁止并发执行)
- *
- * @author ruoyi
- *
- */
-@DisallowConcurrentExecution
-public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
-{
- @Override
- protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
- {
- JobInvokeUtil.invokeMethod(sysJob);
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java
deleted file mode 100644
index 246b693..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/QuartzJobExecution.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.ruoyi.job.util;
-
-import org.quartz.JobExecutionContext;
-
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 定时任务处理(允许并发执行)
- *
- * @author ruoyi
- *
- */
-public class QuartzJobExecution extends AbstractQuartzJob
-{
- @Override
- protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
- {
- JobInvokeUtil.invokeMethod(sysJob);
- }
-}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java b/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java
deleted file mode 100644
index 175ad7b..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/java/com/ruoyi/job/util/ScheduleUtils.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.ruoyi.job.util;
-
-import org.quartz.CronScheduleBuilder;
-import org.quartz.CronTrigger;
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDetail;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.TriggerBuilder;
-import org.quartz.TriggerKey;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.ScheduleConstants;
-import com.ruoyi.common.core.exception.job.TaskException;
-import com.ruoyi.common.core.exception.job.TaskException.Code;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.job.domain.SysJob;
-
-/**
- * 定时任务工具类
- *
- * @author ruoyi
- *
- */
-public class ScheduleUtils
-{
- /**
- * 得到quartz任务类
- *
- * @param sysJob 执行计划
- * @return 具体执行任务类
- */
- private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)
- {
- boolean isConcurrent = "0".equals(sysJob.getConcurrent());
- return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
- }
-
- /**
- * 构建任务触发对象
- */
- public static TriggerKey getTriggerKey(Long jobId, String jobGroup)
- {
- return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
- }
-
- /**
- * 构建任务键对象
- */
- public static JobKey getJobKey(Long jobId, String jobGroup)
- {
- return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
- }
-
- /**
- * 创建定时任务
- */
- public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException
- {
- Class<? extends Job> jobClass = getQuartzJobClass(job);
- // 构建job信息
- Long jobId = job.getJobId();
- String jobGroup = job.getJobGroup();
- JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
-
- // 表达式调度构建器
- CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
- cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
-
- // 按新的cronExpression表达式构建一个新的trigger
- CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
- .withSchedule(cronScheduleBuilder).build();
-
- // 放入参数,运行时的方法可以获取
- jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
-
- // 判断是否存在
- if (scheduler.checkExists(getJobKey(jobId, jobGroup)))
- {
- // 防止创建时存在数据问题 先移除,然后在执行创建操作
- scheduler.deleteJob(getJobKey(jobId, jobGroup));
- }
-
- // 判断任务是否过期
- if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression())))
- {
- // 执行调度任务
- scheduler.scheduleJob(jobDetail, trigger);
- }
-
- // 暂停任务
- if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
- {
- scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
- }
- }
-
- /**
- * 设置定时任务策略
- */
- public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
- throws TaskException
- {
- switch (job.getMisfirePolicy())
- {
- case ScheduleConstants.MISFIRE_DEFAULT:
- return cb;
- case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
- return cb.withMisfireHandlingInstructionIgnoreMisfires();
- case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
- return cb.withMisfireHandlingInstructionFireAndProceed();
- case ScheduleConstants.MISFIRE_DO_NOTHING:
- return cb.withMisfireHandlingInstructionDoNothing();
- default:
- throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
- + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
- }
- }
-
- /**
- * 检查包名是否为白名单配置
- *
- * @param invokeTarget 目标字符串
- * @return 结果
- */
- public static boolean whiteList(String invokeTarget)
- {
- String packageName = StringUtils.substringBefore(invokeTarget, "(");
- int count = StringUtils.countMatches(packageName, ".");
- if (count > 1)
- {
- return StringUtils.startsWithAny(invokeTarget, Constants.JOB_WHITELIST_STR);
- }
- Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
- String beanPackageName = obj.getClass().getPackage().getName();
- return StringUtils.startsWithAny(beanPackageName, Constants.JOB_WHITELIST_STR)
- && !StringUtils.startsWithAny(beanPackageName, Constants.JOB_ERROR_STR);
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt
deleted file mode 100644
index 252407e..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _ _ _
- (_) (_) | |
- _ __ _ _ ___ _ _ _ ______ _ ___ | |__
-| '__|| | | | / _ \ | | | || ||______| | | / _ \ | '_ \
-| | | |_| || (_) || |_| || | | || (_) || |_) |
-|_| \__,_| \___/ \__, ||_| | | \___/ |_.__/
- __/ | _/ |
- |___/ |__/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml
deleted file mode 100644
index 5d7d3f5..0000000
--- a/ruoyi-modules/ruoyi-job/src/main/resources/logback.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true" scanPeriod="60 seconds" debug="false">
- <!-- 日志存放路径 -->
- <property name="log.path" value="logs/ruoyi-job" />
- <!-- 日志输出格式 -->
- <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
-
- <!-- 控制台输出 -->
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- </appender>
-
- <!-- 系统日志输出 -->
- <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/info.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>INFO</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/error.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>ERROR</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 系统模块日志级别控制 -->
- <logger name="com.ruoyi" level="info" />
- <!-- Spring日志级别控制 -->
- <logger name="org.springframework" level="warn" />
-
- <root level="info">
- <appender-ref ref="console" />
- </root>
-
- <!--系统操作日志-->
- <root level="info">
- <appender-ref ref="file_info" />
- <appender-ref ref="file_error" />
- </root>
-</configuration>
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java
deleted file mode 100644
index 3f33217..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/RuoYiSystemApplication.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.ruoyi.system;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import com.ruoyi.common.security.annotation.EnableCustomConfig;
-import com.ruoyi.common.security.annotation.EnableRyFeignClients;
-
-/**
- * 系统模块
- *
- * @author ruoyi
- */
-@EnableCustomConfig
-@EnableRyFeignClients
-@SpringBootApplication
-public class RuoYiSystemApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiSystemApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 系统模块启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java
deleted file mode 100644
index 120d58c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysConfigController.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.domain.SysConfig;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 参数配置 信息操作处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/config")
-public class SysConfigController extends BaseController
-{
- @Autowired
- private ISysConfigService configService;
-
- /**
- * 获取参数配置列表
- */
- @RequiresPermissions("system:config:list")
- @GetMapping("/list")
- public TableDataInfo list(SysConfig config)
- {
- startPage();
- List<SysConfig> list = configService.selectConfigList(config);
- return getDataTable(list);
- }
-
- @Log(title = "参数管理", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:config:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysConfig config)
- {
- List<SysConfig> list = configService.selectConfigList(config);
- ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
- util.exportExcel(response, list, "参数数据");
- }
-
- /**
- * 根据参数编号获取详细信息
- */
- @GetMapping(value = "/{configId}")
- public AjaxResult getInfo(@PathVariable Long configId)
- {
- return success(configService.selectConfigById(configId));
- }
-
- /**
- * 根据参数键名查询参数值
- */
- @GetMapping(value = "/configKey/{configKey}")
- public AjaxResult getConfigKey(@PathVariable String configKey)
- {
- return success(configService.selectConfigByKey(configKey));
- }
-
- /**
- * 新增参数配置
- */
- @RequiresPermissions("system:config:add")
- @Log(title = "参数管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysConfig config)
- {
- if (!configService.checkConfigKeyUnique(config))
- {
- return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
- }
- config.setCreateBy(SecurityUtils.getUsername());
- return toAjax(configService.insertConfig(config));
- }
-
- /**
- * 修改参数配置
- */
- @RequiresPermissions("system:config:edit")
- @Log(title = "参数管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysConfig config)
- {
- if (!configService.checkConfigKeyUnique(config))
- {
- return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
- }
- config.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(configService.updateConfig(config));
- }
-
- /**
- * 删除参数配置
- */
- @RequiresPermissions("system:config:remove")
- @Log(title = "参数管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{configIds}")
- public AjaxResult remove(@PathVariable Long[] configIds)
- {
- configService.deleteConfigByIds(configIds);
- return success();
- }
-
- /**
- * 刷新参数缓存
- */
- @RequiresPermissions("system:config:remove")
- @Log(title = "参数管理", businessType = BusinessType.CLEAN)
- @DeleteMapping("/refreshCache")
- public AjaxResult refreshCache()
- {
- configService.resetConfigCache();
- return success();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java
deleted file mode 100644
index 97cb935..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDeptController.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.service.ISysDeptService;
-
-/**
- * 部门信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/dept")
-public class SysDeptController extends BaseController
-{
- @Autowired
- private ISysDeptService deptService;
-
- /**
- * 获取部门列表
- */
- @RequiresPermissions("system:dept:list")
- @GetMapping("/list")
- public AjaxResult list(SysDept dept)
- {
- List<SysDept> depts = deptService.selectDeptList(dept);
- return success(depts);
- }
-
- /**
- * 查询部门列表(排除节点)
- */
- @RequiresPermissions("system:dept:list")
- @GetMapping("/list/exclude/{deptId}")
- public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
- {
- List<SysDept> depts = deptService.selectDeptList(new SysDept());
- depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
- return success(depts);
- }
-
- /**
- * 根据部门编号获取详细信息
- */
- @RequiresPermissions("system:dept:query")
- @GetMapping(value = "/{deptId}")
- public AjaxResult getInfo(@PathVariable Long deptId)
- {
- deptService.checkDeptDataScope(deptId);
- return success(deptService.selectDeptById(deptId));
- }
-
- /**
- * 新增部门
- */
- @RequiresPermissions("system:dept:add")
- @Log(title = "部门管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysDept dept)
- {
- if (!deptService.checkDeptNameUnique(dept))
- {
- return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
- }
- dept.setCreateBy(SecurityUtils.getUsername());
- return toAjax(deptService.insertDept(dept));
- }
-
- /**
- * 修改部门
- */
- @RequiresPermissions("system:dept:edit")
- @Log(title = "部门管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysDept dept)
- {
- Long deptId = dept.getDeptId();
- deptService.checkDeptDataScope(deptId);
- if (!deptService.checkDeptNameUnique(dept))
- {
- return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
- }
- else if (dept.getParentId().equals(deptId))
- {
- return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
- }
- else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
- {
- return error("该部门包含未停用的子部门!");
- }
- dept.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(deptService.updateDept(dept));
- }
-
- /**
- * 保存部门排序
- */
- @RequiresPermissions("system:dept:edit")
- @Log(title = "保存部门排序", businessType = BusinessType.UPDATE)
- @PutMapping("/updateSort")
- public AjaxResult updateSort(@RequestBody Map<String, String> params)
- {
- String[] deptIds = params.get("deptIds").split(",");
- String[] orderNums = params.get("orderNums").split(",");
- deptService.updateDeptSort(deptIds, orderNums);
- return success();
- }
-
- /**
- * 删除部门
- */
- @RequiresPermissions("system:dept:remove")
- @Log(title = "部门管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{deptId}")
- public AjaxResult remove(@PathVariable Long deptId)
- {
- if (deptService.hasChildByDeptId(deptId))
- {
- return warn("存在下级部门,不允许删除");
- }
- if (deptService.checkDeptExistUser(deptId))
- {
- return warn("部门存在用户,不允许删除");
- }
- deptService.checkDeptDataScope(deptId);
- return toAjax(deptService.deleteDeptById(deptId));
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java
deleted file mode 100644
index 4e2acf9..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictDataController.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.ArrayList;
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDictData;
-import com.ruoyi.system.service.ISysDictDataService;
-import com.ruoyi.system.service.ISysDictTypeService;
-
-/**
- * 数据字典信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/dict/data")
-public class SysDictDataController extends BaseController
-{
- @Autowired
- private ISysDictDataService dictDataService;
-
- @Autowired
- private ISysDictTypeService dictTypeService;
-
- @RequiresPermissions("system:dict:list")
- @GetMapping("/list")
- public TableDataInfo list(SysDictData dictData)
- {
- startPage();
- List<SysDictData> list = dictDataService.selectDictDataList(dictData);
- return getDataTable(list);
- }
-
- @Log(title = "字典数据", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:dict:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysDictData dictData)
- {
- List<SysDictData> list = dictDataService.selectDictDataList(dictData);
- ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
- util.exportExcel(response, list, "字典数据");
- }
-
- /**
- * 查询字典数据详细
- */
- @RequiresPermissions("system:dict:query")
- @GetMapping(value = "/{dictCode}")
- public AjaxResult getInfo(@PathVariable Long dictCode)
- {
- return success(dictDataService.selectDictDataById(dictCode));
- }
-
- /**
- * 根据字典类型查询字典数据信息
- */
- @GetMapping(value = "/type/{dictType}")
- public AjaxResult dictType(@PathVariable String dictType)
- {
- List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
- if (StringUtils.isNull(data))
- {
- data = new ArrayList<SysDictData>();
- }
- return success(data);
- }
-
- /**
- * 新增字典类型
- */
- @RequiresPermissions("system:dict:add")
- @Log(title = "字典数据", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysDictData dict)
- {
- dict.setCreateBy(SecurityUtils.getUsername());
- return toAjax(dictDataService.insertDictData(dict));
- }
-
- /**
- * 修改保存字典类型
- */
- @RequiresPermissions("system:dict:edit")
- @Log(title = "字典数据", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysDictData dict)
- {
- dict.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(dictDataService.updateDictData(dict));
- }
-
- /**
- * 删除字典类型
- */
- @RequiresPermissions("system:dict:remove")
- @Log(title = "字典类型", businessType = BusinessType.DELETE)
- @DeleteMapping("/{dictCodes}")
- public AjaxResult remove(@PathVariable Long[] dictCodes)
- {
- dictDataService.deleteDictDataByIds(dictCodes);
- return success();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java
deleted file mode 100644
index 5a4d3ec..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysDictTypeController.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDictType;
-import com.ruoyi.system.service.ISysDictTypeService;
-
-/**
- * 数据字典信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/dict/type")
-public class SysDictTypeController extends BaseController
-{
- @Autowired
- private ISysDictTypeService dictTypeService;
-
- @RequiresPermissions("system:dict:list")
- @GetMapping("/list")
- public TableDataInfo list(SysDictType dictType)
- {
- startPage();
- List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
- return getDataTable(list);
- }
-
- @Log(title = "字典类型", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:dict:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysDictType dictType)
- {
- List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
- ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
- util.exportExcel(response, list, "字典类型");
- }
-
- /**
- * 查询字典类型详细
- */
- @RequiresPermissions("system:dict:query")
- @GetMapping(value = "/{dictId}")
- public AjaxResult getInfo(@PathVariable Long dictId)
- {
- return success(dictTypeService.selectDictTypeById(dictId));
- }
-
- /**
- * 新增字典类型
- */
- @RequiresPermissions("system:dict:add")
- @Log(title = "字典类型", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysDictType dict)
- {
- if (!dictTypeService.checkDictTypeUnique(dict))
- {
- return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
- }
- dict.setCreateBy(SecurityUtils.getUsername());
- return toAjax(dictTypeService.insertDictType(dict));
- }
-
- /**
- * 修改字典类型
- */
- @RequiresPermissions("system:dict:edit")
- @Log(title = "字典类型", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysDictType dict)
- {
- if (!dictTypeService.checkDictTypeUnique(dict))
- {
- return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
- }
- dict.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(dictTypeService.updateDictType(dict));
- }
-
- /**
- * 删除字典类型
- */
- @RequiresPermissions("system:dict:remove")
- @Log(title = "字典类型", businessType = BusinessType.DELETE)
- @DeleteMapping("/{dictIds}")
- public AjaxResult remove(@PathVariable Long[] dictIds)
- {
- dictTypeService.deleteDictTypeByIds(dictIds);
- return success();
- }
-
- /**
- * 刷新字典缓存
- */
- @RequiresPermissions("system:dict:remove")
- @Log(title = "字典类型", businessType = BusinessType.CLEAN)
- @DeleteMapping("/refreshCache")
- public AjaxResult refreshCache()
- {
- dictTypeService.resetDictCache();
- return success();
- }
-
- /**
- * 获取字典选择框列表
- */
- @GetMapping("/optionselect")
- public AjaxResult optionselect()
- {
- List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
- return success(dictTypes);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java
deleted file mode 100644
index 1aa2ec8..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysLogininforController.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.common.security.annotation.InnerAuth;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.system.api.domain.SysLogininfor;
-import com.ruoyi.system.service.ISysLogininforService;
-
-/**
- * 系统访问记录
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/logininfor")
-public class SysLogininforController extends BaseController
-{
- @Autowired
- private ISysLogininforService logininforService;
-
- @Autowired
- private RedisService redisService;
-
- @RequiresPermissions("system:logininfor:list")
- @GetMapping("/list")
- public TableDataInfo list(SysLogininfor logininfor)
- {
- startPage();
- List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
- return getDataTable(list);
- }
-
- @Log(title = "登录日志", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:logininfor:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysLogininfor logininfor)
- {
- List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
- ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
- util.exportExcel(response, list, "登录日志");
- }
-
- @RequiresPermissions("system:logininfor:remove")
- @Log(title = "登录日志", businessType = BusinessType.DELETE)
- @DeleteMapping("/{infoIds}")
- public AjaxResult remove(@PathVariable Long[] infoIds)
- {
- return toAjax(logininforService.deleteLogininforByIds(infoIds));
- }
-
- @RequiresPermissions("system:logininfor:remove")
- @Log(title = "登录日志", businessType = BusinessType.DELETE)
- @DeleteMapping("/clean")
- public AjaxResult clean()
- {
- logininforService.cleanLogininfor();
- return success();
- }
-
- @RequiresPermissions("system:logininfor:unlock")
- @Log(title = "账户解锁", businessType = BusinessType.OTHER)
- @GetMapping("/unlock/{userName}")
- public AjaxResult unlock(@PathVariable("userName") String userName)
- {
- redisService.deleteObject(CacheConstants.PWD_ERR_CNT_KEY + userName);
- return success();
- }
-
- @InnerAuth
- @PostMapping
- public AjaxResult add(@RequestBody SysLogininfor logininfor)
- {
- return toAjax(logininforService.insertLogininfor(logininfor));
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java
deleted file mode 100644
index 44b15cb..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysMenuController.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import java.util.Map;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.domain.SysMenu;
-import com.ruoyi.system.service.ISysMenuService;
-
-/**
- * 菜单信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/menu")
-public class SysMenuController extends BaseController
-{
- @Autowired
- private ISysMenuService menuService;
-
- /**
- * 获取菜单列表
- */
- @RequiresPermissions("system:menu:list")
- @GetMapping("/list")
- public AjaxResult list(SysMenu menu)
- {
- Long userId = SecurityUtils.getUserId();
- List<SysMenu> menus = menuService.selectMenuList(menu, userId);
- return success(menus);
- }
-
- /**
- * 根据菜单编号获取详细信息
- */
- @RequiresPermissions("system:menu:query")
- @GetMapping(value = "/{menuId}")
- public AjaxResult getInfo(@PathVariable Long menuId)
- {
- return success(menuService.selectMenuById(menuId));
- }
-
- /**
- * 获取菜单下拉树列表
- */
- @GetMapping("/treeselect")
- public AjaxResult treeselect(SysMenu menu)
- {
- Long userId = SecurityUtils.getUserId();
- List<SysMenu> menus = menuService.selectMenuList(menu, userId);
- return success(menuService.buildMenuTreeSelect(menus));
- }
-
- /**
- * 加载对应角色菜单列表树
- */
- @GetMapping(value = "/roleMenuTreeselect/{roleId}")
- public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
- {
- Long userId = SecurityUtils.getUserId();
- List<SysMenu> menus = menuService.selectMenuList(userId);
- AjaxResult ajax = AjaxResult.success();
- ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
- ajax.put("menus", menuService.buildMenuTreeSelect(menus));
- return ajax;
- }
-
- /**
- * 新增菜单
- */
- @RequiresPermissions("system:menu:add")
- @Log(title = "菜单管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysMenu menu)
- {
- if (!menuService.checkMenuNameUnique(menu))
- {
- return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
- }
- else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
- {
- return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
- }
- else if (!menuService.checkRouteConfigUnique(menu))
- {
- return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
- }
- menu.setCreateBy(SecurityUtils.getUsername());
- return toAjax(menuService.insertMenu(menu));
- }
-
- /**
- * 修改菜单
- */
- @RequiresPermissions("system:menu:edit")
- @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysMenu menu)
- {
- if (!menuService.checkMenuNameUnique(menu))
- {
- return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
- }
- else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
- {
- return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
- }
- else if (menu.getMenuId().equals(menu.getParentId()))
- {
- return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
- }
- else if (!menuService.checkRouteConfigUnique(menu))
- {
- return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
- }
- menu.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(menuService.updateMenu(menu));
- }
-
- /**
- * 保存菜单排序
- */
- @RequiresPermissions("system:menu:edit")
- @Log(title = "保存菜单排序", businessType = BusinessType.UPDATE)
- @PutMapping("/updateSort")
- public AjaxResult updateSort(@RequestBody Map<String, String> params)
- {
- String[] menuIds = params.get("menuIds").split(",");
- String[] orderNums = params.get("orderNums").split(",");
- menuService.updateMenuSort(menuIds, orderNums);
- return success();
- }
-
- /**
- * 删除菜单
- */
- @RequiresPermissions("system:menu:remove")
- @Log(title = "菜单管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{menuId}")
- public AjaxResult remove(@PathVariable("menuId") Long menuId)
- {
- if (menuService.hasChildByMenuId(menuId))
- {
- return warn("存在子菜单,不允许删除");
- }
- if (menuService.checkMenuExistRole(menuId))
- {
- return warn("菜单已分配,不允许删除");
- }
- return toAjax(menuService.deleteMenuById(menuId));
- }
-
- /**
- * 获取路由信息
- *
- * @return 路由信息
- */
- @GetMapping("getRouters")
- public AjaxResult getRouters()
- {
- Long userId = SecurityUtils.getUserId();
- List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
- return success(menuService.buildMenus(menus));
- }
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java
deleted file mode 100644
index 3ae141a..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysNoticeController.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.system.service.ISysNoticeReadService;
-import com.ruoyi.system.service.ISysNoticeService;
-
-/**
- * 公告 信息操作处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/notice")
-public class SysNoticeController extends BaseController
-{
- @Autowired
- private ISysNoticeService noticeService;
-
- @Autowired
- private ISysNoticeReadService noticeReadService;
-
- /**
- * 获取通知公告列表
- */
- @RequiresPermissions("system:notice:list")
- @GetMapping("/list")
- public TableDataInfo list(SysNotice notice)
- {
- startPage();
- List<SysNotice> list = noticeService.selectNoticeList(notice);
- return getDataTable(list);
- }
-
- /**
- * 根据通知公告编号获取详细信息
- */
- @GetMapping(value = "/{noticeId}")
- public AjaxResult getInfo(@PathVariable Long noticeId)
- {
- return success(noticeService.selectNoticeById(noticeId));
- }
-
- /**
- * 新增通知公告
- */
- @RequiresPermissions("system:notice:add")
- @Log(title = "通知公告", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysNotice notice)
- {
- notice.setCreateBy(SecurityUtils.getUsername());
- return toAjax(noticeService.insertNotice(notice));
- }
-
- /**
- * 修改通知公告
- */
- @RequiresPermissions("system:notice:edit")
- @Log(title = "通知公告", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysNotice notice)
- {
- notice.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(noticeService.updateNotice(notice));
- }
-
- /**
- * 首页顶部公告列表(返回全部正常公告,带当前用户已读标记,最多5条)
- */
- @GetMapping("/listTop")
- @ResponseBody
- public AjaxResult listTop()
- {
- Long userId = SecurityUtils.getUserId();
- List<SysNotice> list = noticeReadService.selectNoticeListWithReadStatus(userId, 5);
- long unreadCount = list.stream().filter(n -> !n.getIsRead()).count();
- AjaxResult result = AjaxResult.success(list);
- result.put("unreadCount", unreadCount);
- return result;
- }
-
- /**
- * 标记公告已读
- */
- @PostMapping("/markRead")
- @ResponseBody
- public AjaxResult markRead(Long noticeId)
- {
- Long userId = SecurityUtils.getUserId();
- noticeReadService.markRead(noticeId, userId);
- return success();
- }
-
- /**
- * 批量标记已读
- */
- @PostMapping("/markReadAll")
- @ResponseBody
- public AjaxResult markReadAll(String ids)
- {
- Long userId = SecurityUtils.getUserId();
- Long[] noticeIds = Convert.toLongArray(ids);
- noticeReadService.markReadBatch(userId, noticeIds);
- return success();
- }
-
- /**
- * 已读用户列表数据
- */
- @RequiresPermissions("system:notice:list")
- @GetMapping("/readUsers/list")
- @ResponseBody
- public TableDataInfo readUsersList(Long noticeId, String searchValue)
- {
- startPage();
- List<?> list = noticeReadService.selectReadUsersByNoticeId(noticeId, searchValue);
- return getDataTable(list);
- }
-
- /**
- * 删除通知公告
- */
- @RequiresPermissions("system:notice:remove")
- @Log(title = "通知公告", businessType = BusinessType.DELETE)
- @DeleteMapping("/{noticeIds}")
- public AjaxResult remove(@PathVariable Long[] noticeIds)
- {
- noticeReadService.deleteByNoticeIds(noticeIds);
- return toAjax(noticeService.deleteNoticeByIds(noticeIds));
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java
deleted file mode 100644
index 5a3f129..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysOperlogController.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.InnerAuth;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.system.api.domain.SysOperLog;
-import com.ruoyi.system.service.ISysOperLogService;
-
-/**
- * 操作日志记录
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/operlog")
-public class SysOperlogController extends BaseController
-{
- @Autowired
- private ISysOperLogService operLogService;
-
- @RequiresPermissions("system:operlog:list")
- @GetMapping("/list")
- public TableDataInfo list(SysOperLog operLog)
- {
- startPage();
- List<SysOperLog> list = operLogService.selectOperLogList(operLog);
- return getDataTable(list);
- }
-
- @Log(title = "操作日志", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:operlog:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysOperLog operLog)
- {
- List<SysOperLog> list = operLogService.selectOperLogList(operLog);
- ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
- util.exportExcel(response, list, "操作日志");
- }
-
- @Log(title = "操作日志", businessType = BusinessType.DELETE)
- @RequiresPermissions("system:operlog:remove")
- @DeleteMapping("/{operIds}")
- public AjaxResult remove(@PathVariable Long[] operIds)
- {
- return toAjax(operLogService.deleteOperLogByIds(operIds));
- }
-
- @RequiresPermissions("system:operlog:remove")
- @Log(title = "操作日志", businessType = BusinessType.CLEAN)
- @DeleteMapping("/clean")
- public AjaxResult clean()
- {
- operLogService.cleanOperLog();
- return success();
- }
-
- @InnerAuth
- @PostMapping
- public AjaxResult add(@RequestBody SysOperLog operLog)
- {
- return toAjax(operLogService.insertOperlog(operLog));
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java
deleted file mode 100644
index 98e1e65..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysPostController.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.system.service.ISysPostService;
-
-/**
- * 岗位信息操作处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/post")
-public class SysPostController extends BaseController
-{
- @Autowired
- private ISysPostService postService;
-
- /**
- * 获取岗位列表
- */
- @RequiresPermissions("system:post:list")
- @GetMapping("/list")
- public TableDataInfo list(SysPost post)
- {
- startPage();
- List<SysPost> list = postService.selectPostList(post);
- return getDataTable(list);
- }
-
- @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:post:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysPost post)
- {
- List<SysPost> list = postService.selectPostList(post);
- ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
- util.exportExcel(response, list, "岗位数据");
- }
-
- /**
- * 根据岗位编号获取详细信息
- */
- @RequiresPermissions("system:post:query")
- @GetMapping(value = "/{postId}")
- public AjaxResult getInfo(@PathVariable Long postId)
- {
- return success(postService.selectPostById(postId));
- }
-
- /**
- * 新增岗位
- */
- @RequiresPermissions("system:post:add")
- @Log(title = "岗位管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysPost post)
- {
- if (!postService.checkPostNameUnique(post))
- {
- return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
- }
- else if (!postService.checkPostCodeUnique(post))
- {
- return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
- }
- post.setCreateBy(SecurityUtils.getUsername());
- return toAjax(postService.insertPost(post));
- }
-
- /**
- * 修改岗位
- */
- @RequiresPermissions("system:post:edit")
- @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysPost post)
- {
- if (!postService.checkPostNameUnique(post))
- {
- return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
- }
- else if (!postService.checkPostCodeUnique(post))
- {
- return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
- }
- post.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(postService.updatePost(post));
- }
-
- /**
- * 删除岗位
- */
- @RequiresPermissions("system:post:remove")
- @Log(title = "岗位管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{postIds}")
- public AjaxResult remove(@PathVariable Long[] postIds)
- {
- return toAjax(postService.deletePostByIds(postIds));
- }
-
- /**
- * 获取岗位选择框列表
- */
- @GetMapping("/optionselect")
- public AjaxResult optionselect()
- {
- List<SysPost> posts = postService.selectPostAll();
- return success(posts);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java
deleted file mode 100644
index 83aab06..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysProfileController.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.Arrays;
-import java.util.Map;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.file.FileTypeUtils;
-import com.ruoyi.common.core.utils.file.MimeTypeUtils;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.service.TokenService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.RemoteFileService;
-import com.ruoyi.system.api.domain.SysFile;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.model.LoginUser;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 个人信息 业务处理
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/user/profile")
-public class SysProfileController extends BaseController
-{
- @Autowired
- private ISysUserService userService;
-
- @Autowired
- private TokenService tokenService;
-
- @Autowired
- private RemoteFileService remoteFileService;
-
- /**
- * 个人信息
- */
- @GetMapping
- public AjaxResult profile()
- {
- String username = SecurityUtils.getUsername();
- SysUser user = userService.selectUserByUserName(username);
- AjaxResult ajax = AjaxResult.success(user);
- ajax.put("roleGroup", userService.selectUserRoleGroup(username));
- ajax.put("postGroup", userService.selectUserPostGroup(username));
- return ajax;
- }
-
- /**
- * 修改用户
- */
- @Log(title = "个人信息", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult updateProfile(@RequestBody SysUser user)
- {
- LoginUser loginUser = SecurityUtils.getLoginUser();
- SysUser currentUser = loginUser.getSysUser();
- currentUser.setNickName(user.getNickName());
- currentUser.setEmail(user.getEmail());
- currentUser.setPhonenumber(user.getPhonenumber());
- currentUser.setSex(user.getSex());
- if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
- {
- return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
- }
- if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
- {
- return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
- }
- if (userService.updateUserProfile(currentUser))
- {
- // 更新缓存用户信息
- tokenService.setLoginUser(loginUser);
- return success();
- }
- return error("修改个人信息异常,请联系管理员");
- }
-
- /**
- * 重置密码
- */
- @Log(title = "个人信息", businessType = BusinessType.UPDATE)
- @PutMapping("/updatePwd")
- public AjaxResult updatePwd(@RequestBody Map<String, String> params)
- {
- String oldPassword = params.get("oldPassword");
- String newPassword = params.get("newPassword");
- LoginUser loginUser = SecurityUtils.getLoginUser();
- Long userId = loginUser.getUserid();
- String password = loginUser.getSysUser().getPassword();
- if (!SecurityUtils.matchesPassword(oldPassword, password))
- {
- return error("修改密码失败,旧密码错误");
- }
- if (SecurityUtils.matchesPassword(newPassword, password))
- {
- return error("新密码不能与旧密码相同");
- }
- newPassword = SecurityUtils.encryptPassword(newPassword);
- if (userService.resetUserPwd(userId, newPassword) > 0)
- {
- // 更新缓存用户密码&密码最后更新时间
- loginUser.getSysUser().setPwdUpdateDate(DateUtils.getNowDate());
- loginUser.getSysUser().setPassword(newPassword);
- tokenService.setLoginUser(loginUser);
- return success();
- }
- return error("修改密码异常,请联系管理员");
- }
-
- /**
- * 头像上传
- */
- @Log(title = "用户头像", businessType = BusinessType.UPDATE)
- @PostMapping("/avatar")
- public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file)
- {
- if (!file.isEmpty())
- {
- LoginUser loginUser = SecurityUtils.getLoginUser();
- String extension = FileTypeUtils.getExtension(file);
- if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION))
- {
- return error("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式");
- }
- R<SysFile> fileResult = remoteFileService.upload(file);
- if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData()))
- {
- return error("文件服务异常,请联系管理员");
- }
- String url = fileResult.getData().getUrl();
- if (userService.updateUserAvatar(loginUser.getUserid(), url))
- {
- String oldAvatarUrl = loginUser.getSysUser().getAvatar();
- if (StringUtils.isNotEmpty(oldAvatarUrl))
- {
- remoteFileService.delete(oldAvatarUrl);
- }
- AjaxResult ajax = AjaxResult.success();
- ajax.put("imgUrl", url);
- // 更新缓存用户头像
- loginUser.getSysUser().setAvatar(url);
- tokenService.setLoginUser(loginUser);
- return ajax;
- }
- }
- return error("上传图片异常,请联系管理员");
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
deleted file mode 100644
index b016d04..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysRoleController.java
+++ /dev/null
@@ -1,239 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.List;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysRoleService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 角色信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/role")
-public class SysRoleController extends BaseController
-{
- @Autowired
- private ISysRoleService roleService;
-
- @Autowired
- private ISysUserService userService;
-
- @Autowired
- private ISysDeptService deptService;
-
- @RequiresPermissions("system:role:list")
- @GetMapping("/list")
- public TableDataInfo list(SysRole role)
- {
- startPage();
- List<SysRole> list = roleService.selectRoleList(role);
- return getDataTable(list);
- }
-
- @Log(title = "角色管理", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:role:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysRole role)
- {
- List<SysRole> list = roleService.selectRoleList(role);
- ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
- util.exportExcel(response, list, "角色数据");
- }
-
- /**
- * 根据角色编号获取详细信息
- */
- @RequiresPermissions("system:role:query")
- @GetMapping(value = "/{roleId}")
- public AjaxResult getInfo(@PathVariable Long roleId)
- {
- roleService.checkRoleDataScope(roleId);
- return success(roleService.selectRoleById(roleId));
- }
-
- /**
- * 新增角色
- */
- @RequiresPermissions("system:role:add")
- @Log(title = "角色管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysRole role)
- {
- if (!roleService.checkRoleNameUnique(role))
- {
- return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
- }
- else if (!roleService.checkRoleKeyUnique(role))
- {
- return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
- }
- role.setCreateBy(SecurityUtils.getUsername());
- return toAjax(roleService.insertRole(role));
-
- }
-
- /**
- * 修改保存角色
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysRole role)
- {
- roleService.checkRoleAllowed(role);
- roleService.checkRoleDataScope(role.getRoleId());
- if (!roleService.checkRoleNameUnique(role))
- {
- return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
- }
- else if (!roleService.checkRoleKeyUnique(role))
- {
- return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
- }
- role.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(roleService.updateRole(role));
- }
-
- /**
- * 修改保存数据权限
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.UPDATE)
- @PutMapping("/dataScope")
- public AjaxResult dataScope(@RequestBody SysRole role)
- {
- roleService.checkRoleAllowed(role);
- roleService.checkRoleDataScope(role.getRoleId());
- return toAjax(roleService.authDataScope(role));
- }
-
- /**
- * 状态修改
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.UPDATE)
- @PutMapping("/changeStatus")
- public AjaxResult changeStatus(@RequestBody SysRole role)
- {
- roleService.checkRoleAllowed(role);
- roleService.checkRoleDataScope(role.getRoleId());
- role.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(roleService.updateRoleStatus(role));
- }
-
- /**
- * 删除角色
- */
- @RequiresPermissions("system:role:remove")
- @Log(title = "角色管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{roleIds}")
- public AjaxResult remove(@PathVariable Long[] roleIds)
- {
- return toAjax(roleService.deleteRoleByIds(roleIds));
- }
-
- /**
- * 获取角色选择框列表
- */
- @RequiresPermissions("system:role:query")
- @GetMapping("/optionselect")
- public AjaxResult optionselect()
- {
- return success(roleService.selectRoleAll());
- }
- /**
- * 查询已分配用户角色列表
- */
- @RequiresPermissions("system:role:list")
- @GetMapping("/authUser/allocatedList")
- public TableDataInfo allocatedList(SysUser user)
- {
- startPage();
- List<SysUser> list = userService.selectAllocatedList(user);
- return getDataTable(list);
- }
-
- /**
- * 查询未分配用户角色列表
- */
- @RequiresPermissions("system:role:list")
- @GetMapping("/authUser/unallocatedList")
- public TableDataInfo unallocatedList(SysUser user)
- {
- startPage();
- List<SysUser> list = userService.selectUnallocatedList(user);
- return getDataTable(list);
- }
-
- /**
- * 取消授权用户
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.GRANT)
- @PutMapping("/authUser/cancel")
- public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
- {
- return toAjax(roleService.deleteAuthUser(userRole));
- }
-
- /**
- * 批量取消授权用户
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.GRANT)
- @PutMapping("/authUser/cancelAll")
- public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
- {
- return toAjax(roleService.deleteAuthUsers(roleId, userIds));
- }
-
- /**
- * 批量选择用户授权
- */
- @RequiresPermissions("system:role:edit")
- @Log(title = "角色管理", businessType = BusinessType.GRANT)
- @PutMapping("/authUser/selectAll")
- public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
- {
- roleService.checkRoleDataScope(roleId);
- return toAjax(roleService.insertAuthUsers(roleId, userIds));
- }
-
- /**
- * 获取对应角色部门树列表
- */
- @RequiresPermissions("system:role:query")
- @GetMapping(value = "/deptTree/{roleId}")
- public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
- {
- AjaxResult ajax = AjaxResult.success();
- ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
- ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
- return ajax;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
deleted file mode 100644
index 6fce9c9..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserController.java
+++ /dev/null
@@ -1,387 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.io.IOException;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.poi.ExcelUtil;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.security.annotation.InnerAuth;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.common.security.service.TokenService;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.api.model.LoginUser;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysPermissionService;
-import com.ruoyi.system.service.ISysPostService;
-import com.ruoyi.system.service.ISysRoleService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 用户信息
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/user")
-public class SysUserController extends BaseController
-{
- @Autowired
- private ISysUserService userService;
-
- @Autowired
- private ISysRoleService roleService;
-
- @Autowired
- private ISysDeptService deptService;
-
- @Autowired
- private ISysPostService postService;
-
- @Autowired
- private ISysPermissionService permissionService;
-
- @Autowired
- private ISysConfigService configService;
-
- @Autowired
- private TokenService tokenService;
-
- /**
- * 获取用户列表
- */
- @RequiresPermissions("system:user:list")
- @GetMapping("/list")
- public TableDataInfo list(SysUser user)
- {
- startPage();
- List<SysUser> list = userService.selectUserList(user);
- return getDataTable(list);
- }
-
- @Log(title = "用户管理", businessType = BusinessType.EXPORT)
- @RequiresPermissions("system:user:export")
- @PostMapping("/export")
- public void export(HttpServletResponse response, SysUser user)
- {
- List<SysUser> list = userService.selectUserList(user);
- ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
- util.exportExcel(response, list, "用户数据");
- }
-
- @Log(title = "用户管理", businessType = BusinessType.IMPORT)
- @RequiresPermissions("system:user:import")
- @PostMapping("/importData")
- public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
- {
- ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
- List<SysUser> userList = util.importExcel(file.getInputStream());
- String operName = SecurityUtils.getUsername();
- String message = userService.importUser(userList, updateSupport, operName);
- return success(message);
- }
-
- @PostMapping("/importTemplate")
- public void importTemplate(HttpServletResponse response) throws IOException
- {
- ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
- util.importTemplateExcel(response, "用户数据");
- }
-
- /**
- * 获取当前用户信息
- */
- @InnerAuth
- @GetMapping("/info/{username}")
- public R<LoginUser> info(@PathVariable("username") String username)
- {
- SysUser sysUser = userService.selectUserByUserName(username);
- if (StringUtils.isNull(sysUser))
- {
- return R.fail("用户名或密码错误");
- }
- // 角色集合
- Set<String> roles = permissionService.getRolePermission(sysUser);
- // 权限集合
- Set<String> permissions = permissionService.getMenuPermission(sysUser);
- LoginUser sysUserVo = new LoginUser();
- sysUserVo.setSysUser(sysUser);
- sysUserVo.setRoles(roles);
- sysUserVo.setPermissions(permissions);
- return R.ok(sysUserVo);
- }
-
- /**
- * 注册用户信息
- */
- @InnerAuth
- @PostMapping("/register")
- public R<Boolean> register(@RequestBody SysUser sysUser)
- {
- String username = sysUser.getUserName();
- if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
- {
- return R.fail("当前系统没有开启注册功能!");
- }
- if (!userService.checkUserNameUnique(sysUser))
- {
- return R.fail("保存用户'" + username + "'失败,注册账号已存在");
- }
- return R.ok(userService.registerUser(sysUser));
- }
-
- /**
- *记录用户登录IP地址和登录时间
- */
- @InnerAuth
- @PutMapping("/recordlogin")
- public R<Boolean> recordlogin(@RequestBody SysUser sysUser)
- {
- return R.ok(userService.updateLoginInfo(sysUser));
- }
-
- /**
- * 获取用户信息
- *
- * @return 用户信息
- */
- @GetMapping("getInfo")
- public AjaxResult getInfo()
- {
- LoginUser loginUser = SecurityUtils.getLoginUser();
- SysUser user = loginUser.getSysUser();
- // 角色集合
- Set<String> roles = permissionService.getRolePermission(user);
- // 权限集合
- Set<String> permissions = permissionService.getMenuPermission(user);
- if (!loginUser.getPermissions().equals(permissions))
- {
- loginUser.setPermissions(permissions);
- tokenService.refreshToken(loginUser);
- }
- AjaxResult ajax = AjaxResult.success();
- ajax.put("user", user);
- ajax.put("roles", roles);
- ajax.put("permissions", permissions);
- ajax.put("pwdChrtype", getSysAccountChrtype());
- ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
- ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
- return ajax;
- }
-
- // 获取用户密码自定义配置规则
- public String getSysAccountChrtype()
- {
- return Convert.toStr(configService.selectConfigByKey("sys.account.chrtype"), "0");
- }
-
- // 检查初始密码是否提醒修改
- public boolean initPasswordIsModify(Date pwdUpdateDate)
- {
- Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
- return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
- }
-
- // 检查密码是否过期
- public boolean passwordIsExpiration(Date pwdUpdateDate)
- {
- Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
- if (passwordValidateDays != null && passwordValidateDays > 0)
- {
- if (StringUtils.isNull(pwdUpdateDate))
- {
- // 如果从未修改过初始密码,直接提醒过期
- return true;
- }
- Date nowDate = DateUtils.getNowDate();
- return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
- }
- return false;
- }
-
- /**
- * 根据用户编号获取详细信息
- */
- @RequiresPermissions("system:user:query")
- @GetMapping(value = { "/", "/{userId}" })
- public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
- {
- AjaxResult ajax = AjaxResult.success();
- if (StringUtils.isNotNull(userId))
- {
- userService.checkUserDataScope(userId);
- SysUser sysUser = userService.selectUserById(userId);
- ajax.put(AjaxResult.DATA_TAG, sysUser);
- ajax.put("postIds", postService.selectPostListByUserId(userId));
- ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
- }
- List<SysRole> roles = roleService.selectRoleAll();
- ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
- ajax.put("posts", postService.selectPostAll());
- return ajax;
- }
-
- /**
- * 新增用户
- */
- @RequiresPermissions("system:user:add")
- @Log(title = "用户管理", businessType = BusinessType.INSERT)
- @PostMapping
- public AjaxResult add(@Validated @RequestBody SysUser user)
- {
- deptService.checkDeptDataScope(user.getDeptId());
- roleService.checkRoleDataScope(user.getRoleIds());
- if (!userService.checkUserNameUnique(user))
- {
- return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
- }
- else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
- {
- return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
- }
- else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
- {
- return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
- }
- user.setCreateBy(SecurityUtils.getUsername());
- user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
- return toAjax(userService.insertUser(user));
- }
-
- /**
- * 修改用户
- */
- @RequiresPermissions("system:user:edit")
- @Log(title = "用户管理", businessType = BusinessType.UPDATE)
- @PutMapping
- public AjaxResult edit(@Validated @RequestBody SysUser user)
- {
- userService.checkUserAllowed(user);
- userService.checkUserDataScope(user.getUserId());
- deptService.checkDeptDataScope(user.getDeptId());
- roleService.checkRoleDataScope(user.getRoleIds());
- if (!userService.checkUserNameUnique(user))
- {
- return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
- }
- else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
- {
- return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
- }
- else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
- {
- return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
- }
- user.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(userService.updateUser(user));
- }
-
- /**
- * 删除用户
- */
- @RequiresPermissions("system:user:remove")
- @Log(title = "用户管理", businessType = BusinessType.DELETE)
- @DeleteMapping("/{userIds}")
- public AjaxResult remove(@PathVariable Long[] userIds)
- {
- if (ArrayUtils.contains(userIds, SecurityUtils.getUserId()))
- {
- return error("当前用户不能删除");
- }
- return toAjax(userService.deleteUserByIds(userIds));
- }
-
- /**
- * 重置密码
- */
- @RequiresPermissions("system:user:edit")
- @Log(title = "用户管理", businessType = BusinessType.UPDATE)
- @PutMapping("/resetPwd")
- public AjaxResult resetPwd(@RequestBody SysUser user)
- {
- userService.checkUserAllowed(user);
- userService.checkUserDataScope(user.getUserId());
- user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
- user.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(userService.resetPwd(user));
- }
-
- /**
- * 状态修改
- */
- @RequiresPermissions("system:user:edit")
- @Log(title = "用户管理", businessType = BusinessType.UPDATE)
- @PutMapping("/changeStatus")
- public AjaxResult changeStatus(@RequestBody SysUser user)
- {
- userService.checkUserAllowed(user);
- userService.checkUserDataScope(user.getUserId());
- user.setUpdateBy(SecurityUtils.getUsername());
- return toAjax(userService.updateUserStatus(user));
- }
-
- /**
- * 根据用户编号获取授权角色
- */
- @RequiresPermissions("system:user:query")
- @GetMapping("/authRole/{userId}")
- public AjaxResult authRole(@PathVariable("userId") Long userId)
- {
- AjaxResult ajax = AjaxResult.success();
- SysUser user = userService.selectUserById(userId);
- List<SysRole> roles = roleService.selectRolesByUserId(userId);
- ajax.put("user", user);
- ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
- return ajax;
- }
-
- /**
- * 用户授权角色
- */
- @RequiresPermissions("system:user:edit")
- @Log(title = "用户管理", businessType = BusinessType.GRANT)
- @PutMapping("/authRole")
- public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
- {
- userService.checkUserDataScope(userId);
- roleService.checkRoleDataScope(roleIds);
- userService.insertUserAuth(userId, roleIds);
- return success();
- }
-
- /**
- * 获取部门树列表
- */
- @RequiresPermissions("system:user:list")
- @GetMapping("/deptTree")
- public AjaxResult deptTree(SysDept dept)
- {
- return success(deptService.selectDeptTreeList(dept));
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java
deleted file mode 100644
index d15b0ae..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/SysUserOnlineController.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.ruoyi.system.controller;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.web.controller.BaseController;
-import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.log.annotation.Log;
-import com.ruoyi.common.log.enums.BusinessType;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.common.security.annotation.RequiresPermissions;
-import com.ruoyi.system.api.model.LoginUser;
-import com.ruoyi.system.domain.SysUserOnline;
-import com.ruoyi.system.service.ISysUserOnlineService;
-
-/**
- * 在线用户监控
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/online")
-public class SysUserOnlineController extends BaseController
-{
- @Autowired
- private ISysUserOnlineService userOnlineService;
-
- @Autowired
- private RedisService redisService;
-
- @RequiresPermissions("monitor:online:list")
- @GetMapping("/list")
- public TableDataInfo list(String ipaddr, String userName)
- {
- Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
- List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
- for (String key : keys)
- {
- LoginUser user = redisService.getCacheObject(key);
- if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
- {
- userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
- }
- else if (StringUtils.isNotEmpty(ipaddr))
- {
- userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
- }
- else if (StringUtils.isNotEmpty(userName))
- {
- userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
- }
- else
- {
- userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
- }
- }
- Collections.reverse(userOnlineList);
- userOnlineList.removeAll(Collections.singleton(null));
- return getDataTable(userOnlineList);
- }
-
- /**
- * 强退用户
- */
- @RequiresPermissions("monitor:online:forceLogout")
- @Log(title = "在线用户", businessType = BusinessType.FORCE)
- @DeleteMapping("/{tokenId}")
- public AjaxResult forceLogout(@PathVariable String tokenId)
- {
- redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
- return success();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
deleted file mode 100644
index 8974f87..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.ruoyi.system.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 参数配置表 sys_config
- *
- * @author ruoyi
- */
-public class SysConfig extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 参数主键 */
- @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
- private Long configId;
-
- /** 参数名称 */
- @Excel(name = "参数名称")
- private String configName;
-
- /** 参数键名 */
- @Excel(name = "参数键名")
- private String configKey;
-
- /** 参数键值 */
- @Excel(name = "参数键值")
- private String configValue;
-
- /** 系统内置(Y是 N否) */
- @Excel(name = "系统内置", readConverterExp = "Y=是,N=否")
- private String configType;
-
- public Long getConfigId()
- {
- return configId;
- }
-
- public void setConfigId(Long configId)
- {
- this.configId = configId;
- }
-
- @NotBlank(message = "参数名称不能为空")
- @Size(min = 0, max = 100, message = "参数名称不能超过100个字符")
- public String getConfigName()
- {
- return configName;
- }
-
- public void setConfigName(String configName)
- {
- this.configName = configName;
- }
-
- @NotBlank(message = "参数键名长度不能为空")
- @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符")
- public String getConfigKey()
- {
- return configKey;
- }
-
- public void setConfigKey(String configKey)
- {
- this.configKey = configKey;
- }
-
- @NotBlank(message = "参数键值不能为空")
- @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符")
- public String getConfigValue()
- {
- return configValue;
- }
-
- public void setConfigValue(String configValue)
- {
- this.configValue = configValue;
- }
-
- public String getConfigType()
- {
- return configType;
- }
-
- public void setConfigType(String configType)
- {
- this.configType = configType;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("configId", getConfigId())
- .append("configName", getConfigName())
- .append("configKey", getConfigKey())
- .append("configValue", getConfigValue())
- .append("configType", getConfigType())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java
deleted file mode 100644
index 5f1b787..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java
+++ /dev/null
@@ -1,274 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.ArrayList;
-import java.util.List;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 菜单权限表 sys_menu
- *
- * @author ruoyi
- */
-public class SysMenu extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 菜单ID */
- private Long menuId;
-
- /** 菜单名称 */
- private String menuName;
-
- /** 父菜单名称 */
- private String parentName;
-
- /** 父菜单ID */
- private Long parentId;
-
- /** 显示顺序 */
- private Integer orderNum;
-
- /** 路由地址 */
- private String path;
-
- /** 组件路径 */
- private String component;
-
- /** 路由参数 */
- private String query;
-
- /** 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义) */
- private String routeName;
-
- /** 是否为外链(0是 1否) */
- private String isFrame;
-
- /** 是否缓存(0缓存 1不缓存) */
- private String isCache;
-
- /** 类型(M目录 C菜单 F按钮) */
- private String menuType;
-
- /** 显示状态(0显示 1隐藏) */
- private String visible;
-
- /** 菜单状态(0正常 1停用) */
- private String status;
-
- /** 权限字符串 */
- private String perms;
-
- /** 菜单图标 */
- private String icon;
-
- /** 子菜单 */
- private List<SysMenu> children = new ArrayList<SysMenu>();
-
- public Long getMenuId()
- {
- return menuId;
- }
-
- public void setMenuId(Long menuId)
- {
- this.menuId = menuId;
- }
-
- @NotBlank(message = "菜单名称不能为空")
- @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
- public String getMenuName()
- {
- return menuName;
- }
-
- public void setMenuName(String menuName)
- {
- this.menuName = menuName;
- }
-
- public String getParentName()
- {
- return parentName;
- }
-
- public void setParentName(String parentName)
- {
- this.parentName = parentName;
- }
-
- public Long getParentId()
- {
- return parentId;
- }
-
- public void setParentId(Long parentId)
- {
- this.parentId = parentId;
- }
-
- @NotNull(message = "显示顺序不能为空")
- public Integer getOrderNum()
- {
- return orderNum;
- }
-
- public void setOrderNum(Integer orderNum)
- {
- this.orderNum = orderNum;
- }
-
- @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
- public String getPath()
- {
- return path;
- }
-
- public void setPath(String path)
- {
- this.path = path;
- }
-
- @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
- public String getComponent()
- {
- return component;
- }
-
- public void setComponent(String component)
- {
- this.component = component;
- }
-
- public String getQuery()
- {
- return query;
- }
-
- public void setQuery(String query)
- {
- this.query = query;
- }
-
- public String getRouteName()
- {
- return routeName;
- }
-
- public void setRouteName(String routeName)
- {
- this.routeName = routeName;
- }
-
- public String getIsFrame()
- {
- return isFrame;
- }
-
- public void setIsFrame(String isFrame)
- {
- this.isFrame = isFrame;
- }
-
- public String getIsCache()
- {
- return isCache;
- }
-
- public void setIsCache(String isCache)
- {
- this.isCache = isCache;
- }
-
- @NotBlank(message = "菜单类型不能为空")
- public String getMenuType()
- {
- return menuType;
- }
-
- public void setMenuType(String menuType)
- {
- this.menuType = menuType;
- }
-
- public String getVisible()
- {
- return visible;
- }
-
- public void setVisible(String visible)
- {
- this.visible = visible;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
- public String getPerms()
- {
- return perms;
- }
-
- public void setPerms(String perms)
- {
- this.perms = perms;
- }
-
- public String getIcon()
- {
- return icon;
- }
-
- public void setIcon(String icon)
- {
- this.icon = icon;
- }
-
- public List<SysMenu> getChildren()
- {
- return children;
- }
-
- public void setChildren(List<SysMenu> children)
- {
- this.children = children;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("menuId", getMenuId())
- .append("menuName", getMenuName())
- .append("parentId", getParentId())
- .append("orderNum", getOrderNum())
- .append("path", getPath())
- .append("component", getComponent())
- .append("query", getQuery())
- .append("routeName", getRouteName())
- .append("isFrame", getIsFrame())
- .append("IsCache", getIsCache())
- .append("menuType", getMenuType())
- .append("visible", getVisible())
- .append("status ", getStatus())
- .append("perms", getPerms())
- .append("icon", getIcon())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
deleted file mode 100644
index 5b5ee4e..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.ruoyi.system.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-import com.ruoyi.common.core.xss.Xss;
-
-/**
- * 通知公告表 sys_notice
- *
- * @author ruoyi
- */
-public class SysNotice extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 公告ID */
- private Long noticeId;
-
- /** 公告标题 */
- private String noticeTitle;
-
- /** 公告类型(1通知 2公告) */
- private String noticeType;
-
- /** 公告内容 */
- private String noticeContent;
-
- /** 公告状态(0正常 1关闭) */
- private String status;
-
- /** 是否已读 */
- @JsonProperty("isRead")
- private boolean isRead;
-
- public Long getNoticeId()
- {
- return noticeId;
- }
-
- public void setNoticeId(Long noticeId)
- {
- this.noticeId = noticeId;
- }
-
- public void setNoticeTitle(String noticeTitle)
- {
- this.noticeTitle = noticeTitle;
- }
-
- @Xss(message = "公告标题不能包含脚本字符")
- @NotBlank(message = "公告标题不能为空")
- @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
- public String getNoticeTitle()
- {
- return noticeTitle;
- }
-
- public void setNoticeType(String noticeType)
- {
- this.noticeType = noticeType;
- }
-
- public String getNoticeType()
- {
- return noticeType;
- }
-
- public void setNoticeContent(String noticeContent)
- {
- this.noticeContent = noticeContent;
- }
-
- public String getNoticeContent()
- {
- return noticeContent;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public boolean getIsRead()
- {
- return isRead;
- }
-
- public void setIsRead(boolean isRead)
- {
- this.isRead = isRead;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("noticeId", getNoticeId())
- .append("noticeTitle", getNoticeTitle())
- .append("noticeType", getNoticeType())
- .append("noticeContent", getNoticeContent())
- .append("status", getStatus())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNoticeRead.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNoticeRead.java
deleted file mode 100644
index 6ebf88c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNoticeRead.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 公告已读记录表 sys_notice_read
- *
- * @author ruoyi
- */
-public class SysNoticeRead
-{
- /** 主键 */
- private Long readId;
-
- /** 公告ID */
- private Long noticeId;
-
- /** 用户ID */
- private Long userId;
-
- /** 阅读时间 */
- private Date readTime;
-
- public Long getReadId()
- {
- return readId;
- }
-
- public void setReadId(Long readId)
- {
- this.readId = readId;
- }
-
- public Long getNoticeId()
- {
- return noticeId;
- }
-
- public void setNoticeId(Long noticeId)
- {
- this.noticeId = noticeId;
- }
-
- public Long getUserId()
- {
- return userId;
- }
-
- public void setUserId(Long userId)
- {
- this.userId = userId;
- }
-
- public Date getReadTime()
- {
- return readTime;
- }
-
- public void setReadTime(Date readTime)
- {
- this.readTime = readTime;
- }
-
- @Override
- public String toString()
- {
- return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
- .append("readId", getReadId())
- .append("noticeId", getNoticeId())
- .append("userId", getUserId())
- .append("readTime", getReadTime())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
deleted file mode 100644
index 3e3fc9c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.ruoyi.system.domain;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.annotation.Excel;
-import com.ruoyi.common.core.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.web.domain.BaseEntity;
-
-/**
- * 岗位表 sys_post
- *
- * @author ruoyi
- */
-public class SysPost extends BaseEntity
-{
- private static final long serialVersionUID = 1L;
-
- /** 岗位序号 */
- @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
- private Long postId;
-
- /** 岗位编码 */
- @Excel(name = "岗位编码")
- private String postCode;
-
- /** 岗位名称 */
- @Excel(name = "岗位名称")
- private String postName;
-
- /** 岗位排序 */
- @Excel(name = "岗位排序")
- private Integer postSort;
-
- /** 状态(0正常 1停用) */
- @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
- private String status;
-
- /** 用户是否存在此岗位标识 默认不存在 */
- private boolean flag = false;
-
- public Long getPostId()
- {
- return postId;
- }
-
- public void setPostId(Long postId)
- {
- this.postId = postId;
- }
-
- @NotBlank(message = "岗位编码不能为空")
- @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符")
- public String getPostCode()
- {
- return postCode;
- }
-
- public void setPostCode(String postCode)
- {
- this.postCode = postCode;
- }
-
- @NotBlank(message = "岗位名称不能为空")
- @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符")
- public String getPostName()
- {
- return postName;
- }
-
- public void setPostName(String postName)
- {
- this.postName = postName;
- }
-
- @NotNull(message = "显示顺序不能为空")
- public Integer getPostSort()
- {
- return postSort;
- }
-
- public void setPostSort(Integer postSort)
- {
- this.postSort = postSort;
- }
-
- public String getStatus()
- {
- return status;
- }
-
- public void setStatus(String status)
- {
- this.status = status;
- }
-
- public boolean isFlag()
- {
- return flag;
- }
-
- public void setFlag(boolean flag)
- {
- this.flag = flag;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("postId", getPostId())
- .append("postCode", getPostCode())
- .append("postName", getPostName())
- .append("postSort", getPostSort())
- .append("status", getStatus())
- .append("createBy", getCreateBy())
- .append("createTime", getCreateTime())
- .append("updateBy", getUpdateBy())
- .append("updateTime", getUpdateTime())
- .append("remark", getRemark())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
deleted file mode 100644
index 8ed8e47..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.system.domain;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 角色和部门关联 sys_role_dept
- *
- * @author ruoyi
- */
-public class SysRoleDept
-{
- /** 角色ID */
- private Long roleId;
-
- /** 部门ID */
- private Long deptId;
-
- public Long getRoleId()
- {
- return roleId;
- }
-
- public void setRoleId(Long roleId)
- {
- this.roleId = roleId;
- }
-
- public Long getDeptId()
- {
- return deptId;
- }
-
- public void setDeptId(Long deptId)
- {
- this.deptId = deptId;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("roleId", getRoleId())
- .append("deptId", getDeptId())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
deleted file mode 100644
index 59d2869..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.system.domain;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 角色和菜单关联 sys_role_menu
- *
- * @author ruoyi
- */
-public class SysRoleMenu
-{
- /** 角色ID */
- private Long roleId;
-
- /** 菜单ID */
- private Long menuId;
-
- public Long getRoleId()
- {
- return roleId;
- }
-
- public void setRoleId(Long roleId)
- {
- this.roleId = roleId;
- }
-
- public Long getMenuId()
- {
- return menuId;
- }
-
- public void setMenuId(Long menuId)
- {
- this.menuId = menuId;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("roleId", getRoleId())
- .append("menuId", getMenuId())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
deleted file mode 100644
index d9c8df0..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.ruoyi.system.domain;
-
-/**
- * 当前在线会话
- *
- * @author ruoyi
- */
-public class SysUserOnline
-{
- /** 会话编号 */
- private String tokenId;
-
- /** 用户名称 */
- private String userName;
-
- /** 登录IP地址 */
- private String ipaddr;
-
- /** 登录地址 */
- private String loginLocation;
-
- /** 浏览器类型 */
- private String browser;
-
- /** 操作系统 */
- private String os;
-
- /** 登录时间 */
- private Long loginTime;
-
- public String getTokenId()
- {
- return tokenId;
- }
-
- public void setTokenId(String tokenId)
- {
- this.tokenId = tokenId;
- }
-
- public String getUserName()
- {
- return userName;
- }
-
- public void setUserName(String userName)
- {
- this.userName = userName;
- }
-
- public String getIpaddr()
- {
- return ipaddr;
- }
-
- public void setIpaddr(String ipaddr)
- {
- this.ipaddr = ipaddr;
- }
-
- public String getLoginLocation()
- {
- return loginLocation;
- }
-
- public void setLoginLocation(String loginLocation)
- {
- this.loginLocation = loginLocation;
- }
-
- public String getBrowser()
- {
- return browser;
- }
-
- public void setBrowser(String browser)
- {
- this.browser = browser;
- }
-
- public String getOs()
- {
- return os;
- }
-
- public void setOs(String os)
- {
- this.os = os;
- }
-
- public Long getLoginTime()
- {
- return loginTime;
- }
-
- public void setLoginTime(Long loginTime)
- {
- this.loginTime = loginTime;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
deleted file mode 100644
index 07ceb85..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.system.domain;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 用户和岗位关联 sys_user_post
- *
- * @author ruoyi
- */
-public class SysUserPost
-{
- /** 用户ID */
- private Long userId;
-
- /** 岗位ID */
- private Long postId;
-
- public Long getUserId()
- {
- return userId;
- }
-
- public void setUserId(Long userId)
- {
- this.userId = userId;
- }
-
- public Long getPostId()
- {
- return postId;
- }
-
- public void setPostId(Long postId)
- {
- this.postId = postId;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("userId", getUserId())
- .append("postId", getPostId())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
deleted file mode 100644
index ce2af2b..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.ruoyi.system.domain;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 用户和角色关联 sys_user_role
- *
- * @author ruoyi
- */
-public class SysUserRole
-{
- /** 用户ID */
- private Long userId;
-
- /** 角色ID */
- private Long roleId;
-
- public Long getUserId()
- {
- return userId;
- }
-
- public void setUserId(Long userId)
- {
- this.userId = userId;
- }
-
- public Long getRoleId()
- {
- return roleId;
- }
-
- public void setRoleId(Long roleId)
- {
- this.roleId = roleId;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
- .append("userId", getUserId())
- .append("roleId", getRoleId())
- .toString();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
deleted file mode 100644
index 1df3e89..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package com.ruoyi.system.domain.vo;
-
-import com.ruoyi.common.core.utils.StringUtils;
-
-/**
- * 路由显示信息
- *
- * @author ruoyi
- */
-public class MetaVo
-{
- /**
- * 设置该路由在侧边栏和面包屑中展示的名字
- */
- private String title;
-
- /**
- * 设置该路由的图标,对应路径src/assets/icons/svg
- */
- private String icon;
-
- /**
- * 设置为true,则不会被 <keep-alive>缓存
- */
- private boolean noCache;
-
- /**
- * 内链地址(http(s)://开头)
- */
- private String link;
-
- public MetaVo()
- {
- }
-
- public MetaVo(String title, String icon)
- {
- this.title = title;
- this.icon = icon;
- }
-
- public MetaVo(String title, String icon, boolean noCache)
- {
- this.title = title;
- this.icon = icon;
- this.noCache = noCache;
- }
-
- public MetaVo(String title, String icon, String link)
- {
- this.title = title;
- this.icon = icon;
- this.link = link;
- }
-
- public MetaVo(String title, String icon, boolean noCache, String link)
- {
- this.title = title;
- this.icon = icon;
- this.noCache = noCache;
- if (StringUtils.ishttp(link))
- {
- this.link = link;
- }
- }
-
- public boolean isNoCache()
- {
- return noCache;
- }
-
- public void setNoCache(boolean noCache)
- {
- this.noCache = noCache;
- }
-
- public String getTitle()
- {
- return title;
- }
-
- public void setTitle(String title)
- {
- this.title = title;
- }
-
- public String getIcon()
- {
- return icon;
- }
-
- public void setIcon(String icon)
- {
- this.icon = icon;
- }
-
- public String getLink()
- {
- return link;
- }
-
- public void setLink(String link)
- {
- this.link = link;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
deleted file mode 100644
index 2d4a2b8..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.ruoyi.system.domain.vo;
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import java.util.List;
-
-/**
- * 路由配置信息
- *
- * @author ruoyi
- */
-@JsonInclude(JsonInclude.Include.NON_EMPTY)
-public class RouterVo
-{
- /**
- * 路由名字
- */
- private String name;
-
- /**
- * 路由地址
- */
- private String path;
-
- /**
- * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
- */
- private boolean hidden;
-
- /**
- * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
- */
- private String redirect;
-
- /**
- * 组件地址
- */
- private String component;
-
- /**
- * 路由参数:如 {"id": 1, "name": "ry"}
- */
- private String query;
-
- /**
- * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
- */
- private Boolean alwaysShow;
-
- /**
- * 其他元素
- */
- private MetaVo meta;
-
- /**
- * 子路由
- */
- private List<RouterVo> children;
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public String getPath()
- {
- return path;
- }
-
- public void setPath(String path)
- {
- this.path = path;
- }
-
- public boolean getHidden()
- {
- return hidden;
- }
-
- public void setHidden(boolean hidden)
- {
- this.hidden = hidden;
- }
-
- public String getRedirect()
- {
- return redirect;
- }
-
- public void setRedirect(String redirect)
- {
- this.redirect = redirect;
- }
-
- public String getComponent()
- {
- return component;
- }
-
- public void setComponent(String component)
- {
- this.component = component;
- }
-
- public String getQuery()
- {
- return query;
- }
-
- public void setQuery(String query)
- {
- this.query = query;
- }
-
- public Boolean getAlwaysShow()
- {
- return alwaysShow;
- }
-
- public void setAlwaysShow(Boolean alwaysShow)
- {
- this.alwaysShow = alwaysShow;
- }
-
- public MetaVo getMeta()
- {
- return meta;
- }
-
- public void setMeta(MetaVo meta)
- {
- this.meta = meta;
- }
-
- public List<RouterVo> getChildren()
- {
- return children;
- }
-
- public void setChildren(List<RouterVo> children)
- {
- this.children = children;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java
deleted file mode 100644
index e3986d0..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TreeSelect.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.ruoyi.system.domain.vo;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.stream.Collectors;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.domain.SysMenu;
-
-/**
- * Treeselect树结构实体类
- *
- * @author ruoyi
- */
-public class TreeSelect implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /** 节点ID */
- private Long id;
-
- /** 节点名称 */
- private String label;
-
- /** 节点禁用 */
- private boolean disabled = false;
-
- /** 子节点 */
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
- private List<TreeSelect> children;
-
- public TreeSelect()
- {
-
- }
-
- public TreeSelect(SysDept dept)
- {
- this.id = dept.getDeptId();
- this.label = dept.getDeptName();
- this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
- this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
- }
-
- public TreeSelect(SysMenu menu)
- {
- this.id = menu.getMenuId();
- this.label = menu.getMenuName();
- this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
- }
-
- public Long getId()
- {
- return id;
- }
-
- public void setId(Long id)
- {
- this.id = id;
- }
-
- public String getLabel()
- {
- return label;
- }
-
- public void setLabel(String label)
- {
- this.label = label;
- }
-
- public boolean isDisabled()
- {
- return disabled;
- }
-
- public void setDisabled(boolean disabled)
- {
- this.disabled = disabled;
- }
-
- public List<TreeSelect> getChildren()
- {
- return children;
- }
-
- public void setChildren(List<TreeSelect> children)
- {
- this.children = children;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
deleted file mode 100644
index 446eed6..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysConfig;
-
-/**
- * 参数配置 数据层
- *
- * @author ruoyi
- */
-public interface SysConfigMapper
-{
- /**
- * 查询参数配置信息
- *
- * @param config 参数配置信息
- * @return 参数配置信息
- */
- public SysConfig selectConfig(SysConfig config);
-
- /**
- * 通过ID查询配置
- *
- * @param configId 参数ID
- * @return 参数配置信息
- */
- public SysConfig selectConfigById(Long configId);
-
- /**
- * 查询参数配置列表
- *
- * @param config 参数配置信息
- * @return 参数配置集合
- */
- public List<SysConfig> selectConfigList(SysConfig config);
-
- /**
- * 根据键名查询参数配置信息
- *
- * @param configKey 参数键名
- * @return 参数配置信息
- */
- public SysConfig checkConfigKeyUnique(String configKey);
-
- /**
- * 新增参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- public int insertConfig(SysConfig config);
-
- /**
- * 修改参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- public int updateConfig(SysConfig config);
-
- /**
- * 删除参数配置
- *
- * @param configId 参数ID
- * @return 结果
- */
- public int deleteConfigById(Long configId);
-
- /**
- * 批量删除参数信息
- *
- * @param configIds 需要删除的参数ID
- * @return 结果
- */
- public int deleteConfigByIds(Long[] configIds);
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
deleted file mode 100644
index 11ac693..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.api.domain.SysDept;
-
-/**
- * 部门管理 数据层
- *
- * @author ruoyi
- */
-public interface SysDeptMapper
-{
- /**
- * 查询部门管理数据
- *
- * @param dept 部门信息
- * @return 部门信息集合
- */
- public List<SysDept> selectDeptList(SysDept dept);
-
- /**
- * 根据角色ID查询部门树信息
- *
- * @param roleId 角色ID
- * @param deptCheckStrictly 部门树选择项是否关联显示
- * @return 选中部门列表
- */
- public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
-
- /**
- * 根据部门ID查询信息
- *
- * @param deptId 部门ID
- * @return 部门信息
- */
- public SysDept selectDeptById(Long deptId);
-
- /**
- * 根据ID查询所有子部门
- *
- * @param deptId 部门ID
- * @return 部门列表
- */
- public List<SysDept> selectChildrenDeptById(Long deptId);
-
- /**
- * 根据ID查询所有子部门(正常状态)
- *
- * @param deptId 部门ID
- * @return 子部门数
- */
- public int selectNormalChildrenDeptById(Long deptId);
-
- /**
- * 是否存在子节点
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public int hasChildByDeptId(Long deptId);
-
- /**
- * 查询部门是否存在用户
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public int checkDeptExistUser(Long deptId);
-
- /**
- * 校验部门名称是否唯一
- *
- * @param deptName 部门名称
- * @param parentId 父部门ID
- * @return 结果
- */
- public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
-
- /**
- * 新增部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- public int insertDept(SysDept dept);
-
- /**
- * 修改部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- public int updateDept(SysDept dept);
-
- /**
- * 修改所在部门正常状态
- *
- * @param deptIds 部门ID组
- */
- public void updateDeptStatusNormal(Long[] deptIds);
-
- /**
- * 修改子元素关系
- *
- * @param depts 子元素
- * @return 结果
- */
- public int updateDeptChildren(@Param("depts") List<SysDept> depts);
-
- /**
- * 保存部门排序
- *
- * @param dept 部门信息
- */
- public void updateDeptSort(SysDept dept);
-
- /**
- * 删除部门管理信息
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public int deleteDeptById(Long deptId);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
deleted file mode 100644
index 6e416f7..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.api.domain.SysDictData;
-
-/**
- * 字典表 数据层
- *
- * @author ruoyi
- */
-public interface SysDictDataMapper
-{
- /**
- * 根据条件分页查询字典数据
- *
- * @param dictData 字典数据信息
- * @return 字典数据集合信息
- */
- public List<SysDictData> selectDictDataList(SysDictData dictData);
-
- /**
- * 根据字典类型查询字典数据
- *
- * @param dictType 字典类型
- * @return 字典数据集合信息
- */
- public List<SysDictData> selectDictDataByType(String dictType);
-
- /**
- * 根据字典类型和字典键值查询字典数据信息
- *
- * @param dictType 字典类型
- * @param dictValue 字典键值
- * @return 字典标签
- */
- public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue);
-
- /**
- * 根据字典数据ID查询信息
- *
- * @param dictCode 字典数据ID
- * @return 字典数据
- */
- public SysDictData selectDictDataById(Long dictCode);
-
- /**
- * 查询字典数据
- *
- * @param dictType 字典类型
- * @return 字典数据
- */
- public int countDictDataByType(String dictType);
-
- /**
- * 通过字典ID删除字典数据信息
- *
- * @param dictCode 字典数据ID
- * @return 结果
- */
- public int deleteDictDataById(Long dictCode);
-
- /**
- * 批量删除字典数据信息
- *
- * @param dictCodes 需要删除的字典数据ID
- * @return 结果
- */
- public int deleteDictDataByIds(Long[] dictCodes);
-
- /**
- * 新增字典数据信息
- *
- * @param dictData 字典数据信息
- * @return 结果
- */
- public int insertDictData(SysDictData dictData);
-
- /**
- * 修改字典数据信息
- *
- * @param dictData 字典数据信息
- * @return 结果
- */
- public int updateDictData(SysDictData dictData);
-
- /**
- * 同步修改字典类型
- *
- * @param oldDictType 旧字典类型
- * @param newDictType 新旧字典类型
- * @return 结果
- */
- public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
deleted file mode 100644
index 3a172a5..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysDictType;
-
-/**
- * 字典表 数据层
- *
- * @author ruoyi
- */
-public interface SysDictTypeMapper
-{
- /**
- * 根据条件分页查询字典类型
- *
- * @param dictType 字典类型信息
- * @return 字典类型集合信息
- */
- public List<SysDictType> selectDictTypeList(SysDictType dictType);
-
- /**
- * 根据所有字典类型
- *
- * @return 字典类型集合信息
- */
- public List<SysDictType> selectDictTypeAll();
-
- /**
- * 根据字典类型ID查询信息
- *
- * @param dictId 字典类型ID
- * @return 字典类型
- */
- public SysDictType selectDictTypeById(Long dictId);
-
- /**
- * 根据字典类型查询信息
- *
- * @param dictType 字典类型
- * @return 字典类型
- */
- public SysDictType selectDictTypeByType(String dictType);
-
- /**
- * 通过字典ID删除字典信息
- *
- * @param dictId 字典ID
- * @return 结果
- */
- public int deleteDictTypeById(Long dictId);
-
- /**
- * 批量删除字典类型信息
- *
- * @param dictIds 需要删除的字典ID
- * @return 结果
- */
- public int deleteDictTypeByIds(Long[] dictIds);
-
- /**
- * 新增字典类型信息
- *
- * @param dictType 字典类型信息
- * @return 结果
- */
- public int insertDictType(SysDictType dictType);
-
- /**
- * 修改字典类型信息
- *
- * @param dictType 字典类型信息
- * @return 结果
- */
- public int updateDictType(SysDictType dictType);
-
- /**
- * 校验字典类型称是否唯一
- *
- * @param dictType 字典类型
- * @return 结果
- */
- public SysDictType checkDictTypeUnique(String dictType);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
deleted file mode 100644
index 395edf1..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysLogininfor;
-
-/**
- * 系统访问日志情况信息 数据层
- *
- * @author ruoyi
- */
-public interface SysLogininforMapper
-{
- /**
- * 新增系统登录日志
- *
- * @param logininfor 访问日志对象
- */
- public int insertLogininfor(SysLogininfor logininfor);
-
- /**
- * 查询系统登录日志集合
- *
- * @param logininfor 访问日志对象
- * @return 登录记录集合
- */
- public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
-
- /**
- * 批量删除系统登录日志
- *
- * @param infoIds 需要删除的登录日志ID
- * @return 结果
- */
- public int deleteLogininforByIds(Long[] infoIds);
-
- /**
- * 清空系统登录日志
- *
- * @return 结果
- */
- public int cleanLogininfor();
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
deleted file mode 100644
index eb78bae..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.domain.SysMenu;
-
-/**
- * 菜单表 数据层
- *
- * @author ruoyi
- */
-public interface SysMenuMapper
-{
- /**
- * 查询系统菜单列表
- *
- * @param menu 菜单信息
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuList(SysMenu menu);
-
- /**
- * 根据用户所有权限
- *
- * @return 权限列表
- */
- public List<String> selectMenuPerms();
-
- /**
- * 根据用户查询系统菜单列表
- *
- * @param menu 菜单信息
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuListByUserId(SysMenu menu);
-
- /**
- * 根据角色ID查询权限
- *
- * @param roleId 角色ID
- * @return 权限列表
- */
- public List<String> selectMenuPermsByRoleId(Long roleId);
-
- /**
- * 根据用户ID查询权限
- *
- * @param userId 用户ID
- * @return 权限列表
- */
- public List<String> selectMenuPermsByUserId(Long userId);
-
- /**
- * 根据用户ID查询菜单
- *
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuTreeAll();
-
- /**
- * 根据用户ID查询菜单
- *
- * @param userId 用户ID
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuTreeByUserId(Long userId);
-
- /**
- * 根据角色ID查询菜单树信息
- *
- * @param roleId 角色ID
- * @param menuCheckStrictly 菜单树选择项是否关联显示
- * @return 选中菜单列表
- */
- public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
-
- /**
- * 根据菜单ID查询信息
- *
- * @param menuId 菜单ID
- * @return 菜单信息
- */
- public SysMenu selectMenuById(Long menuId);
-
- /**
- * 是否存在菜单子节点
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- public int hasChildByMenuId(Long menuId);
-
- /**
- * 新增菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public int insertMenu(SysMenu menu);
-
- /**
- * 修改菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public int updateMenu(SysMenu menu);
-
- /**
- * 保存菜单排序
- *
- * @param menu 菜单信息
- */
- public void updateMenuSort(SysMenu menu);
-
- /**
- * 删除菜单管理信息
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- public int deleteMenuById(Long menuId);
-
- /**
- * 校验菜单名称是否唯一
- *
- * @param menuName 菜单名称
- * @param parentId 父菜单ID
- * @return 结果
- */
- public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
-
- /**
- * 根据路由路径或名称查询菜单信息(用于唯一性校验)
- *
- * @param path 路由地址
- * @param routeName 路由名称
- * @return 匹配的菜单列表
- */
- public List<SysMenu> selectMenusByPathOrRouteName(@Param("path") String path, @Param("routeName") String routeName);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
deleted file mode 100644
index ec8700d..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysNotice;
-
-/**
- * 通知公告表 数据层
- *
- * @author ruoyi
- */
-public interface SysNoticeMapper
-{
- /**
- * 查询公告信息
- *
- * @param noticeId 公告ID
- * @return 公告信息
- */
- public SysNotice selectNoticeById(Long noticeId);
-
- /**
- * 查询公告列表
- *
- * @param notice 公告信息
- * @return 公告集合
- */
- public List<SysNotice> selectNoticeList(SysNotice notice);
-
- /**
- * 新增公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- public int insertNotice(SysNotice notice);
-
- /**
- * 修改公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- public int updateNotice(SysNotice notice);
-
- /**
- * 批量删除公告
- *
- * @param noticeId 公告ID
- * @return 结果
- */
- public int deleteNoticeById(Long noticeId);
-
- /**
- * 批量删除公告信息
- *
- * @param noticeIds 需要删除的公告ID
- * @return 结果
- */
- public int deleteNoticeByIds(Long[] noticeIds);
-}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeReadMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeReadMapper.java
deleted file mode 100644
index 529b8e1..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeReadMapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import java.util.Map;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.system.domain.SysNoticeRead;
-
-/**
- * 公告已读记录 数据层
- *
- * @author ruoyi
- */
-public interface SysNoticeReadMapper
-{
- /**
- * 新增已读记录(忽略重复)
- *
- * @param noticeRead 已读记录
- * @return 结果
- */
- public int insertNoticeRead(SysNoticeRead noticeRead);
-
- /**
- * 查询某用户未读公告数量
- *
- * @param userId 用户ID
- * @return 未读数量
- */
- public int selectUnreadCount(@Param("userId") Long userId);
-
- /**
- * 查询某用户是否已读某公告
- *
- * @param noticeId 公告ID
- * @param userId 用户ID
- * @return 已读记录数(0未读 1已读)
- */
- public int selectIsRead(@Param("noticeId") Long noticeId, @Param("userId") Long userId);
-
- /**
- * 批量标记已读
- *
- * @param userId 用户ID
- * @param noticeIds 公告ID数组
- * @return 结果
- */
- public int insertNoticeReadBatch(@Param("userId") Long userId, @Param("noticeIds") Long[] noticeIds);
-
- /**
- * 查询带已读状态的公告列表(SQL层限制条数,一次查询完成)
- *
- * @param userId 用户ID
- * @param limit 最多返回条数
- * @return 带 isRead 标记的公告列表
- */
- public List<SysNotice> selectNoticeListWithReadStatus(@Param("userId") Long userId, @Param("limit") int limit);
-
- /**
- * 查询已阅读某公告的用户列表
- *
- * @param noticeId 公告ID
- * @param searchValue 搜索值
- * @return 已读用户列表
- */
- public List<Map<String, Object>> selectReadUsersByNoticeId(@Param("noticeId") Long noticeId, @Param("searchValue") String searchValue);
-
- /**
- * 公告删除时清理对应已读记录
- *
- * @param noticeIds 公告ID数组
- * @return 结果
- */
- public int deleteByNoticeIds(@Param("noticeIds") Long[] noticeIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
deleted file mode 100644
index 4e9b8cb..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysOperLog;
-
-/**
- * 操作日志 数据层
- *
- * @author ruoyi
- */
-public interface SysOperLogMapper
-{
- /**
- * 新增操作日志
- *
- * @param operLog 操作日志对象
- */
- public int insertOperlog(SysOperLog operLog);
-
- /**
- * 查询系统操作日志集合
- *
- * @param operLog 操作日志对象
- * @return 操作日志集合
- */
- public List<SysOperLog> selectOperLogList(SysOperLog operLog);
-
- /**
- * 批量删除系统操作日志
- *
- * @param operIds 需要删除的操作日志ID
- * @return 结果
- */
- public int deleteOperLogByIds(Long[] operIds);
-
- /**
- * 查询操作日志详细
- *
- * @param operId 操作ID
- * @return 操作日志对象
- */
- public SysOperLog selectOperLogById(Long operId);
-
- /**
- * 清空操作日志
- */
- public void cleanOperLog();
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
deleted file mode 100644
index 8603d9a..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysPost;
-
-/**
- * 岗位信息 数据层
- *
- * @author ruoyi
- */
-public interface SysPostMapper
-{
- /**
- * 查询岗位数据集合
- *
- * @param post 岗位信息
- * @return 岗位数据集合
- */
- public List<SysPost> selectPostList(SysPost post);
-
- /**
- * 查询所有岗位
- *
- * @return 岗位列表
- */
- public List<SysPost> selectPostAll();
-
- /**
- * 通过岗位ID查询岗位信息
- *
- * @param postId 岗位ID
- * @return 角色对象信息
- */
- public SysPost selectPostById(Long postId);
-
- /**
- * 根据用户ID获取岗位选择框列表
- *
- * @param userId 用户ID
- * @return 选中岗位ID列表
- */
- public List<Long> selectPostListByUserId(Long userId);
-
- /**
- * 查询用户所属岗位组
- *
- * @param userName 用户名
- * @return 结果
- */
- public List<SysPost> selectPostsByUserName(String userName);
-
- /**
- * 删除岗位信息
- *
- * @param postId 岗位ID
- * @return 结果
- */
- public int deletePostById(Long postId);
-
- /**
- * 批量删除岗位信息
- *
- * @param postIds 需要删除的岗位ID
- * @return 结果
- */
- public int deletePostByIds(Long[] postIds);
-
- /**
- * 修改岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- public int updatePost(SysPost post);
-
- /**
- * 新增岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- public int insertPost(SysPost post);
-
- /**
- * 校验岗位名称
- *
- * @param postName 岗位名称
- * @return 结果
- */
- public SysPost checkPostNameUnique(String postName);
-
- /**
- * 校验岗位编码
- *
- * @param postCode 岗位编码
- * @return 结果
- */
- public SysPost checkPostCodeUnique(String postCode);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
deleted file mode 100644
index a4ad4de..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysRoleDept;
-
-/**
- * 角色与部门关联表 数据层
- *
- * @author ruoyi
- */
-public interface SysRoleDeptMapper
-{
- /**
- * 通过角色ID删除角色和部门关联
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int deleteRoleDeptByRoleId(Long roleId);
-
- /**
- * 批量删除角色部门关联信息
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteRoleDept(Long[] ids);
-
- /**
- * 查询部门使用数量
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public int selectCountRoleDeptByDeptId(Long deptId);
-
- /**
- * 批量新增角色部门信息
- *
- * @param roleDeptList 角色部门列表
- * @return 结果
- */
- public int batchRoleDept(List<SysRoleDept> roleDeptList);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
deleted file mode 100644
index b49511c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysRole;
-
-/**
- * 角色表 数据层
- *
- * @author ruoyi
- */
-public interface SysRoleMapper
-{
- /**
- * 根据条件分页查询角色数据
- *
- * @param role 角色信息
- * @return 角色数据集合信息
- */
- public List<SysRole> selectRoleList(SysRole role);
-
- /**
- * 根据用户ID查询角色
- *
- * @param userId 用户ID
- * @return 角色列表
- */
- public List<SysRole> selectRolePermissionByUserId(Long userId);
-
- /**
- * 查询所有角色
- *
- * @return 角色列表
- */
- public List<SysRole> selectRoleAll();
-
- /**
- * 根据用户ID获取角色选择框列表
- *
- * @param userId 用户ID
- * @return 选中角色ID列表
- */
- public List<Long> selectRoleListByUserId(Long userId);
-
- /**
- * 通过角色ID查询角色
- *
- * @param roleId 角色ID
- * @return 角色对象信息
- */
- public SysRole selectRoleById(Long roleId);
-
- /**
- * 根据用户ID查询角色
- *
- * @param userName 用户名
- * @return 角色列表
- */
- public List<SysRole> selectRolesByUserName(String userName);
-
- /**
- * 校验角色名称是否唯一
- *
- * @param roleName 角色名称
- * @return 角色信息
- */
- public SysRole checkRoleNameUnique(String roleName);
-
- /**
- * 校验角色权限是否唯一
- *
- * @param roleKey 角色权限
- * @return 角色信息
- */
- public SysRole checkRoleKeyUnique(String roleKey);
-
- /**
- * 修改角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- public int updateRole(SysRole role);
-
- /**
- * 新增角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- public int insertRole(SysRole role);
-
- /**
- * 通过角色ID删除角色
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int deleteRoleById(Long roleId);
-
- /**
- * 批量删除角色信息
- *
- * @param roleIds 需要删除的角色ID
- * @return 结果
- */
- public int deleteRoleByIds(Long[] roleIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
deleted file mode 100644
index 2339155..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysRoleMenu;
-
-/**
- * 角色与菜单关联表 数据层
- *
- * @author ruoyi
- */
-public interface SysRoleMenuMapper
-{
- /**
- * 查询菜单使用数量
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- public int checkMenuExistRole(Long menuId);
-
- /**
- * 通过角色ID删除角色和菜单关联
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int deleteRoleMenuByRoleId(Long roleId);
-
- /**
- * 批量删除角色菜单关联信息
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteRoleMenu(Long[] ids);
-
- /**
- * 批量新增角色菜单信息
- *
- * @param roleMenuList 角色菜单列表
- * @return 结果
- */
- public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
deleted file mode 100644
index c486d80..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.api.domain.SysUser;
-
-/**
- * 用户表 数据层
- *
- * @author ruoyi
- */
-public interface SysUserMapper
-{
- /**
- * 根据条件分页查询用户列表
- *
- * @param sysUser 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectUserList(SysUser sysUser);
-
- /**
- * 根据条件分页查询已配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectAllocatedList(SysUser user);
-
- /**
- * 根据条件分页查询未分配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectUnallocatedList(SysUser user);
-
- /**
- * 通过用户名查询用户
- *
- * @param userName 用户名
- * @return 用户对象信息
- */
- public SysUser selectUserByUserName(String userName);
-
- /**
- * 通过用户ID查询用户
- *
- * @param userId 用户ID
- * @return 用户对象信息
- */
- public SysUser selectUserById(Long userId);
-
- /**
- * 新增用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public int insertUser(SysUser user);
-
- /**
- * 修改用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public int updateUser(SysUser user);
-
- /**
- * 修改用户头像
- *
- * @param userId 用户ID
- * @param avatar 头像地址
- * @return 结果
- */
- public int updateUserAvatar(@Param("userId") Long userId, @Param("avatar") String avatar);
-
- /**
- * 修改用户状态
- *
- * @param userId 用户ID
- * @param status 状态
- * @return 结果
- */
- public int updateUserStatus(@Param("userId") Long userId, @Param("status") String status);
-
- /**
- * 更新用户登录信息(IP和登录时间)
- *
- * @param user 用户信息
- * @return 结果
- */
- public int updateLoginInfo(SysUser user);
-
- /**
- * 重置用户密码
- *
- * @param userId 用户ID
- * @param password 密码
- * @return 结果
- */
- public int resetUserPwd(@Param("userId") Long userId, @Param("password") String password);
-
- /**
- * 通过用户ID删除用户
- *
- * @param userId 用户ID
- * @return 结果
- */
- public int deleteUserById(Long userId);
-
- /**
- * 批量删除用户信息
- *
- * @param userIds 需要删除的用户ID
- * @return 结果
- */
- public int deleteUserByIds(Long[] userIds);
-
- /**
- * 校验用户名称是否唯一
- *
- * @param userName 用户名称
- * @return 结果
- */
- public SysUser checkUserNameUnique(String userName);
-
- /**
- * 校验手机号码是否唯一
- *
- * @param phonenumber 手机号码
- * @return 结果
- */
- public SysUser checkPhoneUnique(String phonenumber);
-
- /**
- * 校验email是否唯一
- *
- * @param email 用户邮箱
- * @return 结果
- */
- public SysUser checkEmailUnique(String email);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
deleted file mode 100644
index 81d6e71..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysUserPost;
-
-/**
- * 用户与岗位关联表 数据层
- *
- * @author ruoyi
- */
-public interface SysUserPostMapper
-{
- /**
- * 通过用户ID删除用户和岗位关联
- *
- * @param userId 用户ID
- * @return 结果
- */
- public int deleteUserPostByUserId(Long userId);
-
- /**
- * 通过岗位ID查询岗位使用数量
- *
- * @param postId 岗位ID
- * @return 结果
- */
- public int countUserPostById(Long postId);
-
- /**
- * 批量删除用户和岗位关联
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteUserPost(Long[] ids);
-
- /**
- * 批量新增用户岗位信息
- *
- * @param userPostList 用户岗位列表
- * @return 结果
- */
- public int batchUserPost(List<SysUserPost> userPostList);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
deleted file mode 100644
index ad3fe62..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.system.domain.SysUserRole;
-
-/**
- * 用户与角色关联表 数据层
- *
- * @author ruoyi
- */
-public interface SysUserRoleMapper
-{
- /**
- * 通过用户ID删除用户和角色关联
- *
- * @param userId 用户ID
- * @return 结果
- */
- public int deleteUserRoleByUserId(Long userId);
-
- /**
- * 批量删除用户和角色关联
- *
- * @param ids 需要删除的数据ID
- * @return 结果
- */
- public int deleteUserRole(Long[] ids);
-
- /**
- * 通过角色ID查询角色使用数量
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int countUserRoleByRoleId(Long roleId);
-
- /**
- * 批量新增用户角色信息
- *
- * @param userRoleList 用户角色列表
- * @return 结果
- */
- public int batchUserRole(List<SysUserRole> userRoleList);
-
- /**
- * 删除用户和角色关联信息
- *
- * @param userRole 用户和角色关联信息
- * @return 结果
- */
- public int deleteUserRoleInfo(SysUserRole userRole);
-
- /**
- * 批量取消授权用户角色
- *
- * @param roleId 角色ID
- * @param userIds 需要删除的用户数据ID
- * @return 结果
- */
- public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
deleted file mode 100644
index 8ec8573..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysConfig;
-
-/**
- * 参数配置 服务层
- *
- * @author ruoyi
- */
-public interface ISysConfigService
-{
- /**
- * 查询参数配置信息
- *
- * @param configId 参数配置ID
- * @return 参数配置信息
- */
- public SysConfig selectConfigById(Long configId);
-
- /**
- * 根据键名查询参数配置信息
- *
- * @param configKey 参数键名
- * @return 参数键值
- */
- public String selectConfigByKey(String configKey);
-
- /**
- * 查询参数配置列表
- *
- * @param config 参数配置信息
- * @return 参数配置集合
- */
- public List<SysConfig> selectConfigList(SysConfig config);
-
- /**
- * 新增参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- public int insertConfig(SysConfig config);
-
- /**
- * 修改参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- public int updateConfig(SysConfig config);
-
- /**
- * 批量删除参数信息
- *
- * @param configIds 需要删除的参数ID
- */
- public void deleteConfigByIds(Long[] configIds);
-
- /**
- * 加载参数缓存数据
- */
- public void loadingConfigCache();
-
- /**
- * 清空参数缓存数据
- */
- public void clearConfigCache();
-
- /**
- * 重置参数缓存数据
- */
- public void resetConfigCache();
-
- /**
- * 校验参数键名是否唯一
- *
- * @param config 参数信息
- * @return 结果
- */
- public boolean checkConfigKeyUnique(SysConfig config);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
deleted file mode 100644
index 6092564..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.domain.vo.TreeSelect;
-
-/**
- * 部门管理 服务层
- *
- * @author ruoyi
- */
-public interface ISysDeptService
-{
- /**
- * 查询部门管理数据
- *
- * @param dept 部门信息
- * @return 部门信息集合
- */
- public List<SysDept> selectDeptList(SysDept dept);
-
- /**
- * 查询部门树结构信息
- *
- * @param dept 部门信息
- * @return 部门树信息集合
- */
- public List<TreeSelect> selectDeptTreeList(SysDept dept);
-
- /**
- * 构建前端所需要树结构
- *
- * @param depts 部门列表
- * @return 树结构列表
- */
- public List<SysDept> buildDeptTree(List<SysDept> depts);
-
- /**
- * 构建前端所需要下拉树结构
- *
- * @param depts 部门列表
- * @return 下拉树结构列表
- */
- public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts);
-
- /**
- * 根据角色ID查询部门树信息
- *
- * @param roleId 角色ID
- * @return 选中部门列表
- */
- public List<Long> selectDeptListByRoleId(Long roleId);
-
- /**
- * 根据部门ID查询信息
- *
- * @param deptId 部门ID
- * @return 部门信息
- */
- public SysDept selectDeptById(Long deptId);
-
- /**
- * 根据ID查询所有子部门(正常状态)
- *
- * @param deptId 部门ID
- * @return 子部门数
- */
- public int selectNormalChildrenDeptById(Long deptId);
-
- /**
- * 是否存在部门子节点
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public boolean hasChildByDeptId(Long deptId);
-
- /**
- * 查询部门是否存在用户
- *
- * @param deptId 部门ID
- * @return 结果 true 存在 false 不存在
- */
- public boolean checkDeptExistUser(Long deptId);
-
- /**
- * 校验部门名称是否唯一
- *
- * @param dept 部门信息
- * @return 结果
- */
- public boolean checkDeptNameUnique(SysDept dept);
-
- /**
- * 校验部门是否有数据权限
- *
- * @param deptId 部门id
- */
- public void checkDeptDataScope(Long deptId);
-
- /**
- * 新增保存部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- public int insertDept(SysDept dept);
-
- /**
- * 修改保存部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- public int updateDept(SysDept dept);
-
- /**
- * 保存部门排序
- *
- * @param deptIds 部门ID数组
- * @param orderNums 排序数组
- */
- public void updateDeptSort(String[] deptIds, String[] orderNums);
-
- /**
- * 删除部门管理信息
- *
- * @param deptId 部门ID
- * @return 结果
- */
- public int deleteDeptById(Long deptId);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
deleted file mode 100644
index 6e06bfd..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysDictData;
-
-/**
- * 字典 业务层
- *
- * @author ruoyi
- */
-public interface ISysDictDataService
-{
- /**
- * 根据条件分页查询字典数据
- *
- * @param dictData 字典数据信息
- * @return 字典数据集合信息
- */
- public List<SysDictData> selectDictDataList(SysDictData dictData);
-
- /**
- * 根据字典类型和字典键值查询字典数据信息
- *
- * @param dictType 字典类型
- * @param dictValue 字典键值
- * @return 字典标签
- */
- public String selectDictLabel(String dictType, String dictValue);
-
- /**
- * 根据字典数据ID查询信息
- *
- * @param dictCode 字典数据ID
- * @return 字典数据
- */
- public SysDictData selectDictDataById(Long dictCode);
-
- /**
- * 批量删除字典数据信息
- *
- * @param dictCodes 需要删除的字典数据ID
- */
- public void deleteDictDataByIds(Long[] dictCodes);
-
- /**
- * 新增保存字典数据信息
- *
- * @param dictData 字典数据信息
- * @return 结果
- */
- public int insertDictData(SysDictData dictData);
-
- /**
- * 修改保存字典数据信息
- *
- * @param dictData 字典数据信息
- * @return 结果
- */
- public int updateDictData(SysDictData dictData);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
deleted file mode 100644
index e8534c5..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysDictData;
-import com.ruoyi.system.api.domain.SysDictType;
-
-/**
- * 字典 业务层
- *
- * @author ruoyi
- */
-public interface ISysDictTypeService
-{
- /**
- * 根据条件分页查询字典类型
- *
- * @param dictType 字典类型信息
- * @return 字典类型集合信息
- */
- public List<SysDictType> selectDictTypeList(SysDictType dictType);
-
- /**
- * 根据所有字典类型
- *
- * @return 字典类型集合信息
- */
- public List<SysDictType> selectDictTypeAll();
-
- /**
- * 根据字典类型查询字典数据
- *
- * @param dictType 字典类型
- * @return 字典数据集合信息
- */
- public List<SysDictData> selectDictDataByType(String dictType);
-
- /**
- * 根据字典类型ID查询信息
- *
- * @param dictId 字典类型ID
- * @return 字典类型
- */
- public SysDictType selectDictTypeById(Long dictId);
-
- /**
- * 根据字典类型查询信息
- *
- * @param dictType 字典类型
- * @return 字典类型
- */
- public SysDictType selectDictTypeByType(String dictType);
-
- /**
- * 批量删除字典信息
- *
- * @param dictIds 需要删除的字典ID
- */
- public void deleteDictTypeByIds(Long[] dictIds);
-
- /**
- * 加载字典缓存数据
- */
- public void loadingDictCache();
-
- /**
- * 清空字典缓存数据
- */
- public void clearDictCache();
-
- /**
- * 重置字典缓存数据
- */
- public void resetDictCache();
-
- /**
- * 新增保存字典类型信息
- *
- * @param dictType 字典类型信息
- * @return 结果
- */
- public int insertDictType(SysDictType dictType);
-
- /**
- * 修改保存字典类型信息
- *
- * @param dictType 字典类型信息
- * @return 结果
- */
- public int updateDictType(SysDictType dictType);
-
- /**
- * 校验字典类型称是否唯一
- *
- * @param dictType 字典类型
- * @return 结果
- */
- public boolean checkDictTypeUnique(SysDictType dictType);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
deleted file mode 100644
index 724a6a9..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysLogininfor;
-
-/**
- * 系统访问日志情况信息 服务层
- *
- * @author ruoyi
- */
-public interface ISysLogininforService
-{
- /**
- * 新增系统登录日志
- *
- * @param logininfor 访问日志对象
- */
- public int insertLogininfor(SysLogininfor logininfor);
-
- /**
- * 查询系统登录日志集合
- *
- * @param logininfor 访问日志对象
- * @return 登录记录集合
- */
- public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
-
- /**
- * 批量删除系统登录日志
- *
- * @param infoIds 需要删除的登录日志ID
- * @return 结果
- */
- public int deleteLogininforByIds(Long[] infoIds);
-
- /**
- * 清空系统登录日志
- */
- public void cleanLogininfor();
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
deleted file mode 100644
index eabbd21..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import java.util.Set;
-import com.ruoyi.system.domain.SysMenu;
-import com.ruoyi.system.domain.vo.RouterVo;
-import com.ruoyi.system.domain.vo.TreeSelect;
-
-/**
- * 菜单 业务层
- *
- * @author ruoyi
- */
-public interface ISysMenuService
-{
- /**
- * 根据用户查询系统菜单列表
- *
- * @param userId 用户ID
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuList(Long userId);
-
- /**
- * 根据用户查询系统菜单列表
- *
- * @param menu 菜单信息
- * @param userId 用户ID
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuList(SysMenu menu, Long userId);
-
- /**
- * 根据用户ID查询权限
- *
- * @param userId 用户ID
- * @return 权限列表
- */
- public Set<String> selectMenuPermsByUserId(Long userId);
-
- /**
- * 根据角色ID查询权限
- *
- * @param roleId 角色ID
- * @return 权限列表
- */
- public Set<String> selectMenuPermsByRoleId(Long roleId);
-
- /**
- * 根据用户ID查询菜单树信息
- *
- * @param userId 用户ID
- * @return 菜单列表
- */
- public List<SysMenu> selectMenuTreeByUserId(Long userId);
-
- /**
- * 根据角色ID查询菜单树信息
- *
- * @param roleId 角色ID
- * @return 选中菜单列表
- */
- public List<Long> selectMenuListByRoleId(Long roleId);
-
- /**
- * 构建前端路由所需要的菜单
- *
- * @param menus 菜单列表
- * @return 路由列表
- */
- public List<RouterVo> buildMenus(List<SysMenu> menus);
-
- /**
- * 构建前端所需要树结构
- *
- * @param menus 菜单列表
- * @return 树结构列表
- */
- public List<SysMenu> buildMenuTree(List<SysMenu> menus);
-
- /**
- * 构建前端所需要下拉树结构
- *
- * @param menus 菜单列表
- * @return 下拉树结构列表
- */
- public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus);
-
- /**
- * 根据菜单ID查询信息
- *
- * @param menuId 菜单ID
- * @return 菜单信息
- */
- public SysMenu selectMenuById(Long menuId);
-
- /**
- * 是否存在菜单子节点
- *
- * @param menuId 菜单ID
- * @return 结果 true 存在 false 不存在
- */
- public boolean hasChildByMenuId(Long menuId);
-
- /**
- * 查询菜单是否存在角色
- *
- * @param menuId 菜单ID
- * @return 结果 true 存在 false 不存在
- */
- public boolean checkMenuExistRole(Long menuId);
-
- /**
- * 新增保存菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public int insertMenu(SysMenu menu);
-
- /**
- * 修改保存菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public int updateMenu(SysMenu menu);
-
- /**
- * 保存菜单排序
- *
- * @param menuIds 菜单ID
- * @param orderNums 排序ID
- */
- public void updateMenuSort(String[] menuIds, String[] orderNums);
-
- /**
- * 删除菜单管理信息
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- public int deleteMenuById(Long menuId);
-
- /**
- * 校验菜单名称是否唯一
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public boolean checkMenuNameUnique(SysMenu menu);
-
- /**
- * 校验路由组合是否唯一
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public boolean checkRouteConfigUnique(SysMenu menu);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeReadService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeReadService.java
deleted file mode 100644
index 56e958a..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeReadService.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import java.util.Map;
-import com.ruoyi.system.domain.SysNotice;
-
-/**
- * 公告已读记录 服务层
- *
- * @author ruoyi
- */
-public interface ISysNoticeReadService
-{
- /**
- * 标记已读(幂等,重复调用不报错)
- *
- * @param noticeId 公告ID
- * @param userId 用户ID
- */
- public void markRead(Long noticeId, Long userId);
-
- /**
- * 查询某用户未读公告数量
- *
- * @param userId 用户ID
- * @return 未读数量
- */
- public int selectUnreadCount(Long userId);
-
- /**
- * 查询公告列表并标记当前用户已读状态(用于首页展示)
- *
- * @param userId 用户ID
- * @param limit 最多返回条数
- * @return 带 isRead 标记的公告列表
- */
- public List<SysNotice> selectNoticeListWithReadStatus(Long userId, int limit);
-
- /**
- * 批量标记已读
- *
- * @param userId 用户ID
- * @param noticeIds 公告ID数组
- */
- public void markReadBatch(Long userId, Long[] noticeIds);
-
- /**
- * 查询已阅读某公告的用户列表
- *
- * @param noticeId 公告ID
- * @param searchValue 搜索值
- * @return 已读用户列表
- */
- public List<Map<String, Object>> selectReadUsersByNoticeId(Long noticeId, String searchValue);
-
- /**
- * 删除公告时清理对应已读记录
- *
- * @param noticeIds 公告ID数组
- */
- public void deleteByNoticeIds(Long[] noticeIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
deleted file mode 100644
index 7252dc2..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysNotice;
-
-/**
- * 公告 服务层
- *
- * @author ruoyi
- */
-public interface ISysNoticeService
-{
- /**
- * 查询公告信息
- *
- * @param noticeId 公告ID
- * @return 公告信息
- */
- public SysNotice selectNoticeById(Long noticeId);
-
- /**
- * 查询公告列表
- *
- * @param notice 公告信息
- * @return 公告集合
- */
- public List<SysNotice> selectNoticeList(SysNotice notice);
-
- /**
- * 新增公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- public int insertNotice(SysNotice notice);
-
- /**
- * 修改公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- public int updateNotice(SysNotice notice);
-
- /**
- * 删除公告信息
- *
- * @param noticeId 公告ID
- * @return 结果
- */
- public int deleteNoticeById(Long noticeId);
-
- /**
- * 批量删除公告信息
- *
- * @param noticeIds 需要删除的公告ID
- * @return 结果
- */
- public int deleteNoticeByIds(Long[] noticeIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
deleted file mode 100644
index 42c94f1..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysOperLog;
-
-/**
- * 操作日志 服务层
- *
- * @author ruoyi
- */
-public interface ISysOperLogService
-{
- /**
- * 新增操作日志
- *
- * @param operLog 操作日志对象
- * @return 结果
- */
- public int insertOperlog(SysOperLog operLog);
-
- /**
- * 查询系统操作日志集合
- *
- * @param operLog 操作日志对象
- * @return 操作日志集合
- */
- public List<SysOperLog> selectOperLogList(SysOperLog operLog);
-
- /**
- * 批量删除系统操作日志
- *
- * @param operIds 需要删除的操作日志ID
- * @return 结果
- */
- public int deleteOperLogByIds(Long[] operIds);
-
- /**
- * 查询操作日志详细
- *
- * @param operId 操作ID
- * @return 操作日志对象
- */
- public SysOperLog selectOperLogById(Long operId);
-
- /**
- * 清空操作日志
- */
- public void cleanOperLog();
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java
deleted file mode 100644
index bc3bf32..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPermissionService.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.Set;
-
-import com.ruoyi.system.api.domain.SysUser;
-
-/**
- * 权限信息 服务层
- *
- * @author ruoyi
- */
-public interface ISysPermissionService
-{
- /**
- * 获取角色数据权限
- *
- * @param userId 用户Id
- * @return 角色权限信息
- */
- public Set<String> getRolePermission(SysUser user);
-
- /**
- * 获取菜单数据权限
- *
- * @param userId 用户Id
- * @return 菜单权限信息
- */
- public Set<String> getMenuPermission(SysUser user);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
deleted file mode 100644
index 590634b..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysPost;
-
-/**
- * 岗位信息 服务层
- *
- * @author ruoyi
- */
-public interface ISysPostService
-{
- /**
- * 查询岗位信息集合
- *
- * @param post 岗位信息
- * @return 岗位列表
- */
- public List<SysPost> selectPostList(SysPost post);
-
- /**
- * 查询所有岗位
- *
- * @return 岗位列表
- */
- public List<SysPost> selectPostAll();
-
- /**
- * 通过岗位ID查询岗位信息
- *
- * @param postId 岗位ID
- * @return 角色对象信息
- */
- public SysPost selectPostById(Long postId);
-
- /**
- * 根据用户ID获取岗位选择框列表
- *
- * @param userId 用户ID
- * @return 选中岗位ID列表
- */
- public List<Long> selectPostListByUserId(Long userId);
-
- /**
- * 校验岗位名称
- *
- * @param post 岗位信息
- * @return 结果
- */
- public boolean checkPostNameUnique(SysPost post);
-
- /**
- * 校验岗位编码
- *
- * @param post 岗位信息
- * @return 结果
- */
- public boolean checkPostCodeUnique(SysPost post);
-
- /**
- * 通过岗位ID查询岗位使用数量
- *
- * @param postId 岗位ID
- * @return 结果
- */
- public int countUserPostById(Long postId);
-
- /**
- * 删除岗位信息
- *
- * @param postId 岗位ID
- * @return 结果
- */
- public int deletePostById(Long postId);
-
- /**
- * 批量删除岗位信息
- *
- * @param postIds 需要删除的岗位ID
- * @return 结果
- */
- public int deletePostByIds(Long[] postIds);
-
- /**
- * 新增保存岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- public int insertPost(SysPost post);
-
- /**
- * 修改保存岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- public int updatePost(SysPost post);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
deleted file mode 100644
index 7f572fd..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import java.util.Set;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.domain.SysUserRole;
-
-/**
- * 角色业务层
- *
- * @author ruoyi
- */
-public interface ISysRoleService
-{
- /**
- * 根据条件分页查询角色数据
- *
- * @param role 角色信息
- * @return 角色数据集合信息
- */
- public List<SysRole> selectRoleList(SysRole role);
-
- /**
- * 根据用户ID查询角色列表
- *
- * @param userId 用户ID
- * @return 角色列表
- */
- public List<SysRole> selectRolesByUserId(Long userId);
-
- /**
- * 根据用户ID查询角色权限
- *
- * @param userId 用户ID
- * @return 权限列表
- */
- public Set<String> selectRolePermissionByUserId(Long userId);
-
- /**
- * 查询所有角色
- *
- * @return 角色列表
- */
- public List<SysRole> selectRoleAll();
-
- /**
- * 根据用户ID获取角色选择框列表
- *
- * @param userId 用户ID
- * @return 选中角色ID列表
- */
- public List<Long> selectRoleListByUserId(Long userId);
-
- /**
- * 通过角色ID查询角色
- *
- * @param roleId 角色ID
- * @return 角色对象信息
- */
- public SysRole selectRoleById(Long roleId);
-
- /**
- * 校验角色名称是否唯一
- *
- * @param role 角色信息
- * @return 结果
- */
- public boolean checkRoleNameUnique(SysRole role);
-
- /**
- * 校验角色权限是否唯一
- *
- * @param role 角色信息
- * @return 结果
- */
- public boolean checkRoleKeyUnique(SysRole role);
-
- /**
- * 校验角色是否允许操作
- *
- * @param role 角色信息
- */
- public void checkRoleAllowed(SysRole role);
-
- /**
- * 校验角色是否有数据权限
- *
- * @param roleIds 角色id
- */
- public void checkRoleDataScope(Long... roleIds);
-
- /**
- * 通过角色ID查询角色使用数量
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int countUserRoleByRoleId(Long roleId);
-
- /**
- * 新增保存角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- public int insertRole(SysRole role);
-
- /**
- * 修改保存角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- public int updateRole(SysRole role);
-
- /**
- * 修改角色状态
- *
- * @param role 角色信息
- * @return 结果
- */
- public int updateRoleStatus(SysRole role);
-
- /**
- * 修改数据权限信息
- *
- * @param role 角色信息
- * @return 结果
- */
- public int authDataScope(SysRole role);
-
- /**
- * 通过角色ID删除角色
- *
- * @param roleId 角色ID
- * @return 结果
- */
- public int deleteRoleById(Long roleId);
-
- /**
- * 批量删除角色信息
- *
- * @param roleIds 需要删除的角色ID
- * @return 结果
- */
- public int deleteRoleByIds(Long[] roleIds);
-
- /**
- * 取消授权用户角色
- *
- * @param userRole 用户和角色关联信息
- * @return 结果
- */
- public int deleteAuthUser(SysUserRole userRole);
-
- /**
- * 批量取消授权用户角色
- *
- * @param roleId 角色ID
- * @param userIds 需要取消授权的用户数据ID
- * @return 结果
- */
- public int deleteAuthUsers(Long roleId, Long[] userIds);
-
- /**
- * 批量选择授权用户角色
- *
- * @param roleId 角色ID
- * @param userIds 需要删除的用户数据ID
- * @return 结果
- */
- public int insertAuthUsers(Long roleId, Long[] userIds);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
deleted file mode 100644
index dd602b2..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.ruoyi.system.service;
-
-import com.ruoyi.system.api.model.LoginUser;
-import com.ruoyi.system.domain.SysUserOnline;
-
-/**
- * 在线用户 服务层
- *
- * @author ruoyi
- */
-public interface ISysUserOnlineService
-{
- /**
- * 通过登录地址查询信息
- *
- * @param ipaddr 登录地址
- * @param user 用户信息
- * @return 在线用户信息
- */
- public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user);
-
- /**
- * 通过用户名称查询信息
- *
- * @param userName 用户名称
- * @param user 用户信息
- * @return 在线用户信息
- */
- public SysUserOnline selectOnlineByUserName(String userName, LoginUser user);
-
- /**
- * 通过登录地址/用户名称查询信息
- *
- * @param ipaddr 登录地址
- * @param userName 用户名称
- * @param user 用户信息
- * @return 在线用户信息
- */
- public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user);
-
- /**
- * 设置在线用户信息
- *
- * @param user 用户信息
- * @return 在线用户
- */
- public SysUserOnline loginUserToUserOnline(LoginUser user);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
deleted file mode 100644
index 107fe9e..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
+++ /dev/null
@@ -1,214 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.api.domain.SysUser;
-
-/**
- * 用户 业务层
- *
- * @author ruoyi
- */
-public interface ISysUserService
-{
- /**
- * 根据条件分页查询用户列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectUserList(SysUser user);
-
- /**
- * 根据条件分页查询已分配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectAllocatedList(SysUser user);
-
- /**
- * 根据条件分页查询未分配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- public List<SysUser> selectUnallocatedList(SysUser user);
-
- /**
- * 通过用户名查询用户
- *
- * @param userName 用户名
- * @return 用户对象信息
- */
- public SysUser selectUserByUserName(String userName);
-
- /**
- * 通过用户ID查询用户
- *
- * @param userId 用户ID
- * @return 用户对象信息
- */
- public SysUser selectUserById(Long userId);
-
- /**
- * 根据用户ID查询用户所属角色组
- *
- * @param userName 用户名
- * @return 结果
- */
- public String selectUserRoleGroup(String userName);
-
- /**
- * 根据用户ID查询用户所属岗位组
- *
- * @param userName 用户名
- * @return 结果
- */
- public String selectUserPostGroup(String userName);
-
- /**
- * 校验用户名称是否唯一
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean checkUserNameUnique(SysUser user);
-
- /**
- * 校验手机号码是否唯一
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean checkPhoneUnique(SysUser user);
-
- /**
- * 校验email是否唯一
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean checkEmailUnique(SysUser user);
-
- /**
- * 校验用户是否允许操作
- *
- * @param user 用户信息
- */
- public void checkUserAllowed(SysUser user);
-
- /**
- * 校验用户是否有数据权限
- *
- * @param userId 用户id
- */
- public void checkUserDataScope(Long userId);
-
- /**
- * 新增用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public int insertUser(SysUser user);
-
- /**
- * 注册用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean registerUser(SysUser user);
-
- /**
- * 修改用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public int updateUser(SysUser user);
-
- /**
- * 用户授权角色
- *
- * @param userId 用户ID
- * @param roleIds 角色组
- */
- public void insertUserAuth(Long userId, Long[] roleIds);
-
- /**
- * 修改用户状态
- *
- * @param user 用户信息
- * @return 结果
- */
- public int updateUserStatus(SysUser user);
-
- /**
- * 修改用户基本信息
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean updateUserProfile(SysUser user);
-
- /**
- * 修改用户头像
- *
- * @param userId 用户ID
- * @param avatar 头像地址
- * @return 结果
- */
- public boolean updateUserAvatar(Long userId, String avatar);
-
- /**
- * 更新用户登录信息(IP和登录时间)
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean updateLoginInfo(SysUser user);
-
- /**
- * 重置用户密码
- *
- * @param user 用户信息
- * @return 结果
- */
- public int resetPwd(SysUser user);
-
- /**
- * 重置用户密码
- *
- * @param userId 用户ID
- * @param password 密码
- * @return 结果
- */
- public int resetUserPwd(Long userId, String password);
-
- /**
- * 通过用户ID删除用户
- *
- * @param userId 用户ID
- * @return 结果
- */
- public int deleteUserById(Long userId);
-
- /**
- * 批量删除用户信息
- *
- * @param userIds 需要删除的用户ID
- * @return 结果
- */
- public int deleteUserByIds(Long[] userIds);
-
- /**
- * 导入用户数据
- *
- * @param userList 用户数据列表
- * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
- * @param operName 操作用户
- * @return 结果
- */
- public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
deleted file mode 100644
index 8a142d6..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.Collection;
-import java.util.List;
-import jakarta.annotation.PostConstruct;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.redis.service.RedisService;
-import com.ruoyi.system.domain.SysConfig;
-import com.ruoyi.system.mapper.SysConfigMapper;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 参数配置 服务层实现
- *
- * @author ruoyi
- */
-@Service
-public class SysConfigServiceImpl implements ISysConfigService
-{
- @Autowired
- private SysConfigMapper configMapper;
-
- @Autowired
- private RedisService redisService;
-
- /**
- * 项目启动时,初始化参数到缓存
- */
- @PostConstruct
- public void init()
- {
- loadingConfigCache();
- }
-
- /**
- * 查询参数配置信息
- *
- * @param configId 参数配置ID
- * @return 参数配置信息
- */
- @Override
- public SysConfig selectConfigById(Long configId)
- {
- SysConfig config = new SysConfig();
- config.setConfigId(configId);
- return configMapper.selectConfig(config);
- }
-
- /**
- * 根据键名查询参数配置信息
- *
- * @param configKey 参数key
- * @return 参数键值
- */
- @Override
- public String selectConfigByKey(String configKey)
- {
- String configValue = Convert.toStr(redisService.getCacheObject(getCacheKey(configKey)));
- if (StringUtils.isNotEmpty(configValue))
- {
- return configValue;
- }
- SysConfig config = new SysConfig();
- config.setConfigKey(configKey);
- SysConfig retConfig = configMapper.selectConfig(config);
- if (StringUtils.isNotNull(retConfig))
- {
- redisService.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
- return retConfig.getConfigValue();
- }
- return StringUtils.EMPTY;
- }
-
- /**
- * 查询参数配置列表
- *
- * @param config 参数配置信息
- * @return 参数配置集合
- */
- @Override
- public List<SysConfig> selectConfigList(SysConfig config)
- {
- return configMapper.selectConfigList(config);
- }
-
- /**
- * 新增参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- @Override
- public int insertConfig(SysConfig config)
- {
- int row = configMapper.insertConfig(config);
- if (row > 0)
- {
- redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
- }
- return row;
- }
-
- /**
- * 修改参数配置
- *
- * @param config 参数配置信息
- * @return 结果
- */
- @Override
- public int updateConfig(SysConfig config)
- {
- SysConfig temp = configMapper.selectConfigById(config.getConfigId());
- if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
- {
- redisService.deleteObject(getCacheKey(temp.getConfigKey()));
- }
-
- int row = configMapper.updateConfig(config);
- if (row > 0)
- {
- redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
- }
- return row;
- }
-
- /**
- * 批量删除参数信息
- *
- * @param configIds 需要删除的参数ID
- */
- @Override
- public void deleteConfigByIds(Long[] configIds)
- {
- for (Long configId : configIds)
- {
- SysConfig config = selectConfigById(configId);
- if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
- {
- throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
- }
- configMapper.deleteConfigById(configId);
- redisService.deleteObject(getCacheKey(config.getConfigKey()));
- }
- }
-
- /**
- * 加载参数缓存数据
- */
- @Override
- public void loadingConfigCache()
- {
- List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
- for (SysConfig config : configsList)
- {
- redisService.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
- }
- }
-
- /**
- * 清空参数缓存数据
- */
- @Override
- public void clearConfigCache()
- {
- Collection<String> keys = redisService.keys(CacheConstants.SYS_CONFIG_KEY + "*");
- redisService.deleteObject(keys);
- }
-
- /**
- * 重置参数缓存数据
- */
- @Override
- public void resetConfigCache()
- {
- clearConfigCache();
- loadingConfigCache();
- }
-
- /**
- * 校验参数键名是否唯一
- *
- * @param config 参数配置信息
- * @return 结果
- */
- @Override
- public boolean checkConfigKeyUnique(SysConfig config)
- {
- Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
- SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());
- if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 设置cache key
- *
- * @param configKey 参数键
- * @return 缓存键key
- */
- private String getCacheKey(String configKey)
- {
- return CacheConstants.SYS_CONFIG_KEY + configKey;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
deleted file mode 100644
index 8a01479..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
+++ /dev/null
@@ -1,364 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.stream.Collectors;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.datascope.annotation.DataScope;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysDept;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.domain.vo.TreeSelect;
-import com.ruoyi.system.mapper.SysDeptMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.service.ISysDeptService;
-
-/**
- * 部门管理 服务实现
- *
- * @author ruoyi
- */
-@Service
-public class SysDeptServiceImpl implements ISysDeptService
-{
- @Autowired
- private SysDeptMapper deptMapper;
-
- @Autowired
- private SysRoleMapper roleMapper;
-
- /**
- * 查询部门管理数据
- *
- * @param dept 部门信息
- * @return 部门信息集合
- */
- @Override
- @DataScope(deptAlias = "d")
- public List<SysDept> selectDeptList(SysDept dept)
- {
- return deptMapper.selectDeptList(dept);
- }
-
- /**
- * 查询部门树结构信息
- *
- * @param dept 部门信息
- * @return 部门树信息集合
- */
- @Override
- public List<TreeSelect> selectDeptTreeList(SysDept dept)
- {
- List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
- return buildDeptTreeSelect(depts);
- }
-
- /**
- * 构建前端所需要树结构
- *
- * @param depts 部门列表
- * @return 树结构列表
- */
- @Override
- public List<SysDept> buildDeptTree(List<SysDept> depts)
- {
- List<SysDept> returnList = new ArrayList<SysDept>();
- List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
- for (SysDept dept : depts)
- {
- // 如果是顶级节点, 遍历该父节点的所有子节点
- if (!tempList.contains(dept.getParentId()))
- {
- recursionFn(depts, dept);
- returnList.add(dept);
- }
- }
- if (returnList.isEmpty())
- {
- returnList = depts;
- }
- return returnList;
- }
-
- /**
- * 构建前端所需要下拉树结构
- *
- * @param depts 部门列表
- * @return 下拉树结构列表
- */
- @Override
- public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts)
- {
- List<SysDept> deptTrees = buildDeptTree(depts);
- return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
- }
-
- /**
- * 根据角色ID查询部门树信息
- *
- * @param roleId 角色ID
- * @return 选中部门列表
- */
- @Override
- public List<Long> selectDeptListByRoleId(Long roleId)
- {
- SysRole role = roleMapper.selectRoleById(roleId);
- return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
- }
-
- /**
- * 根据部门ID查询信息
- *
- * @param deptId 部门ID
- * @return 部门信息
- */
- @Override
- public SysDept selectDeptById(Long deptId)
- {
- return deptMapper.selectDeptById(deptId);
- }
-
- /**
- * 根据ID查询所有子部门(正常状态)
- *
- * @param deptId 部门ID
- * @return 子部门数
- */
- @Override
- public int selectNormalChildrenDeptById(Long deptId)
- {
- return deptMapper.selectNormalChildrenDeptById(deptId);
- }
-
- /**
- * 是否存在子节点
- *
- * @param deptId 部门ID
- * @return 结果
- */
- @Override
- public boolean hasChildByDeptId(Long deptId)
- {
- int result = deptMapper.hasChildByDeptId(deptId);
- return result > 0;
- }
-
- /**
- * 查询部门是否存在用户
- *
- * @param deptId 部门ID
- * @return 结果 true 存在 false 不存在
- */
- @Override
- public boolean checkDeptExistUser(Long deptId)
- {
- int result = deptMapper.checkDeptExistUser(deptId);
- return result > 0;
- }
-
- /**
- * 校验部门名称是否唯一
- *
- * @param dept 部门信息
- * @return 结果
- */
- @Override
- public boolean checkDeptNameUnique(SysDept dept)
- {
- Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
- SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
- if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验部门是否有数据权限
- *
- * @param deptId 部门id
- */
- @Override
- public void checkDeptDataScope(Long deptId)
- {
- if (!SecurityUtils.isAdmin() && StringUtils.isNotNull(deptId))
- {
- SysDept dept = new SysDept();
- dept.setDeptId(deptId);
- List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
- if (StringUtils.isEmpty(depts))
- {
- throw new ServiceException("没有权限访问部门数据!");
- }
- }
- }
-
- /**
- * 新增保存部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- @Override
- public int insertDept(SysDept dept)
- {
- SysDept info = deptMapper.selectDeptById(dept.getParentId());
- // 如果父节点不为正常状态,则不允许新增子节点
- if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
- {
- throw new ServiceException("部门停用,不允许新增");
- }
- dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
- return deptMapper.insertDept(dept);
- }
-
- /**
- * 修改保存部门信息
- *
- * @param dept 部门信息
- * @return 结果
- */
- @Override
- public int updateDept(SysDept dept)
- {
- SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
- SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
- if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
- {
- String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
- String oldAncestors = oldDept.getAncestors();
- dept.setAncestors(newAncestors);
- updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
- }
- int result = deptMapper.updateDept(dept);
- if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
- && !StringUtils.equals("0", dept.getAncestors()))
- {
- // 如果该部门是启用状态,则启用该部门的所有上级部门
- updateParentDeptStatusNormal(dept);
- }
- return result;
- }
-
- /**
- * 修改该部门的父级部门状态
- *
- * @param dept 当前部门
- */
- private void updateParentDeptStatusNormal(SysDept dept)
- {
- String ancestors = dept.getAncestors();
- Long[] deptIds = Convert.toLongArray(ancestors);
- deptMapper.updateDeptStatusNormal(deptIds);
- }
-
- /**
- * 修改子元素关系
- *
- * @param deptId 被修改的部门ID
- * @param newAncestors 新的父ID集合
- * @param oldAncestors 旧的父ID集合
- */
- public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
- {
- List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
- for (SysDept child : children)
- {
- child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
- }
- if (children.size() > 0)
- {
- deptMapper.updateDeptChildren(children);
- }
- }
-
- /**
- * 保存部门排序
- *
- * @param deptIds 部门ID数组
- * @param orderNums 排序数组
- */
- @Override
- @Transactional
- public void updateDeptSort(String[] deptIds, String[] orderNums)
- {
- try
- {
- for (int i = 0; i < deptIds.length; i++)
- {
- SysDept dept = new SysDept();
- dept.setDeptId(Convert.toLong(deptIds[i]));
- dept.setOrderNum(Convert.toInt(orderNums[i]));
- deptMapper.updateDeptSort(dept);
- }
- }
- catch (Exception e)
- {
- throw new ServiceException("保存排序异常,请联系管理员");
- }
- }
-
- /**
- * 删除部门管理信息
- *
- * @param deptId 部门ID
- * @return 结果
- */
- @Override
- public int deleteDeptById(Long deptId)
- {
- return deptMapper.deleteDeptById(deptId);
- }
-
- /**
- * 递归列表
- */
- private void recursionFn(List<SysDept> list, SysDept t)
- {
- // 得到子节点列表
- List<SysDept> childList = getChildList(list, t);
- t.setChildren(childList);
- for (SysDept tChild : childList)
- {
- if (hasChild(list, tChild))
- {
- recursionFn(list, tChild);
- }
- }
- }
-
- /**
- * 得到子节点列表
- */
- private List<SysDept> getChildList(List<SysDept> list, SysDept t)
- {
- List<SysDept> tlist = new ArrayList<SysDept>();
- Iterator<SysDept> it = list.iterator();
- while (it.hasNext())
- {
- SysDept n = (SysDept) it.next();
- if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue())
- {
- tlist.add(n);
- }
- }
- return tlist;
- }
-
- /**
- * 判断是否有子节点
- */
- private boolean hasChild(List<SysDept> list, SysDept t)
- {
- return getChildList(list, t).size() > 0 ? true : false;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
deleted file mode 100644
index 791db69..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.security.utils.DictUtils;
-import com.ruoyi.system.api.domain.SysDictData;
-import com.ruoyi.system.mapper.SysDictDataMapper;
-import com.ruoyi.system.service.ISysDictDataService;
-
-/**
- * 字典 业务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysDictDataServiceImpl implements ISysDictDataService
-{
- @Autowired
- private SysDictDataMapper dictDataMapper;
-
- /**
- * 根据条件分页查询字典数据
- *
- * @param dictData 字典数据信息
- * @return 字典数据集合信息
- */
- @Override
- public List<SysDictData> selectDictDataList(SysDictData dictData)
- {
- return dictDataMapper.selectDictDataList(dictData);
- }
-
- /**
- * 根据字典类型和字典键值查询字典数据信息
- *
- * @param dictType 字典类型
- * @param dictValue 字典键值
- * @return 字典标签
- */
- @Override
- public String selectDictLabel(String dictType, String dictValue)
- {
- return dictDataMapper.selectDictLabel(dictType, dictValue);
- }
-
- /**
- * 根据字典数据ID查询信息
- *
- * @param dictCode 字典数据ID
- * @return 字典数据
- */
- @Override
- public SysDictData selectDictDataById(Long dictCode)
- {
- return dictDataMapper.selectDictDataById(dictCode);
- }
-
- /**
- * 批量删除字典数据信息
- *
- * @param dictCodes 需要删除的字典数据ID
- */
- @Override
- public void deleteDictDataByIds(Long[] dictCodes)
- {
- for (Long dictCode : dictCodes)
- {
- SysDictData data = selectDictDataById(dictCode);
- dictDataMapper.deleteDictDataById(dictCode);
- List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
- DictUtils.setDictCache(data.getDictType(), dictDatas);
- }
- }
-
- /**
- * 新增保存字典数据信息
- *
- * @param data 字典数据信息
- * @return 结果
- */
- @Override
- public int insertDictData(SysDictData data)
- {
- int row = dictDataMapper.insertDictData(data);
- if (row > 0)
- {
- List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
- DictUtils.setDictCache(data.getDictType(), dictDatas);
- }
- return row;
- }
-
- /**
- * 修改保存字典数据信息
- *
- * @param data 字典数据信息
- * @return 结果
- */
- @Override
- public int updateDictData(SysDictData data)
- {
- int row = dictDataMapper.updateDictData(data);
- if (row > 0)
- {
- List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
- DictUtils.setDictCache(data.getDictType(), dictDatas);
- }
- return row;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
deleted file mode 100644
index df8d4df..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import jakarta.annotation.PostConstruct;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.security.utils.DictUtils;
-import com.ruoyi.system.api.domain.SysDictData;
-import com.ruoyi.system.api.domain.SysDictType;
-import com.ruoyi.system.mapper.SysDictDataMapper;
-import com.ruoyi.system.mapper.SysDictTypeMapper;
-import com.ruoyi.system.service.ISysDictTypeService;
-
-/**
- * 字典 业务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysDictTypeServiceImpl implements ISysDictTypeService
-{
- @Autowired
- private SysDictTypeMapper dictTypeMapper;
-
- @Autowired
- private SysDictDataMapper dictDataMapper;
-
- /**
- * 项目启动时,初始化字典到缓存
- */
- @PostConstruct
- public void init()
- {
- loadingDictCache();
- }
-
- /**
- * 根据条件分页查询字典类型
- *
- * @param dictType 字典类型信息
- * @return 字典类型集合信息
- */
- @Override
- public List<SysDictType> selectDictTypeList(SysDictType dictType)
- {
- return dictTypeMapper.selectDictTypeList(dictType);
- }
-
- /**
- * 根据所有字典类型
- *
- * @return 字典类型集合信息
- */
- @Override
- public List<SysDictType> selectDictTypeAll()
- {
- return dictTypeMapper.selectDictTypeAll();
- }
-
- /**
- * 根据字典类型查询字典数据
- *
- * @param dictType 字典类型
- * @return 字典数据集合信息
- */
- @Override
- public List<SysDictData> selectDictDataByType(String dictType)
- {
- List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
- if (StringUtils.isNotEmpty(dictDatas))
- {
- return dictDatas;
- }
- dictDatas = dictDataMapper.selectDictDataByType(dictType);
- if (StringUtils.isNotEmpty(dictDatas))
- {
- DictUtils.setDictCache(dictType, dictDatas);
- return dictDatas;
- }
- return null;
- }
-
- /**
- * 根据字典类型ID查询信息
- *
- * @param dictId 字典类型ID
- * @return 字典类型
- */
- @Override
- public SysDictType selectDictTypeById(Long dictId)
- {
- return dictTypeMapper.selectDictTypeById(dictId);
- }
-
- /**
- * 根据字典类型查询信息
- *
- * @param dictType 字典类型
- * @return 字典类型
- */
- @Override
- public SysDictType selectDictTypeByType(String dictType)
- {
- return dictTypeMapper.selectDictTypeByType(dictType);
- }
-
- /**
- * 批量删除字典类型信息
- *
- * @param dictIds 需要删除的字典ID
- */
- @Override
- public void deleteDictTypeByIds(Long[] dictIds)
- {
- for (Long dictId : dictIds)
- {
- SysDictType dictType = selectDictTypeById(dictId);
- if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0)
- {
- throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
- }
- dictTypeMapper.deleteDictTypeById(dictId);
- DictUtils.removeDictCache(dictType.getDictType());
- }
- }
-
- /**
- * 加载字典缓存数据
- */
- @Override
- public void loadingDictCache()
- {
- SysDictData dictData = new SysDictData();
- dictData.setStatus("0");
- Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
- for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())
- {
- DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
- }
- }
-
- /**
- * 清空字典缓存数据
- */
- @Override
- public void clearDictCache()
- {
- DictUtils.clearDictCache();
- }
-
- /**
- * 重置字典缓存数据
- */
- @Override
- public void resetDictCache()
- {
- clearDictCache();
- loadingDictCache();
- }
-
- /**
- * 新增保存字典类型信息
- *
- * @param dict 字典类型信息
- * @return 结果
- */
- @Override
- public int insertDictType(SysDictType dict)
- {
- int row = dictTypeMapper.insertDictType(dict);
- if (row > 0)
- {
- DictUtils.setDictCache(dict.getDictType(), null);
- }
- return row;
- }
-
- /**
- * 修改保存字典类型信息
- *
- * @param dict 字典类型信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int updateDictType(SysDictType dict)
- {
- SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());
- dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());
- int row = dictTypeMapper.updateDictType(dict);
- if (row > 0)
- {
- List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
- DictUtils.setDictCache(dict.getDictType(), dictDatas);
- }
- return row;
- }
-
- /**
- * 校验字典类型称是否唯一
- *
- * @param dict 字典类型
- * @return 结果
- */
- @Override
- public boolean checkDictTypeUnique(SysDictType dict)
- {
- Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
- SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());
- if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
deleted file mode 100644
index ca823ab..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.api.domain.SysLogininfor;
-import com.ruoyi.system.mapper.SysLogininforMapper;
-import com.ruoyi.system.service.ISysLogininforService;
-
-/**
- * 系统访问日志情况信息 服务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysLogininforServiceImpl implements ISysLogininforService
-{
-
- @Autowired
- private SysLogininforMapper logininforMapper;
-
- /**
- * 新增系统登录日志
- *
- * @param logininfor 访问日志对象
- */
- @Override
- public int insertLogininfor(SysLogininfor logininfor)
- {
- return logininforMapper.insertLogininfor(logininfor);
- }
-
- /**
- * 查询系统登录日志集合
- *
- * @param logininfor 访问日志对象
- * @return 登录记录集合
- */
- @Override
- public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor)
- {
- return logininforMapper.selectLogininforList(logininfor);
- }
-
- /**
- * 批量删除系统登录日志
- *
- * @param infoIds 需要删除的登录日志ID
- * @return 结果
- */
- @Override
- public int deleteLogininforByIds(Long[] infoIds)
- {
- return logininforMapper.deleteLogininforByIds(infoIds);
- }
-
- /**
- * 清空系统登录日志
- */
- @Override
- public void cleanLogininfor()
- {
- logininforMapper.cleanLogininfor();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
deleted file mode 100644
index f52c5ac..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
+++ /dev/null
@@ -1,618 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.domain.SysMenu;
-import com.ruoyi.system.domain.vo.MetaVo;
-import com.ruoyi.system.domain.vo.RouterVo;
-import com.ruoyi.system.domain.vo.TreeSelect;
-import com.ruoyi.system.mapper.SysMenuMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysRoleMenuMapper;
-import com.ruoyi.system.service.ISysMenuService;
-
-/**
- * 菜单 业务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysMenuServiceImpl implements ISysMenuService
-{
- private static final Logger log = LoggerFactory.getLogger(SysMenuServiceImpl.class);
-
- public static final String PREMISSION_STRING = "perms[\"{0}\"]";
-
- public static final Long MENU_ROOT_ID = 0L;
-
- @Autowired
- private SysMenuMapper menuMapper;
-
- @Autowired
- private SysRoleMapper roleMapper;
-
- @Autowired
- private SysRoleMenuMapper roleMenuMapper;
-
- /**
- * 根据用户查询系统菜单列表
- *
- * @param userId 用户ID
- * @return 菜单列表
- */
- @Override
- public List<SysMenu> selectMenuList(Long userId)
- {
- return selectMenuList(new SysMenu(), userId);
- }
-
- /**
- * 查询系统菜单列表
- *
- * @param menu 菜单信息
- * @return 菜单列表
- */
- @Override
- public List<SysMenu> selectMenuList(SysMenu menu, Long userId)
- {
- List<SysMenu> menuList = null;
- // 管理员显示所有菜单信息
- if (SecurityUtils.isAdmin(userId))
- {
- menuList = menuMapper.selectMenuList(menu);
- }
- else
- {
- menu.getParams().put("userId", userId);
- menuList = menuMapper.selectMenuListByUserId(menu);
- }
- return menuList;
- }
-
- /**
- * 根据用户ID查询权限
- *
- * @param userId 用户ID
- * @return 权限列表
- */
- @Override
- public Set<String> selectMenuPermsByUserId(Long userId)
- {
- List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
- Set<String> permsSet = new HashSet<>();
- for (String perm : perms)
- {
- if (StringUtils.isNotEmpty(perm))
- {
- permsSet.addAll(Arrays.asList(perm.trim().split(",")));
- }
- }
- return permsSet;
- }
-
- /**
- * 根据角色ID查询权限
- *
- * @param roleId 角色ID
- * @return 权限列表
- */
- @Override
- public Set<String> selectMenuPermsByRoleId(Long roleId)
- {
- List<String> perms = menuMapper.selectMenuPermsByRoleId(roleId);
- Set<String> permsSet = new HashSet<>();
- for (String perm : perms)
- {
- if (StringUtils.isNotEmpty(perm))
- {
- permsSet.addAll(Arrays.asList(perm.trim().split(",")));
- }
- }
- return permsSet;
- }
-
- /**
- * 根据用户ID查询菜单
- *
- * @param userId 用户名称
- * @return 菜单列表
- */
- @Override
- public List<SysMenu> selectMenuTreeByUserId(Long userId)
- {
- List<SysMenu> menus = null;
- if (SecurityUtils.isAdmin(userId))
- {
- menus = menuMapper.selectMenuTreeAll();
- }
- else
- {
- menus = menuMapper.selectMenuTreeByUserId(userId);
- }
- return getChildPerms(menus, MENU_ROOT_ID);
- }
-
- /**
- * 根据角色ID查询菜单树信息
- *
- * @param roleId 角色ID
- * @return 选中菜单列表
- */
- @Override
- public List<Long> selectMenuListByRoleId(Long roleId)
- {
- SysRole role = roleMapper.selectRoleById(roleId);
- return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
- }
-
- /**
- * 构建前端路由所需要的菜单
- *
- * @param menus 菜单列表
- * @return 路由列表
- */
- @Override
- public List<RouterVo> buildMenus(List<SysMenu> menus)
- {
- List<RouterVo> routers = new LinkedList<RouterVo>();
- for (SysMenu menu : menus)
- {
- RouterVo router = new RouterVo();
- router.setHidden("1".equals(menu.getVisible()));
- router.setName(getRouteName(menu));
- router.setPath(getRouterPath(menu));
- router.setComponent(getComponent(menu));
- router.setQuery(menu.getQuery());
- router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
- List<SysMenu> cMenus = menu.getChildren();
- if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
- {
- router.setAlwaysShow(true);
- router.setRedirect("noRedirect");
- router.setChildren(buildMenus(cMenus));
- }
- else if (isMenuFrame(menu))
- {
- router.setMeta(null);
- List<RouterVo> childrenList = new ArrayList<RouterVo>();
- RouterVo children = new RouterVo();
- children.setPath(menu.getPath());
- children.setComponent(menu.getComponent());
- children.setName(getRouteName(menu.getRouteName(), menu.getPath()));
- children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
- children.setQuery(menu.getQuery());
- childrenList.add(children);
- router.setChildren(childrenList);
- }
- else if (menu.getParentId().intValue() == MENU_ROOT_ID && isInnerLink(menu))
- {
- router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
- router.setPath("/");
- List<RouterVo> childrenList = new ArrayList<RouterVo>();
- RouterVo children = new RouterVo();
- String routerPath = innerLinkReplaceEach(menu.getPath());
- children.setPath(routerPath);
- children.setComponent(UserConstants.INNER_LINK);
- children.setName(getRouteName(menu.getRouteName(), routerPath));
- children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
- childrenList.add(children);
- router.setChildren(childrenList);
- }
- routers.add(router);
- }
- return routers;
- }
-
- /**
- * 构建前端所需要树结构
- *
- * @param menus 菜单列表
- * @return 树结构列表
- */
- @Override
- public List<SysMenu> buildMenuTree(List<SysMenu> menus)
- {
- List<SysMenu> returnList = new ArrayList<SysMenu>();
- List<Long> tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
- for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();)
- {
- SysMenu menu = (SysMenu) iterator.next();
- // 如果是顶级节点, 遍历该父节点的所有子节点
- if (!tempList.contains(menu.getParentId()))
- {
- recursionFn(menus, menu);
- returnList.add(menu);
- }
- }
- if (returnList.isEmpty())
- {
- returnList = menus;
- }
- return returnList;
- }
-
- /**
- * 构建前端所需要下拉树结构
- *
- * @param menus 菜单列表
- * @return 下拉树结构列表
- */
- @Override
- public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus)
- {
- List<SysMenu> menuTrees = buildMenuTree(menus);
- return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
- }
-
- /**
- * 根据菜单ID查询信息
- *
- * @param menuId 菜单ID
- * @return 菜单信息
- */
- @Override
- public SysMenu selectMenuById(Long menuId)
- {
- return menuMapper.selectMenuById(menuId);
- }
-
- /**
- * 是否存在菜单子节点
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- @Override
- public boolean hasChildByMenuId(Long menuId)
- {
- int result = menuMapper.hasChildByMenuId(menuId);
- return result > 0;
- }
-
- /**
- * 查询菜单使用数量
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- @Override
- public boolean checkMenuExistRole(Long menuId)
- {
- int result = roleMenuMapper.checkMenuExistRole(menuId);
- return result > 0;
- }
-
- /**
- * 新增保存菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- @Override
- public int insertMenu(SysMenu menu)
- {
- return menuMapper.insertMenu(menu);
- }
-
- /**
- * 修改保存菜单信息
- *
- * @param menu 菜单信息
- * @return 结果
- */
- @Override
- public int updateMenu(SysMenu menu)
- {
- return menuMapper.updateMenu(menu);
- }
-
- /**
- * 保存菜单排序
- *
- * @param menuIds 菜单ID
- * @param orderNums 排序ID
- */
- @Override
- @Transactional
- public void updateMenuSort(String[] menuIds, String[] orderNums)
- {
- try
- {
- for (int i = 0; i < menuIds.length; i++)
- {
- SysMenu menu = new SysMenu();
- menu.setMenuId(Convert.toLong(menuIds[i]));
- menu.setOrderNum(Convert.toInt(orderNums[i]));
- menuMapper.updateMenuSort(menu);
- }
- }
- catch (Exception e)
- {
- throw new ServiceException("保存排序异常,请联系管理员");
- }
- }
-
- /**
- * 删除菜单管理信息
- *
- * @param menuId 菜单ID
- * @return 结果
- */
- @Override
- public int deleteMenuById(Long menuId)
- {
- return menuMapper.deleteMenuById(menuId);
- }
-
- /**
- * 校验菜单名称是否唯一
- *
- * @param menu 菜单信息
- * @return 结果
- */
- @Override
- public boolean checkMenuNameUnique(SysMenu menu)
- {
- Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
- SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());
- if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验路由名称是否唯一
- *
- * @param menu 菜单信息
- * @return 结果
- */
- @Override
- public boolean checkRouteConfigUnique(SysMenu menu)
- {
- Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
- Long parentId = menu.getParentId();
- String path = menu.getPath();
- String routeName = StringUtils.isEmpty(menu.getRouteName()) ? path : menu.getRouteName();
- List<SysMenu> sysMenuList = menuMapper.selectMenusByPathOrRouteName(path, routeName);
- for (SysMenu sysMenu : sysMenuList)
- {
- if (sysMenu.getMenuId().longValue() != menuId.longValue())
- {
- Long dbParentId = sysMenu.getParentId();
- String dbPath = sysMenu.getPath();
- String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName();
- if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == dbParentId.longValue())
- {
- log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName());
- return UserConstants.NOT_UNIQUE;
- }
- else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == MENU_ROOT_ID)
- {
- log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName());
- return UserConstants.NOT_UNIQUE;
- }
- else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName))
- {
- log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName());
- return UserConstants.NOT_UNIQUE;
- }
- }
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 获取路由名称
- *
- * @param menu 菜单信息
- * @return 路由名称
- */
- public String getRouteName(SysMenu menu)
- {
- // 非外链并且是一级目录(类型为目录)
- if (isMenuFrame(menu))
- {
- return StringUtils.EMPTY;
- }
- return getRouteName(menu.getRouteName(), menu.getPath());
- }
-
- /**
- * 获取路由名称,如没有配置路由名称则取路由地址
- *
- * @param name 路由名称
- * @param path 路由地址
- * @return 路由名称(驼峰格式)
- */
- public String getRouteName(String name, String path)
- {
- String routerName = StringUtils.isNotEmpty(name) ? name : path;
- return StringUtils.capitalize(routerName);
- }
-
- /**
- * 获取路由地址
- *
- * @param menu 菜单信息
- * @return 路由地址
- */
- public String getRouterPath(SysMenu menu)
- {
- String routerPath = menu.getPath();
- // 内链打开外网方式
- if (menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu))
- {
- routerPath = innerLinkReplaceEach(routerPath);
- }
- // 非外链并且是一级目录(类型为目录)
- if (MENU_ROOT_ID == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
- && UserConstants.NO_FRAME.equals(menu.getIsFrame()))
- {
- routerPath = "/" + menu.getPath();
- }
- // 非外链并且是一级目录(类型为菜单)
- else if (isMenuFrame(menu))
- {
- routerPath = "/";
- }
- return routerPath;
- }
-
- /**
- * 获取组件信息
- *
- * @param menu 菜单信息
- * @return 组件信息
- */
- public String getComponent(SysMenu menu)
- {
- String component = UserConstants.LAYOUT;
- if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu))
- {
- component = menu.getComponent();
- }
- else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != MENU_ROOT_ID && isInnerLink(menu))
- {
- component = UserConstants.INNER_LINK;
- }
- else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu))
- {
- component = UserConstants.PARENT_VIEW;
- }
- return component;
- }
-
- /**
- * 是否为菜单内部跳转
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public boolean isMenuFrame(SysMenu menu)
- {
- return menu.getParentId().intValue() == MENU_ROOT_ID && UserConstants.TYPE_MENU.equals(menu.getMenuType())
- && menu.getIsFrame().equals(UserConstants.NO_FRAME);
- }
-
- /**
- * 是否为parent_view组件
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public boolean isParentView(SysMenu menu)
- {
- return menu.getParentId().intValue() != MENU_ROOT_ID && UserConstants.TYPE_DIR.equals(menu.getMenuType());
- }
-
- /**
- * 是否为内链组件
- *
- * @param menu 菜单信息
- * @return 结果
- */
- public boolean isInnerLink(SysMenu menu)
- {
- return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
- }
-
- /**
- * 根据父节点的ID获取所有子节点
- *
- * @param list 分类表
- * @param parentId 传入的父节点ID
- * @return String
- */
- public List<SysMenu> getChildPerms(List<SysMenu> list, long parentId)
- {
- List<SysMenu> returnList = new ArrayList<SysMenu>();
- for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
- {
- SysMenu t = (SysMenu) iterator.next();
- // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
- if (t.getParentId() == parentId)
- {
- recursionFn(list, t);
- returnList.add(t);
- }
- }
- return returnList;
- }
-
- /**
- * 递归列表
- *
- * @param list 分类表
- * @param t 子节点
- */
- private void recursionFn(List<SysMenu> list, SysMenu t)
- {
- // 得到子节点列表
- List<SysMenu> childList = getChildList(list, t);
- t.setChildren(childList);
- for (SysMenu tChild : childList)
- {
- if (hasChild(list, tChild))
- {
- recursionFn(list, tChild);
- }
- }
- }
-
- /**
- * 得到子节点列表
- */
- private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t)
- {
- List<SysMenu> tlist = new ArrayList<SysMenu>();
- Iterator<SysMenu> it = list.iterator();
- while (it.hasNext())
- {
- SysMenu n = (SysMenu) it.next();
- if (n.getParentId().longValue() == t.getMenuId().longValue())
- {
- tlist.add(n);
- }
- }
- return tlist;
- }
-
- /**
- * 判断是否有子节点
- */
- private boolean hasChild(List<SysMenu> list, SysMenu t)
- {
- return getChildList(list, t).size() > 0;
- }
-
- /**
- * 内链域名特殊字符替换
- *
- * @return 替换后的内链域名
- */
- public String innerLinkReplaceEach(String path)
- {
- return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":" },
- new String[] { "", "", "", "/", "/" });
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeReadServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeReadServiceImpl.java
deleted file mode 100644
index f8e63a6..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeReadServiceImpl.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import java.util.Map;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.system.domain.SysNoticeRead;
-import com.ruoyi.system.mapper.SysNoticeReadMapper;
-import com.ruoyi.system.service.ISysNoticeReadService;
-
-/**
- * 公告已读记录 服务层实现
- *
- * @author ruoyi
- */
-@Service
-public class SysNoticeReadServiceImpl implements ISysNoticeReadService
-{
- @Autowired
- private SysNoticeReadMapper noticeReadMapper;
-
- /**
- * 标记已读
- */
- @Override
- public void markRead(Long noticeId, Long userId)
- {
- SysNoticeRead record = new SysNoticeRead();
- record.setNoticeId(noticeId);
- record.setUserId(userId);
- noticeReadMapper.insertNoticeRead(record);
- }
-
- /**
- * 查询某用户未读公告数量
- */
- @Override
- public int selectUnreadCount(Long userId)
- {
- return noticeReadMapper.selectUnreadCount(userId);
- }
-
- /**
- * 查询公告列表并标记当前用户已读状态
- */
- @Override
- public List<SysNotice> selectNoticeListWithReadStatus(Long userId, int limit)
- {
- return noticeReadMapper.selectNoticeListWithReadStatus(userId, limit);
- }
-
- /**
- * 批量标记已读
- */
- @Override
- public void markReadBatch(Long userId, Long[] noticeIds)
- {
- if (noticeIds == null || noticeIds.length == 0)
- {
- return;
- }
- noticeReadMapper.insertNoticeReadBatch(userId, noticeIds);
- }
-
- /**
- * 查询已阅读某公告的用户列表
- */
- @Override
- public List<Map<String, Object>> selectReadUsersByNoticeId(Long noticeId, String searchValue)
- {
- return noticeReadMapper.selectReadUsersByNoticeId(noticeId, searchValue);
- }
-
- /**
- * 删除公告时清理对应已读记录
- */
- @Override
- public void deleteByNoticeIds(Long[] noticeIds)
- {
- noticeReadMapper.deleteByNoticeIds(noticeIds);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
deleted file mode 100644
index 8bebd9c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.system.mapper.SysNoticeMapper;
-import com.ruoyi.system.service.ISysNoticeService;
-
-/**
- * 公告 服务层实现
- *
- * @author ruoyi
- */
-@Service
-public class SysNoticeServiceImpl implements ISysNoticeService
-{
- @Autowired
- private SysNoticeMapper noticeMapper;
-
- /**
- * 查询公告信息
- *
- * @param noticeId 公告ID
- * @return 公告信息
- */
- @Override
- public SysNotice selectNoticeById(Long noticeId)
- {
- return noticeMapper.selectNoticeById(noticeId);
- }
-
- /**
- * 查询公告列表
- *
- * @param notice 公告信息
- * @return 公告集合
- */
- @Override
- public List<SysNotice> selectNoticeList(SysNotice notice)
- {
- return noticeMapper.selectNoticeList(notice);
- }
-
- /**
- * 新增公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- @Override
- public int insertNotice(SysNotice notice)
- {
- return noticeMapper.insertNotice(notice);
- }
-
- /**
- * 修改公告
- *
- * @param notice 公告信息
- * @return 结果
- */
- @Override
- public int updateNotice(SysNotice notice)
- {
- return noticeMapper.updateNotice(notice);
- }
-
- /**
- * 删除公告对象
- *
- * @param noticeId 公告ID
- * @return 结果
- */
- @Override
- public int deleteNoticeById(Long noticeId)
- {
- return noticeMapper.deleteNoticeById(noticeId);
- }
-
- /**
- * 批量删除公告信息
- *
- * @param noticeIds 需要删除的公告ID
- * @return 结果
- */
- @Override
- public int deleteNoticeByIds(Long[] noticeIds)
- {
- return noticeMapper.deleteNoticeByIds(noticeIds);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
deleted file mode 100644
index 57764cf..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.api.domain.SysOperLog;
-import com.ruoyi.system.mapper.SysOperLogMapper;
-import com.ruoyi.system.service.ISysOperLogService;
-
-/**
- * 操作日志 服务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysOperLogServiceImpl implements ISysOperLogService
-{
- @Autowired
- private SysOperLogMapper operLogMapper;
-
- /**
- * 新增操作日志
- *
- * @param operLog 操作日志对象
- * @return 结果
- */
- @Override
- public int insertOperlog(SysOperLog operLog)
- {
- return operLogMapper.insertOperlog(operLog);
- }
-
- /**
- * 查询系统操作日志集合
- *
- * @param operLog 操作日志对象
- * @return 操作日志集合
- */
- @Override
- public List<SysOperLog> selectOperLogList(SysOperLog operLog)
- {
- return operLogMapper.selectOperLogList(operLog);
- }
-
- /**
- * 批量删除系统操作日志
- *
- * @param operIds 需要删除的操作日志ID
- * @return 结果
- */
- @Override
- public int deleteOperLogByIds(Long[] operIds)
- {
- return operLogMapper.deleteOperLogByIds(operIds);
- }
-
- /**
- * 查询操作日志详细
- *
- * @param operId 操作ID
- * @return 操作日志对象
- */
- @Override
- public SysOperLog selectOperLogById(Long operId)
- {
- return operLogMapper.selectOperLogById(operId);
- }
-
- /**
- * 清空操作日志
- */
- @Override
- public void cleanOperLog()
- {
- operLogMapper.cleanOperLog();
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java
deleted file mode 100644
index 36b6dbf..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPermissionServiceImpl.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.service.ISysMenuService;
-import com.ruoyi.system.service.ISysPermissionService;
-import com.ruoyi.system.service.ISysRoleService;
-
-/**
- * 用户权限处理
- *
- * @author ruoyi
- */
-@Service
-public class SysPermissionServiceImpl implements ISysPermissionService
-{
- @Autowired
- private ISysRoleService roleService;
-
- @Autowired
- private ISysMenuService menuService;
-
- /**
- * 获取角色数据权限
- *
- * @param userId 用户Id
- * @return 角色权限信息
- */
- @Override
- public Set<String> getRolePermission(SysUser user)
- {
- Set<String> roles = new HashSet<String>();
- // 管理员拥有所有权限
- if (user.isAdmin())
- {
- roles.add(Constants.SUPER_ADMIN);
- }
- else
- {
- roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
- }
- return roles;
- }
-
- /**
- * 获取菜单数据权限
- *
- * @param userId 用户Id
- * @return 菜单权限信息
- */
- @Override
- public Set<String> getMenuPermission(SysUser user)
- {
- Set<String> perms = new HashSet<String>();
- // 管理员拥有所有权限
- if (user.isAdmin())
- {
- perms.add(Constants.ALL_PERMISSION);
- }
- else
- {
- List<SysRole> roles = user.getRoles();
- if (!CollectionUtils.isEmpty(roles))
- {
- // 多角色设置permissions属性,以便数据权限匹配权限
- for (SysRole role : roles)
- {
- if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && !role.isAdmin())
- {
- Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
- role.setPermissions(rolePerms);
- perms.addAll(rolePerms);
- }
- }
- }
- else
- {
- perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
- }
- }
- return perms;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
deleted file mode 100644
index 8df3b4c..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.system.mapper.SysPostMapper;
-import com.ruoyi.system.mapper.SysUserPostMapper;
-import com.ruoyi.system.service.ISysPostService;
-
-/**
- * 岗位信息 服务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysPostServiceImpl implements ISysPostService
-{
- @Autowired
- private SysPostMapper postMapper;
-
- @Autowired
- private SysUserPostMapper userPostMapper;
-
- /**
- * 查询岗位信息集合
- *
- * @param post 岗位信息
- * @return 岗位信息集合
- */
- @Override
- public List<SysPost> selectPostList(SysPost post)
- {
- return postMapper.selectPostList(post);
- }
-
- /**
- * 查询所有岗位
- *
- * @return 岗位列表
- */
- @Override
- public List<SysPost> selectPostAll()
- {
- return postMapper.selectPostAll();
- }
-
- /**
- * 通过岗位ID查询岗位信息
- *
- * @param postId 岗位ID
- * @return 角色对象信息
- */
- @Override
- public SysPost selectPostById(Long postId)
- {
- return postMapper.selectPostById(postId);
- }
-
- /**
- * 根据用户ID获取岗位选择框列表
- *
- * @param userId 用户ID
- * @return 选中岗位ID列表
- */
- @Override
- public List<Long> selectPostListByUserId(Long userId)
- {
- return postMapper.selectPostListByUserId(userId);
- }
-
- /**
- * 校验岗位名称是否唯一
- *
- * @param post 岗位信息
- * @return 结果
- */
- @Override
- public boolean checkPostNameUnique(SysPost post)
- {
- Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
- SysPost info = postMapper.checkPostNameUnique(post.getPostName());
- if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验岗位编码是否唯一
- *
- * @param post 岗位信息
- * @return 结果
- */
- @Override
- public boolean checkPostCodeUnique(SysPost post)
- {
- Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
- SysPost info = postMapper.checkPostCodeUnique(post.getPostCode());
- if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 通过岗位ID查询岗位使用数量
- *
- * @param postId 岗位ID
- * @return 结果
- */
- @Override
- public int countUserPostById(Long postId)
- {
- return userPostMapper.countUserPostById(postId);
- }
-
- /**
- * 删除岗位信息
- *
- * @param postId 岗位ID
- * @return 结果
- */
- @Override
- public int deletePostById(Long postId)
- {
- return postMapper.deletePostById(postId);
- }
-
- /**
- * 批量删除岗位信息
- *
- * @param postIds 需要删除的岗位ID
- * @return 结果
- */
- @Override
- public int deletePostByIds(Long[] postIds)
- {
- for (Long postId : postIds)
- {
- SysPost post = selectPostById(postId);
- if (countUserPostById(postId) > 0)
- {
- throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName()));
- }
- }
- return postMapper.deletePostByIds(postIds);
- }
-
- /**
- * 新增保存岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- @Override
- public int insertPost(SysPost post)
- {
- return postMapper.insertPost(post);
- }
-
- /**
- * 修改保存岗位信息
- *
- * @param post 岗位信息
- * @return 结果
- */
- @Override
- public int updatePost(SysPost post)
- {
- return postMapper.updatePost(post);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
deleted file mode 100644
index 67e6db8..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
+++ /dev/null
@@ -1,426 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.datascope.annotation.DataScope;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.domain.SysRoleDept;
-import com.ruoyi.system.domain.SysRoleMenu;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.mapper.SysRoleDeptMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysRoleMenuMapper;
-import com.ruoyi.system.mapper.SysUserRoleMapper;
-import com.ruoyi.system.service.ISysRoleService;
-
-/**
- * 角色 业务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysRoleServiceImpl implements ISysRoleService
-{
- @Autowired
- private SysRoleMapper roleMapper;
-
- @Autowired
- private SysRoleMenuMapper roleMenuMapper;
-
- @Autowired
- private SysUserRoleMapper userRoleMapper;
-
- @Autowired
- private SysRoleDeptMapper roleDeptMapper;
-
- /**
- * 根据条件分页查询角色数据
- *
- * @param role 角色信息
- * @return 角色数据集合信息
- */
- @Override
- @DataScope(deptAlias = "d")
- public List<SysRole> selectRoleList(SysRole role)
- {
- return roleMapper.selectRoleList(role);
- }
-
- /**
- * 根据用户ID查询角色
- *
- * @param userId 用户ID
- * @return 角色列表
- */
- @Override
- public List<SysRole> selectRolesByUserId(Long userId)
- {
- List<SysRole> userRoles = roleMapper.selectRolePermissionByUserId(userId);
- List<SysRole> roles = selectRoleAll();
- for (SysRole role : roles)
- {
- for (SysRole userRole : userRoles)
- {
- if (role.getRoleId().longValue() == userRole.getRoleId().longValue())
- {
- role.setFlag(true);
- break;
- }
- }
- }
- return roles;
- }
-
- /**
- * 根据用户ID查询权限
- *
- * @param userId 用户ID
- * @return 权限列表
- */
- @Override
- public Set<String> selectRolePermissionByUserId(Long userId)
- {
- List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId);
- Set<String> permsSet = new HashSet<>();
- for (SysRole perm : perms)
- {
- if (StringUtils.isNotNull(perm))
- {
- permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
- }
- }
- return permsSet;
- }
-
- /**
- * 查询所有角色
- *
- * @return 角色列表
- */
- @Override
- public List<SysRole> selectRoleAll()
- {
- return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());
- }
-
- /**
- * 根据用户ID获取角色选择框列表
- *
- * @param userId 用户ID
- * @return 选中角色ID列表
- */
- @Override
- public List<Long> selectRoleListByUserId(Long userId)
- {
- return roleMapper.selectRoleListByUserId(userId);
- }
-
- /**
- * 通过角色ID查询角色
- *
- * @param roleId 角色ID
- * @return 角色对象信息
- */
- @Override
- public SysRole selectRoleById(Long roleId)
- {
- return roleMapper.selectRoleById(roleId);
- }
-
- /**
- * 校验角色名称是否唯一
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- public boolean checkRoleNameUnique(SysRole role)
- {
- Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
- SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
- if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验角色权限是否唯一
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- public boolean checkRoleKeyUnique(SysRole role)
- {
- Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
- SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
- if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验角色是否允许操作
- *
- * @param role 角色信息
- */
- @Override
- public void checkRoleAllowed(SysRole role)
- {
- if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())
- {
- throw new ServiceException("不允许操作超级管理员角色");
- }
- }
-
- /**
- * 校验角色是否有数据权限
- *
- * @param roleIds 角色id
- */
- @Override
- public void checkRoleDataScope(Long... roleIds)
- {
- if (!SecurityUtils.isAdmin())
- {
- for (Long roleId : roleIds)
- {
- SysRole role = new SysRole();
- role.setRoleId(roleId);
- List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
- if (StringUtils.isEmpty(roles))
- {
- throw new ServiceException("没有权限访问角色数据!");
- }
- }
- }
- }
-
- /**
- * 通过角色ID查询角色使用数量
- *
- * @param roleId 角色ID
- * @return 结果
- */
- @Override
- public int countUserRoleByRoleId(Long roleId)
- {
- return userRoleMapper.countUserRoleByRoleId(roleId);
- }
-
- /**
- * 新增保存角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int insertRole(SysRole role)
- {
- // 新增角色信息
- roleMapper.insertRole(role);
- return insertRoleMenu(role);
- }
-
- /**
- * 修改保存角色信息
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int updateRole(SysRole role)
- {
- // 修改角色信息
- roleMapper.updateRole(role);
- // 删除角色与菜单关联
- roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId());
- return insertRoleMenu(role);
- }
-
- /**
- * 修改角色状态
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- public int updateRoleStatus(SysRole role)
- {
- return roleMapper.updateRole(role);
- }
-
- /**
- * 修改数据权限信息
- *
- * @param role 角色信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int authDataScope(SysRole role)
- {
- // 修改角色信息
- roleMapper.updateRole(role);
- // 删除角色与部门关联
- roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId());
- // 新增角色和部门信息(数据权限)
- return insertRoleDept(role);
- }
-
- /**
- * 新增角色菜单信息
- *
- * @param role 角色对象
- */
- public int insertRoleMenu(SysRole role)
- {
- int rows = 1;
- // 新增用户与角色管理
- List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
- for (Long menuId : role.getMenuIds())
- {
- SysRoleMenu rm = new SysRoleMenu();
- rm.setRoleId(role.getRoleId());
- rm.setMenuId(menuId);
- list.add(rm);
- }
- if (list.size() > 0)
- {
- rows = roleMenuMapper.batchRoleMenu(list);
- }
- return rows;
- }
-
- /**
- * 新增角色部门信息(数据权限)
- *
- * @param role 角色对象
- */
- public int insertRoleDept(SysRole role)
- {
- int rows = 1;
- // 新增角色与部门(数据权限)管理
- List<SysRoleDept> list = new ArrayList<SysRoleDept>();
- for (Long deptId : role.getDeptIds())
- {
- SysRoleDept rd = new SysRoleDept();
- rd.setRoleId(role.getRoleId());
- rd.setDeptId(deptId);
- list.add(rd);
- }
- if (list.size() > 0)
- {
- rows = roleDeptMapper.batchRoleDept(list);
- }
- return rows;
- }
-
- /**
- * 通过角色ID删除角色
- *
- * @param roleId 角色ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int deleteRoleById(Long roleId)
- {
- // 删除角色与菜单关联
- roleMenuMapper.deleteRoleMenuByRoleId(roleId);
- // 删除角色与部门关联
- roleDeptMapper.deleteRoleDeptByRoleId(roleId);
- return roleMapper.deleteRoleById(roleId);
- }
-
- /**
- * 批量删除角色信息
- *
- * @param roleIds 需要删除的角色ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int deleteRoleByIds(Long[] roleIds)
- {
- for (Long roleId : roleIds)
- {
- checkRoleAllowed(new SysRole(roleId));
- checkRoleDataScope(roleId);
- SysRole role = selectRoleById(roleId);
- if (countUserRoleByRoleId(roleId) > 0)
- {
- throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
- }
- }
- // 删除角色与菜单关联
- roleMenuMapper.deleteRoleMenu(roleIds);
- // 删除角色与部门关联
- roleDeptMapper.deleteRoleDept(roleIds);
- return roleMapper.deleteRoleByIds(roleIds);
- }
-
- /**
- * 取消授权用户角色
- *
- * @param userRole 用户和角色关联信息
- * @return 结果
- */
- @Override
- public int deleteAuthUser(SysUserRole userRole)
- {
- return userRoleMapper.deleteUserRoleInfo(userRole);
- }
-
- /**
- * 批量取消授权用户角色
- *
- * @param roleId 角色ID
- * @param userIds 需要取消授权的用户数据ID
- * @return 结果
- */
- @Override
- public int deleteAuthUsers(Long roleId, Long[] userIds)
- {
- return userRoleMapper.deleteUserRoleInfos(roleId, userIds);
- }
-
- /**
- * 批量选择授权用户角色
- *
- * @param roleId 角色ID
- * @param userIds 需要授权的用户数据ID
- * @return 结果
- */
- @Override
- public int insertAuthUsers(Long roleId, Long[] userIds)
- {
- // 新增用户与角色管理
- List<SysUserRole> list = new ArrayList<SysUserRole>();
- for (Long userId : userIds)
- {
- SysUserRole ur = new SysUserRole();
- ur.setUserId(userId);
- ur.setRoleId(roleId);
- list.add(ur);
- }
- return userRoleMapper.batchUserRole(list);
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
deleted file mode 100644
index dcb0325..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.system.api.model.LoginUser;
-import com.ruoyi.system.domain.SysUserOnline;
-import com.ruoyi.system.service.ISysUserOnlineService;
-
-/**
- * 在线用户 服务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysUserOnlineServiceImpl implements ISysUserOnlineService
-{
- /**
- * 通过登录地址查询信息
- *
- * @param ipaddr 登录地址
- * @param user 用户信息
- * @return 在线用户信息
- */
- @Override
- public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user)
- {
- if (StringUtils.equals(ipaddr, user.getIpaddr()))
- {
- return loginUserToUserOnline(user);
- }
- return null;
- }
-
- /**
- * 通过用户名称查询信息
- *
- * @param userName 用户名称
- * @param user 用户信息
- * @return 在线用户信息
- */
- @Override
- public SysUserOnline selectOnlineByUserName(String userName, LoginUser user)
- {
- if (StringUtils.equals(userName, user.getUsername()))
- {
- return loginUserToUserOnline(user);
- }
- return null;
- }
-
- /**
- * 通过登录地址/用户名称查询信息
- *
- * @param ipaddr 登录地址
- * @param userName 用户名称
- * @param user 用户信息
- * @return 在线用户信息
- */
- @Override
- public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user)
- {
- if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
- {
- return loginUserToUserOnline(user);
- }
- return null;
- }
-
- /**
- * 设置在线用户信息
- *
- * @param user 用户信息
- * @return 在线用户
- */
- @Override
- public SysUserOnline loginUserToUserOnline(LoginUser user)
- {
- if (StringUtils.isNull(user))
- {
- return null;
- }
- SysUserOnline sysUserOnline = new SysUserOnline();
- sysUserOnline.setTokenId(user.getToken());
- sysUserOnline.setUserName(user.getUsername());
- sysUserOnline.setIpaddr(user.getIpaddr());
- sysUserOnline.setLoginTime(user.getLoginTime());
- return sysUserOnline;
- }
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
deleted file mode 100644
index ba14cde..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ /dev/null
@@ -1,563 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import jakarta.validation.Validator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.CollectionUtils;
-import com.ruoyi.common.core.constant.UserConstants;
-import com.ruoyi.common.core.exception.ServiceException;
-import com.ruoyi.common.core.utils.SpringUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.bean.BeanValidators;
-import com.ruoyi.common.datascope.annotation.DataScope;
-import com.ruoyi.common.security.utils.SecurityUtils;
-import com.ruoyi.system.api.domain.SysRole;
-import com.ruoyi.system.api.domain.SysUser;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.system.domain.SysUserPost;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.mapper.SysPostMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysUserMapper;
-import com.ruoyi.system.mapper.SysUserPostMapper;
-import com.ruoyi.system.mapper.SysUserRoleMapper;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 用户 业务层处理
- *
- * @author ruoyi
- */
-@Service
-public class SysUserServiceImpl implements ISysUserService
-{
- private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);
-
- @Autowired
- private SysUserMapper userMapper;
-
- @Autowired
- private SysRoleMapper roleMapper;
-
- @Autowired
- private SysPostMapper postMapper;
-
- @Autowired
- private SysUserRoleMapper userRoleMapper;
-
- @Autowired
- private SysUserPostMapper userPostMapper;
-
- @Autowired
- private ISysConfigService configService;
-
- @Autowired
- private ISysDeptService deptService;
-
- @Autowired
- protected Validator validator;
-
- /**
- * 根据条件分页查询用户列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- @Override
- @DataScope(deptAlias = "d", userAlias = "u")
- public List<SysUser> selectUserList(SysUser user)
- {
- return userMapper.selectUserList(user);
- }
-
- /**
- * 根据条件分页查询已分配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- @Override
- @DataScope(deptAlias = "d", userAlias = "u")
- public List<SysUser> selectAllocatedList(SysUser user)
- {
- return userMapper.selectAllocatedList(user);
- }
-
- /**
- * 根据条件分页查询未分配用户角色列表
- *
- * @param user 用户信息
- * @return 用户信息集合信息
- */
- @Override
- @DataScope(deptAlias = "d", userAlias = "u")
- public List<SysUser> selectUnallocatedList(SysUser user)
- {
- return userMapper.selectUnallocatedList(user);
- }
-
- /**
- * 通过用户名查询用户
- *
- * @param userName 用户名
- * @return 用户对象信息
- */
- @Override
- public SysUser selectUserByUserName(String userName)
- {
- return userMapper.selectUserByUserName(userName);
- }
-
- /**
- * 通过用户ID查询用户
- *
- * @param userId 用户ID
- * @return 用户对象信息
- */
- @Override
- public SysUser selectUserById(Long userId)
- {
- return userMapper.selectUserById(userId);
- }
-
- /**
- * 查询用户所属角色组
- *
- * @param userName 用户名
- * @return 结果
- */
- @Override
- public String selectUserRoleGroup(String userName)
- {
- List<SysRole> list = roleMapper.selectRolesByUserName(userName);
- if (CollectionUtils.isEmpty(list))
- {
- return StringUtils.EMPTY;
- }
- return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
- }
-
- /**
- * 查询用户所属岗位组
- *
- * @param userName 用户名
- * @return 结果
- */
- @Override
- public String selectUserPostGroup(String userName)
- {
- List<SysPost> list = postMapper.selectPostsByUserName(userName);
- if (CollectionUtils.isEmpty(list))
- {
- return StringUtils.EMPTY;
- }
- return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
- }
-
- /**
- * 校验用户名称是否唯一
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- public boolean checkUserNameUnique(SysUser user)
- {
- Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
- SysUser info = userMapper.checkUserNameUnique(user.getUserName());
- if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验手机号码是否唯一
- *
- * @param user 用户信息
- * @return
- */
- @Override
- public boolean checkPhoneUnique(SysUser user)
- {
- Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
- SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
- if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验email是否唯一
- *
- * @param user 用户信息
- * @return
- */
- @Override
- public boolean checkEmailUnique(SysUser user)
- {
- Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
- SysUser info = userMapper.checkEmailUnique(user.getEmail());
- if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
- {
- return UserConstants.NOT_UNIQUE;
- }
- return UserConstants.UNIQUE;
- }
-
- /**
- * 校验用户是否允许操作
- *
- * @param user 用户信息
- */
- @Override
- public void checkUserAllowed(SysUser user)
- {
- if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
- {
- throw new ServiceException("不允许操作超级管理员用户");
- }
- }
-
- /**
- * 校验用户是否有数据权限
- *
- * @param userId 用户id
- */
- @Override
- public void checkUserDataScope(Long userId)
- {
- if (!SecurityUtils.isAdmin())
- {
- SysUser user = new SysUser();
- user.setUserId(userId);
- List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
- if (StringUtils.isEmpty(users))
- {
- throw new ServiceException("没有权限访问用户数据!");
- }
- }
- }
-
- /**
- * 新增保存用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int insertUser(SysUser user)
- {
- // 新增用户信息
- int rows = userMapper.insertUser(user);
- // 新增用户岗位关联
- insertUserPost(user);
- // 新增用户与角色管理
- insertUserRole(user);
- return rows;
- }
-
- /**
- * 注册用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- public boolean registerUser(SysUser user)
- {
- return userMapper.insertUser(user) > 0;
- }
-
- /**
- * 修改保存用户信息
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int updateUser(SysUser user)
- {
- Long userId = user.getUserId();
- // 删除用户与角色关联
- userRoleMapper.deleteUserRoleByUserId(userId);
- // 新增用户与角色管理
- insertUserRole(user);
- // 删除用户与岗位关联
- userPostMapper.deleteUserPostByUserId(userId);
- // 新增用户与岗位管理
- insertUserPost(user);
- return userMapper.updateUser(user);
- }
-
- /**
- * 用户授权角色
- *
- * @param userId 用户ID
- * @param roleIds 角色组
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void insertUserAuth(Long userId, Long[] roleIds)
- {
- userRoleMapper.deleteUserRoleByUserId(userId);
- insertUserRole(userId, roleIds);
- }
-
- /**
- * 修改用户状态
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- public int updateUserStatus(SysUser user)
- {
- return userMapper.updateUserStatus(user.getUserId(), user.getStatus());
- }
-
- /**
- * 修改用户基本信息
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- public boolean updateUserProfile(SysUser user)
- {
- return userMapper.updateUser(user) > 0;
- }
-
- /**
- * 修改用户头像
- *
- * @param userId 用户ID
- * @param avatar 头像地址
- * @return 结果
- */
- @Override
- public boolean updateUserAvatar(Long userId, String avatar)
- {
- return userMapper.updateUserAvatar(userId, avatar) > 0;
- }
-
- /**
- * 更新用户登录信息(IP和登录时间)
- *
- * @param user 用户信息
- * @return 结果
- */
- public boolean updateLoginInfo(SysUser user)
- {
- return userMapper.updateLoginInfo(user) > 0;
- }
-
- /**
- * 重置用户密码
- *
- * @param user 用户信息
- * @return 结果
- */
- @Override
- public int resetPwd(SysUser user)
- {
- return userMapper.resetUserPwd(user.getUserId(), user.getPassword());
- }
-
- /**
- * 重置用户密码
- *
- * @param userId 用户ID
- * @param password 密码
- * @return 结果
- */
- @Override
- public int resetUserPwd(Long userId, String password)
- {
- return userMapper.resetUserPwd(userId, password);
- }
-
- /**
- * 新增用户角色信息
- *
- * @param user 用户对象
- */
- public void insertUserRole(SysUser user)
- {
- this.insertUserRole(user.getUserId(), user.getRoleIds());
- }
-
- /**
- * 新增用户岗位信息
- *
- * @param user 用户对象
- */
- public void insertUserPost(SysUser user)
- {
- Long[] posts = user.getPostIds();
- if (StringUtils.isNotEmpty(posts))
- {
- // 新增用户与岗位管理
- List<SysUserPost> list = new ArrayList<SysUserPost>();
- for (Long postId : posts)
- {
- SysUserPost up = new SysUserPost();
- up.setUserId(user.getUserId());
- up.setPostId(postId);
- list.add(up);
- }
- userPostMapper.batchUserPost(list);
- }
- }
-
- /**
- * 新增用户角色信息
- *
- * @param userId 用户ID
- * @param roleIds 角色组
- */
- public void insertUserRole(Long userId, Long[] roleIds)
- {
- if (StringUtils.isNotEmpty(roleIds))
- {
- // 新增用户与角色管理
- List<SysUserRole> list = new ArrayList<SysUserRole>();
- for (Long roleId : roleIds)
- {
- SysUserRole ur = new SysUserRole();
- ur.setUserId(userId);
- ur.setRoleId(roleId);
- list.add(ur);
- }
- userRoleMapper.batchUserRole(list);
- }
- }
-
- /**
- * 通过用户ID删除用户
- *
- * @param userId 用户ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int deleteUserById(Long userId)
- {
- // 删除用户与角色关联
- userRoleMapper.deleteUserRoleByUserId(userId);
- // 删除用户与岗位表
- userPostMapper.deleteUserPostByUserId(userId);
- return userMapper.deleteUserById(userId);
- }
-
- /**
- * 批量删除用户信息
- *
- * @param userIds 需要删除的用户ID
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int deleteUserByIds(Long[] userIds)
- {
- for (Long userId : userIds)
- {
- checkUserAllowed(new SysUser(userId));
- checkUserDataScope(userId);
- }
- // 删除用户与角色关联
- userRoleMapper.deleteUserRole(userIds);
- // 删除用户与岗位关联
- userPostMapper.deleteUserPost(userIds);
- return userMapper.deleteUserByIds(userIds);
- }
-
- /**
- * 导入用户数据
- *
- * @param userList 用户数据列表
- * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
- * @param operName 操作用户
- * @return 结果
- */
- @Override
- public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)
- {
- if (StringUtils.isNull(userList) || userList.size() == 0)
- {
- throw new ServiceException("导入用户数据不能为空!");
- }
- int successNum = 0;
- int failureNum = 0;
- StringBuilder successMsg = new StringBuilder();
- StringBuilder failureMsg = new StringBuilder();
- for (SysUser user : userList)
- {
- try
- {
- // 验证是否存在这个用户
- SysUser u = userMapper.selectUserByUserName(user.getUserName());
- if (StringUtils.isNull(u))
- {
- BeanValidators.validateWithException(validator, user);
- deptService.checkDeptDataScope(user.getDeptId());
- String password = configService.selectConfigByKey("sys.user.initPassword");
- user.setPassword(SecurityUtils.encryptPassword(password));
- user.setCreateBy(operName);
- userMapper.insertUser(user);
- successNum++;
- successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
- }
- else if (isUpdateSupport)
- {
- BeanValidators.validateWithException(validator, user);
- checkUserAllowed(u);
- checkUserDataScope(u.getUserId());
- deptService.checkDeptDataScope(user.getDeptId());
- user.setUserId(u.getUserId());
- user.setDeptId(u.getDeptId());
- user.setUpdateBy(operName);
- userMapper.updateUser(user);
- successNum++;
- successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
- }
- else
- {
- failureNum++;
- failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
- }
- }
- catch (Exception e)
- {
- failureNum++;
- String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:";
- failureMsg.append(msg + e.getMessage());
- log.error(msg, e);
- }
- }
- if (failureNum > 0)
- {
- failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
- throw new ServiceException(failureMsg.toString());
- }
- else
- {
- successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
- }
- return successMsg.toString();
- }
-
-}
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt
deleted file mode 100644
index e5e8395..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _ _
- (_) | |
- _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___
-| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \
-| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | |
-|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_|
- __/ | __/ |
- |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml b/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml
deleted file mode 100644
index 96bc0bb..0000000
--- a/ruoyi-modules/ruoyi-system/src/main/resources/logback.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true" scanPeriod="60 seconds" debug="false">
- <!-- 日志存放路径 -->
- <property name="log.path" value="logs/ruoyi-system" />
- <!-- 日志输出格式 -->
- <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
-
- <!-- 控制台输出 -->
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- </appender>
-
- <!-- 系统日志输出 -->
- <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/info.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>INFO</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/error.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>ERROR</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 系统模块日志级别控制 -->
- <logger name="com.ruoyi" level="info" />
- <!-- Spring日志级别控制 -->
- <logger name="org.springframework" level="warn" />
-
- <root level="info">
- <appender-ref ref="console" />
- </root>
-
- <!--系统操作日志-->
- <root level="info">
- <appender-ref ref="file_info" />
- <appender-ref ref="file_error" />
- </root>
-</configuration>
\ No newline at end of file
diff --git a/ruoyi-ui/.editorconfig b/ruoyi-ui/.editorconfig
deleted file mode 100644
index 22d302e..0000000
--- a/ruoyi-ui/.editorconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-# 告诉EditorConfig插件,这是根文件,不用继续往上查找
-root = true
-
-# 匹配全部文件
-[*]
-# 设置字符集
-charset = utf-8
-# 缩进风格,可选space、tab
-indent_style = space
-# 缩进的空格数
-indent_size = 2
-# 结尾换行符,可选lf、cr、crlf
-end_of_line = lf
-# 在文件结尾插入新行
-insert_final_newline = true
-# 删除一行中的前后空格
-trim_trailing_whitespace = true
-
-# 匹配md结尾的文件
-[*.md]
-insert_final_newline = false
-trim_trailing_whitespace = false
diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development
deleted file mode 100644
index 18b2a3e..0000000
--- a/ruoyi-ui/.env.development
+++ /dev/null
@@ -1,11 +0,0 @@
-# 页面标题
-VUE_APP_TITLE = 若依管理系统
-
-# 开发环境配置
-ENV = 'development'
-
-# 若依管理系统/开发环境
-VUE_APP_BASE_API = '/dev-api'
-
-# 路由懒加载
-VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production
deleted file mode 100644
index cb064ec..0000000
--- a/ruoyi-ui/.env.production
+++ /dev/null
@@ -1,8 +0,0 @@
-# 页面标题
-VUE_APP_TITLE = 若依管理系统
-
-# 生产环境配置
-ENV = 'production'
-
-# 若依管理系统/生产环境
-VUE_APP_BASE_API = '/prod-api'
diff --git a/ruoyi-ui/.env.staging b/ruoyi-ui/.env.staging
deleted file mode 100644
index 730af34..0000000
--- a/ruoyi-ui/.env.staging
+++ /dev/null
@@ -1,12 +0,0 @@
-# 页面标题
-VUE_APP_TITLE = 若依管理系统
-
-BABEL_ENV = production
-
-NODE_ENV = production
-
-# 测试环境配置
-ENV = 'staging'
-
-# 若依管理系统/测试环境
-VUE_APP_BASE_API = '/stage-api'
diff --git a/ruoyi-ui/.gitignore b/ruoyi-ui/.gitignore
deleted file mode 100644
index 2c9b3a7..0000000
--- a/ruoyi-ui/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-.DS_Store
-node_modules/
-dist/
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-**/*.log
-
-tests/**/coverage/
-tests/e2e/reports
-selenium-debug.log
-
-# Editor directories and files
-.idea
-.vscode
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.local
-
-package-lock.json
-yarn.lock
diff --git a/ruoyi-ui/README.md b/ruoyi-ui/README.md
deleted file mode 100644
index ad24b68..0000000
--- a/ruoyi-ui/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-## 开发
-
-```bash
-# 克隆项目
-git clone https://gitee.com/y_project/RuoYi-Vue
-
-# 进入项目目录
-cd ruoyi-ui
-
-# 安装依赖
-npm install
-
-# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
-npm install --registry=https://registry.npmmirror.com
-
-# 启动服务
-npm run dev
-```
-
-浏览器访问 http://localhost:80
-
-## 发布
-
-```bash
-# 构建测试环境
-npm run build:stage
-
-# 构建生产环境
-npm run build:prod
-```
\ No newline at end of file
diff --git a/ruoyi-ui/babel.config.js b/ruoyi-ui/babel.config.js
deleted file mode 100644
index d33f9ea..0000000
--- a/ruoyi-ui/babel.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = {
- presets: [
- // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
- '@vue/cli-plugin-babel/preset'
- ],
- 'env': {
- 'development': {
- // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
- // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
- 'plugins': ['dynamic-import-node']
- }
- }
-}
\ No newline at end of file
diff --git a/ruoyi-ui/bin/build.bat b/ruoyi-ui/bin/build.bat
deleted file mode 100644
index 3159093..0000000
--- a/ruoyi-ui/bin/build.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-@echo off
-echo.
-echo [��Ϣ] ���Web���̣�����dist�ļ���
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm run build:prod
-
-pause
\ No newline at end of file
diff --git a/ruoyi-ui/bin/package.bat b/ruoyi-ui/bin/package.bat
deleted file mode 100644
index dff0c61..0000000
--- a/ruoyi-ui/bin/package.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-@echo off
-echo.
-echo [��Ϣ] ��װWeb���̣�����node_modules�ļ���
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm install --registry=https://registry.npmmirror.com
-
-pause
\ No newline at end of file
diff --git a/ruoyi-ui/bin/run-web.bat b/ruoyi-ui/bin/run-web.bat
deleted file mode 100644
index 921902c..0000000
--- a/ruoyi-ui/bin/run-web.bat
+++ /dev/null
@@ -1,12 +0,0 @@
-@echo off
-echo.
-echo [��Ϣ] ʹ�� Vue CLI �������� Web ���̡�
-echo.
-
-%~d0
-cd %~dp0
-
-cd ..
-npm run dev
-
-pause
\ No newline at end of file
diff --git a/ruoyi-ui/build/index.js b/ruoyi-ui/build/index.js
deleted file mode 100644
index 385da08..0000000
--- a/ruoyi-ui/build/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const { run } = require('runjs')
-const chalk = require('chalk')
-const config = require('../vue.config.js')
-const rawArgv = process.argv.slice(2)
-const args = rawArgv.join(' ')
-
-if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
- const report = rawArgv.includes('--report')
-
- run(`vue-cli-service build ${args}`)
-
- const port = 9526
- const publicPath = config.publicPath
-
- var connect = require('connect')
- var serveStatic = require('serve-static')
- const app = connect()
-
- app.use(
- publicPath,
- serveStatic('./dist', {
- index: ['index.html', '/']
- })
- )
-
- app.listen(port, function () {
- console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
- if (report) {
- console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
- }
-
- })
-} else {
- run(`vue-cli-service build ${args}`)
-}
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
deleted file mode 100644
index 4f77767..0000000
--- a/ruoyi-ui/package.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "name": "ruoyi",
- "version": "3.6.8",
- "description": "若依管理系统",
- "author": "若依",
- "license": "MIT",
- "scripts": {
- "dev": "vue-cli-service serve",
- "build:prod": "vue-cli-service build",
- "build:stage": "vue-cli-service build --mode staging",
- "preview": "node build/index.js --preview"
- },
- "keywords": [
- "vue",
- "admin",
- "dashboard",
- "element-ui",
- "boilerplate",
- "admin-template",
- "management-system"
- ],
- "repository": {
- "type": "git",
- "url": "https://gitee.com/y_project/RuoYi-Cloud.git"
- },
- "dependencies": {
- "@riophae/vue-treeselect": "0.4.0",
- "axios": "0.30.3",
- "clipboard": "2.0.8",
- "core-js": "3.37.1",
- "echarts": "5.4.0",
- "element-ui": "2.15.14",
- "file-saver": "2.0.5",
- "fuse.js": "6.4.3",
- "highlight.js": "9.18.5",
- "js-beautify": "1.13.0",
- "js-cookie": "3.0.1",
- "jsencrypt": "3.0.0-rc.1",
- "nprogress": "0.2.0",
- "quill": "2.0.2",
- "screenfull": "5.0.2",
- "sortablejs": "1.10.2",
- "vue": "2.6.12",
- "vue-count-to": "1.0.13",
- "vue-cropper": "0.5.5",
- "vue-router": "3.4.9",
- "vuedraggable": "2.24.3",
- "vuex": "3.6.0"
- },
- "devDependencies": {
- "@vue/cli-plugin-babel": "4.4.6",
- "@vue/cli-service": "4.4.6",
- "babel-plugin-dynamic-import-node": "2.3.3",
- "chalk": "4.1.0",
- "compression-webpack-plugin": "6.1.2",
- "connect": "3.6.6",
- "sass": "1.32.13",
- "sass-loader": "10.1.1",
- "script-ext-html-webpack-plugin": "2.1.5",
- "svg-sprite-loader": "5.1.1",
- "vue-template-compiler": "2.6.12"
- },
- "engines": {
- "node": ">=8.9",
- "npm": ">= 3.0.0"
- },
- "browserslist": [
- "> 1%",
- "last 2 versions"
- ]
-}
diff --git a/ruoyi-ui/public/html/ie.html b/ruoyi-ui/public/html/ie.html
deleted file mode 100644
index 390ce8a..0000000
--- a/ruoyi-ui/public/html/ie.html
+++ /dev/null
@@ -1,46 +0,0 @@
-
-<!DOCTYPE html>
-<html lang="zh-CN">
-<head>
- <meta charset="UTF-8" />
- <title>请升级您的浏览器</title>
- <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
- <meta name="renderer" content="webkit">
- <base target="_blank" />
- <style type="text/css">
- html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}
- a{text-decoration:none;color:#0072c6;}a:hover{text-decoration:none;color:#004d8c;}
- body{width:960px;margin:0 auto;padding:10px;font-size:14px;line-height:24px;color:#454545;font-family:'Microsoft YaHei UI','Microsoft YaHei',DengXian,SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif;overflow-y:scroll}
- h1{font-size:40px;line-height:80px;font-weight:100;margin-bottom:10px;}
- h2{font-size:20px;line-height:25px;font-weight:100;margin:10px 0;}
- em{color:red}
- p{margin-bottom:10px;}
- hr{margin:20px 0;border:0;border-top:1px solid #dadada}
- span{display:block;font-size:12px;line-height:12px;}
- .clean{clear:both;}
- .browser{padding:10px 10px;}
- .browser li{width:auto;padding:0 80px;margin-top:30px;height:34px;line-height:22px;float:left;list-style:none;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAADMCAYAAAAWCXEwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAC7ESURBVHja5Lx5dFRV1rBfgHwYRQQVtB26ZWhtabtfeUGxGxFbUGZF8RMHGkVbRkekVYiKisicVhE0gEwBokgDAhEMMSSQkAECwcxkrlRSqVTqJqnxzs/vj5t7qUyAvr9e37fWV2vtleSm6p6n9t5nn733OVU2RaUaEP5PiqJSbeMXPBTA5/Xhzk9Vnd9vo3HFx21E2LYJX9IRgh6npvyCe9uaqS4K4C3IpXHFx9S99CTuJ8Z0KLVjRlA7ZgTuJ8ZgXxmJL+kIlwAkXBQk6HFq9pWRVA8fSvXwodYgdS892a6EA1UNvouqwXdR99KTeAtyfz2IL+kI1cOHYh9wqwVwKWJqpXbMCOv19gG3Imzb1JF2OgZxfr/NukH4jcNVfyEAE8IU+4BbKet1PfaVke3BtA/i/H6b8aIBt7a4mWmaC0nr55vmqRp8F5V33Mm5LhHtwbQF8SUdsSDCb1I1+K42g1xIWgOYYh9wK+e6RCBs29QxSIWus37aJM51iWjx4so77mwD1d5AHQ1eecedlN9yuyVlva6nrNf14Q7cEmRn4W7u3T2E9ME3UX7L7W1uZg5Weced1s3sA2613ql5LXzQjuRclwjcT4wxTXQeRHC7GLdnHPeensiCVwa3e0PznZk3EbZtwluQa0kofz8NcVNxr++Ce30XnNuv61Bcu7viXt8Fvyu7JYipjfGHxzD+8Bh2j+7fAiZcC+Y0zPDIbCyD6DyV6DyVeDcIQR2C39J4oieNJ3oSOnkVcnZ35Ozu6MVdDHF0N6S4C43OqJYg/0ydzb27hzDx0FjuPT2R+asfa6OVsl7X40s6QoWus/CQk6fWZPHChhxe3lbMCxtyrN9TyxSQSwidvMoC0XK6tRGybPjSRmOuNUKVo4Zxe8YxIu4+Jh4ay/jDY7j39MQWWjnXJYLGFR9Toes8tSaLiavTrIHDxfxfapkCwW8hy9YuhCmhk1fR1FRnaCS1NM4yy8RDYy2tjIkZRXq/HtYsCnqc2sJDTkYsTrU00J6YkEJQR7M/eEGY0MmrcOenqjZA2JmyzTJLuJiOe65LBHUvPUmGR2bE4lQmrk7jqTVZHcrE1WkMWpRIdJ4KnpUXBCHLRl3e16EWIOEaMU00/vAY9na/gsYVH/NdgYe+8w9bMBeSQYsSWXjICcFvL2ga+dhlFwcJ10rjio/ZklprgbSWiavTWvzdd/5hXt5W/OtATC201sq9u4eQ+PVijmSW0nf+YQYtSmTQosR2gUYsTmXQokT6zj9saeRCpmkJ0hxD2gOZeGgsI+Lu45+ps7FXlFmDmDDtSd/5h+k7/zCpZQpa9cwOQciyIR+77LyzFhXlMyZmFOP2jLP8orVWRsTdR2ppHFtSa+k6ZZM1WHvSdcomwyxySceayO4OWTY88TdirygzUkWf18eL2//RQiutYcwYE/Q4tagDOUQ8uo6uUzbRZ3qMJV2nbCLi0XU8tSbrolNXzu6OfOyylgEN4NOkaO5acw/j9ozr0ET37h5imehIZimPL91rAfSZHsOQBfuISS7E7vaTETeX0MmrOoQInbwK+dhlNKWsahni0zPSuGvNPW1M1BrI1NrOwt0WkCn2ijJSS+MYt2ccuQk3oxd36RCi8URPY+HLT1VbgGiSzPsx71laCddMe2Yygf6ZOtuScXvG0XfJn/n8YL+LQnjibyQ34WZ8Xl/bfKSoKL+FVi4EYwKZcu/uIQzaPoExMaPQcrq1ADFX33AI1+6u1OV9HVI6ShU/TYqm75I/dwjTHtDEQ2MZt2ccg7ZPaGGScIDWEBlxc42UoSMQ00StYdoDCgcbtH0Cbx+8p40ZTIBwiFM7RmB3+y+exZvT2YRpDdR6ZoVrw1xRWwN44m/Euf06A6Ki7NLrmnDNmH7TEdSg7RP4/GA/yLK1GdwEKNzSk1M7RlDlqPl1JefOlG2MXTGmXaAxMaMsB/XE34h4tH+7ANlrB7T2iV8OAlDlqOH9mPcsIBPKlF3R16Ad7GwlxoVberYAKCrKv1ghfmkg5sPldLIzZVsLqLErxpC9doAlp3aMICNurlGyVpRdSAu/HqS1Q58rd1JUlI87P1UtKsrHXlGG3e1HCOoov+x2wiX3RxT+o49L1IgutXxVUCfDIxNfLraQDI+M3e3/NdCXbhohqBNfLrIsVzZqmoT6dmXG0SBLTrmJLxd/CVRLECXcDGFaSC1TmHE0yKg4B0P2uxiy38WoOAePHaptAfHYoVqG7HcxcGc5o+IcfFfgsbQUPoYoSa213BbE78oGucTSwpJTbobFFjNgbQHdvi6g8/Z6Om+vZ8h+VxsQE7T/97UMWFvA+Og0UvIryfDIZBQ4CeXvt8a5IAhAY/RImlJWUaHrPHaolhuXFXHN+8e58qNcbomq5P6t3xG973WePLzPgnnsUG0LiP7f1zJwZzk3LisyctfSOFxOJ4lfLzYToQubxu/KpmpWBFWzInguOokrP8ql7/zDRMxLpFfUabasHwlZNnITbmbgznI6b6+3Bu7/fa2lrW5fF9Ar6jQD1hYwLLaYx5fupdi+EiGok748koa4qa010xKkKWUV2UM7kd6vB7tH9yfpnUFkLzQiZOGWnmgHO9N4oie9ok5bA4YPbkqvqNNc8/5xIuYl8tSaLOLLRXambENXF+PxNJD0ziAanVHhYaEliH1lJD/1iqD0qSsIzu2M/N550TZ3QjvYmS3rR1qDtwdhgpgwnabGMj46zRjQsxJdXYw7P1X1pY0GuaRjkMKxPah5qxuV8y6nct7l1LzVDfdyo6miHexM+ou9mblwKfdv/Y77t37HNe8fbwMQDhIxL5FOU2PZklqLJjUYdU7wWxBuN+ricBAF0KQG6pcNovZpw0fCQao/MEBcu7tSOLYHjnu7EZzbmeDczqyfNokrP8ptMXi4XDnzAJ0n72TIgn1oUoMB4VlpgIjj24I0payi9KkrqHj+Ssth2wM5c38f8p68D2nbHKRtc3h86d42A/eZHsOVMw9Y0nXKJmxDvyS1NA70z8Gz0qh5hNvbzpr6ZYMofzyiBUwLkOVdjfR/eVcao0dSl/d1aHx0GhHzEi0TXDnzAJ2mxtJpaixdp2yypM/0GLrcs5D3Y94ztNDsK7qjuxmzDBBz2rYGqZoVQc1b3dr4yfppk+g8eWeLd91aAxGPrqPbyKV0G7mUiEfXMWdz+nmQ0Jsgn1AbT/SkMXrkeZC6vK9DpU9d0S5I5bzLqf6gq6UV7WBn5q9+zDJBuEQ8us4SE6LLPQvpcs9CjmSW4ndlo1XPNBxWLiE34WbSX+wNapEBEsrfT/njERSO7WGBmDA1b3Wj9KkrSO/Xg1WjBjJl/CT+8sQ8a0BT/eGDhwN0uWchXe94ia07YkE+oSLc3gxyQt2yfiSrRg0E+YRqgRSO7UHh2B4UT7ragqmcdznFk67mp14ROO7txpTxk7AN/bLFgN1GLsU29EvrejiACdG59xQjKgu3GzVP9UwIvcmCVwYb102NmBHVBDFNVDUrgjP39yF98E0E5xox5Dcj5lsDhwOYQObg4dK59xR2RV8D4njEo/0NIEd3dkVfgy9t9HkfMTWSO6pXG63kjupF8aSrqXj+SoJzO1M573KmjJ/Eb0bM5y9PzGPBK4Mp3GKUEFvWj+Q3I+a3AOjcewp/eWKesUQ0T1mz2att7oSU9+F5EE2SqXvpSbKHdrIGNmHCoapmRVgh33LezZ3QNncyloGDnVnwyuA2IFvWj0Q+dplREzu6Wy0r9/KubVvg9pWRpPfrwZn7+1haMSHCxdSM/J4RWWufjiC9Xw/m9PgtN9w0uo1JbrhpNI0njAXTrAIbT/TEvb4LjdEj2641vqQjpPfrQfrgm1qYKHxKlz51BbmjerFj4G2WtAYwtWDKglcGG2ZoXrldu43AWDUrAmnbnLaRVZMayHvyPn7qZThoa38pfeoKap+OIDi3M6tGDeSGm0a3GTT82g03jeaGm0bj3H4d8rHLrN0I93LDpDsG3kb68si2a425hfZTrwjSB9/UBiZcM+YM6ghoyvhJpL/Ym+yFhknc67tYQVF+z3gjc3r8Fuf32zpOFTMeHXpRGDNfMYF2j+7PqlEDWTVqIOkv9rZ8SNvcCff6LlTOu9yK1Okv9mZOj9+S8ehQNKmBDhs17vxU9adeES1gwoHKH49oFyhcwhfKynmXWzOu4vkryR7aieyhnQjl7+84QzNNJGzbxN7uV1gw7WmntYZaLw2mmNdrn44ge2gnztzfx9od7zBnDa9t0pdHtgsTDhRustaaCndwEyLj0aG481PVS9r3FSUJj6eBrConMZHvnodpntrh2gkHCgcLl/TBN7G3+xXGLMlIo0LXjU7ixeoaUZIQ3C7OlTtJya8kJvJddgy8DctvWgGFaylcHPd2Y2/3K5jT47esGjWQrTtiyapy4nI6jUrvUmpfUytFRfmkZ6SxdUcs66dNYsfA2ywNtQBrJeb/dgy8jZjId/kx4YgF4fP6Ln1L3uyhhWvnSGYpOw6lEBP5LuunTWLDAw+x4YGHrAi74YGHWD9tEuunTSIm8l227ohtAyBK0i8/pNDagTVJxuf1YXf7OVfuJKvKMF16RhrpGWkcySwlJb+SrCqn1awRgjqaJP9nO0b/Zxo1v+ahS0ZqKJ9QCX5rJMyhN42aRj6h/udB5BKjiAp+i64uNrJ2M0Vs3rUiy4aU92G42X49iCYZDZjUMoX4ctFIcILfGgVU6E0LwEyCxKP98aWNxpc2GvFof+RjlyHlfdjxWnOxh93tJya5kIWHnDx2qJbnopP4NCmaYvtKC0LL6WYkQps70RA3laaUVbjzU1V7RRn2ijK8BbkWUJsM7VIAog7k8MyuPKtD1AJA/9zQQpYN9/oubFk/kpkLl7J4a0KbtrdZa/vSRrfMWS8GcSSzlGd25TH5VIjptTpR9T5SS+OMsrHZD3RHd7SDnTm1YwSzY2KsTtL46DSei07iSGZpm/tKeR8a5gnf0+vI8zfE5zAstpjptTrvifBJeeZ5LTQDkGXDtbsr0fte59mjDmaWaUyv1ZlZpvH3XJlRcQ6Grj5OTHJhy/t7VhrpwMVAog7kMCrOwcs+nZWaccak2L7S0oLpC6d2jGDJiUyWN8E6FVZqsLwJ5ruwYO5O9jFoUSIb4nPOT+/gtxf3kZjkQobFFreAaHRGGZoQbm+hhWd25fHsUQevHilgbo7bAmoNM2S/i6Grj3Mks9Tolcgn1Hb39MzHuXInw9edZrJd4z3xPISuLrYgCrf0ZOuOWKLzVFLLFDIKmlfr5EJmHMxhfoWvDczkUyELxl5RduFUUZNkIvdm8+BpkZd9eocQPyYc6XDnocpRQ+TebObmuFmptdTK5FMhBqwt4K1vMi4cWTMKnIyKczDZrvFJeWaHEBdrbVc5aphxMIflTR1rJaPA2TFI1IEc7k72tZwdYRCLtyZc6h4MMcmF7WrlwRSRAWsLiNyb3T6Iz+vjmV15jIpztIHwxN/I7JgY4svFS47CHk9DG62Y5hm4s5zx0Wntb0CnlikMiy3m06ToFpFSO9iZnSnbeGZXHkcyS8kocF6SHMksZc7m9AuaJyW/si3IltRaZsfEGNM09KZVs2bEzWV5EyzLlXn1SEG7MuNgTruy5JS73dlzd7IvPMi1BIlJLmRnyjbLJFawar7ZHi5NdrSS9jRyd7KPXlGnzQDXyjSlcYY2mk1SuKUnS05kslI7f9M9/HKgdaoh74nn/cR02NV7M9t2A9A/t/qf2uZOvB/zHvNdxk3Mm0bV+36VzK8wxHTWVutPmEbkE6q1hjQ3/yefCvGeeB7k1SPGlLsUeeubDOtnezJnczpvfZPBuXJnGEjzAqSri9FyulG4pSf3b/3OCvErNQNmxsEczpU70ST5kuWXJc9yiZXemQ3du5N9TK/VedmnW1qZm+M+v3r+gpTS42nA42nA5XRa4vE0hFd8zSDBb63cInvtAAYtSuTuZB+T7ZoFYy7tz+zK6+igQZtHRoGTyL3ZLab4M7vyGB+dxpAF+1i8NaEliLmWyNndsa+MZPi60/T/vpaJhTKT7ZqllZWaoZW3vsnA42m4IMS5cifPRScxN8fNeyK87NOZXqszsdDITa55/3i4dgVb0OPUTG2IR/vjzk9Vt6Qau5R3J/uYWCi3MJEJM2dzOkcyS80Q3WKrPia50IIIX2cmnwrxYIpIr6jTPBed1Mo0apFgpv0NcVMR3C5ESWLO5nS6fV3Ag6fFdmHmV/iYcTCHyL3ZRB3IsSRybzbP7MpjfoWvXYj+39cyZME+c7aEgTQ36smy0RA31dostrv9DF193IIJ9xcTxgSam+O2xAQwg9fMMo2JhTIPnjYgBi1KbC+RPq8REyR8iT9X7rRgWptpvssYLBwqHGB6rc7fc2ULYsh+F4MWJbLjUErH09c8ytcaxNTMCxtyGLC2oIUDT6/VO5TJdkMLJsTAneUMWpTYNotvE0eaj3rKxy6zun2t69mdKdt4fOley4lN35ls11pIOIC51D8XnWQu9xcGUQCteibyscuM5n31TKNqD5fm1H9DfA7PRScxdPVxhsUWMyy22Dq4MGS/i2GxxQxfd9oC2HEopb1WVcdtCU2Sqcv7OmTWpGbRLOV9SCh/P0GPUwvPvDIKnMQkFxK5N5s5m9N5LjqJ56KTeOubDFbvzSQlv7LN1P5FxzZ8Xp918v8SWk5WsWStLbr0a5oLHRdY/+GjPP8vtq7+0yCiJOHz+hDcLlxOJ2bzxeV0Irhdlk/9x0B8Xh9VjhoEt6s5rZTaFU1qQHC7qHLU/PpZ05EGqhw1uJxO0CVESSIlv5KoAznM2ZxufTJgzuZ0og7kkJJfaR1mcjmdVDlqflkc6ahSs1eUWdMzJrmQQYsSrYMJNy4raiHmYQWzD2IC2SvKLpa/dAzi8/qsc6cZBU6GLNjHlTMPcEtUJVMSdd45qRGdp7KxDOvDPu+c1JhxNMgtUZVcOfMAQxbss0K7vaLsQqbq+GCtCbEhPodOU2O58qNcZhwNsrMK4t0Xlp1VMONokCs/yqXT1FgrE7sATPvbJK0hblxWxDsnNWugvc7zcqFry3JlbomqbANzSdskpk9kFDjpOmWTpQnzne6sMgbbWWWYY8kpN0tOuYnOU1v8z9TcOyc1blxWRNcpmwwz6dLFjxr7vD5rY+eO13YSMS+Rh/co1iAby4wBluXKLDnl5rsCD1lVxk7FdwUelpxysyxXbvHcjWUwYb9CxLxE7nhtp7X10spELUHMMiHqQA6dJ+9k8KYaJh1u6ZRLTrnZklrb+hS3lURtSa1lySm39fyNZTAlUWfwpho6T95p1rqtS5LzICapJsmWNkbEBpiSqLMs1/gY3DsntfAuT4tDlkrYtci92bxzUmNjmaG9KYk6I2IDbbTStsBqjhma1EBKfiVdp2xiwNoCHt6jMOmwxjsnNev46KWUkaIksfCQk2W5Mu+c1Jh0WGPCfoUBawvoOmWT1d4Miy3nQczIuXpvJp2mxjJ4Uw0T9hsg09KM6fhcdBIxyYWXJM9FJzHjaJBpaTDpsAEzeFMNnabGGhVec+RtA1LlqAFd4vGley0Q8wZTEnWmpWGdWX3sUC3PHnW0K+b/n0qoZ1oaTEszfCQc5PGle0GXwv0k7PxI87S9EMjMMo35rvMdILPDbErrzlA4iOmw4SBh0/iXgUxLg8mnQvw9V2Zmmdau/D1XtpoxpiYe3qPw8B6FW6IqreOCvwpkWhqMinMwaFEi46PTfrFMXG38HLr6OHe8ttPykXZNYzrr4q0JdJoay4C1BS2cdfCmGuZsTrd6Hv/T5ozZJ7no9L1xWZE1fU0bD193unXx3GESFZNcyIb4nDazaUN8Dh6PkTy1O307CmgT9itM2K9YWnkuOumi26wTV6dZR43NXOXKj3LpPHknEY+us0DaDWiWnwCr92bSdcomBm+q4eE9ShsThTXh2jRn5mxOZ/CmmjYzZkRsgE5TY40Q33bhu/iiF66VcJjh604TuTfbUnnk3myGrzttQZgzZtJhzQrvfabHWGNccNELnz2tfSUcJjxADVhbwIC1BdYsMyOp+fyH9yhWGnAks/TS0gDTV4qK8q2NxU5TY7klqrIFTDhQ6+gZ/hwzdoSbpKgo/9LPj5hnR8yUwEwVw810MRkRG7BSRXPpLyrKv/RUsT2YI5mlLZLnEbEBK1q2lhGxASt5vuO1nZY5ioryL5TJX7icENwuioryjV1rr4+oAzkMWbDvouXEkAX7iDqQg8/rQ5MaLgZxaQWWJslWSWkWWBkFzl9UYP2PvgjFPNrj8/osM/2YcIQfE46QnpFmfL7K7SLocWpBj1Mz6+D0jLQWzzPb3b/6aI8SVnCbvXTTVOZxno6kqCjfKlPNUH4pIP9XPGz/N319UFnrf2iKLGi6LmggqCBoIOi6JuiqIqCrgqIrgqyrgoYu6JpiiK4LKgigCpquCCEdQdVVAU0VdP2iMGW29tplmtbcQNQ1QEXXNDQdQGsWHZBbvdQsKkTQfaiaBJrc/PyLPpQ2zqqbL9U10GV0TUbTZUCyQAoaJPaVinx5RmbVKZnVWRpf56r8WKlQFww2Q4bf8VdMXwsEtfkdGb97xSAb8yRG7df4zYYQ3deEsK2WsK1UsK1U6LIqxJWfKQzcEODVw0GS7KbG1F8Pout6C7WuL5Dpv1PBtlLEFgWXfyHTY61Ery91rvkiwLWfB7h6jcxV/5LoskLF9gl0+tjLI7FesuuxzKnrHeqneQdL143Bjacj6wqg4ZFUph8JYvusCdsXIldvhGvXi/T+SuS6dQrXrZO4fp3Ib76UuH5NiD6fi1z/mcgNnwa5epWMbbHG1StEvsoSjbeoq2i60h6MYNN1XTAhNF1vdlBoVFSG7/Nh+1Ti2o1Brl8v03uDyDVfN3DDVz5u+FKh15cKvdbp9FoHvT5X6PW5wjVr4LrPda6NkugTJdL1EwXbIpkVx5sdGaXZ8S9gGgNIJ6ipPHgghO3TED23h+ixTafXZpmb1ofos0ml+9dw1VcaV3wapMvKIF1WSVz+qULPzxV6faZw9Wc613yq0Xt1iN9Ehei+WMG2QObz03JHDtxsGk07P2XRmZ/hx7ZG5rqtMjdubqTHFonrNov8doPMZRvA9pmPqz8X+MNWhb/tkrg/VuGWaJXLPmmk85Imen6m0+sz6BMlcsNqP9etVujysU63jwIcrwy1N6UFm6Zrgma4KKBxrE7lyq999PnaT58dcMNWjV5bFa7d6sP2lcj/+szP6/FNHK2SqQtpSKqIKItUN2psyJH52yYXtkV+uq9UuP5fMj1XqVy9WuWGFSE6LQgxbHMQv6kVXW92B12wKZouSEjGNNMVJvwgYdugcGOsym+2q/TZqnD9dh3bVz5u3h4guVJtnpJa808zkJlBMMS7SQG6vB/gimUKvVdK9Fmu0nu5zLXLZGzvaWzLDhggmoysqwYIKoKqG+rKqVO5douP62JUfvutxg2xCn1iZTpv0rgpRuF0XQAIgRJElSUURUWWZWRZRpFlgrIKeIEg7yaC7X2FXkslei+XDVkmY1sQ4pFNDaA3hwcdNF0XbGjNZwNQWXZaxrZV5XexMjftFLnpW4ne34rYNvjZUywBQUJqEEkMoEk6oqIgySqipCCKEt6Qis8fRNEaAB+TtijYInV6Lwtx7VKRPstkIj5S6PGBRGFtwFCgApquCDYFTQANXZeZkiARsVPnlu9kfhcr0/cbiYivA4w94DM0oet4VQVJUQiJGiFRIiTKBEMSAX+QhoBIvU/C1SQCfpIKGrl8kZerFitcu0Tkuk9ErlsiYXtDYuMpYyobE0gVbIouC6DiDsgMiwtx406Z/rs0+u6WGPCNSI8tIZbnSoCCEvITkBRkWSMUkAgEJbz+EE2+IA3eAPUNjTR6fNTWSni9PuoFN/d8KtBpkcg1n3jp82GQ3h/6sc33seAHb/P6pYOmCTY0VQCNEkHhrgMhfrdL5k/fafT/XqT/boU+sRI/2r0AhESFYFDCF1TwBSWa/CE8TQHcjQFcDX6cdQGq63w43PWU1AoEmup4emMjtvl+enzop/d7Aa57N4Btvo/Z37jCHBzBpuqaAHDOHWDo/iD99in8+XuZO/er/H6fxsB/h0irDgGqoYGAhOAL0eALUd/oo87TRK2nCUddI3anQKXTTUl1DUVVNXga6nh2mwvb6066L3Bz3btOekU2YXtd5MVNDmuVVtEFm6brAmiUu4OMPODnjv0idx+UGHpQ4q6DEnf928+h0iCg0egN0OgXqW8MUCd4cXm81LgbqHIJlDs9lFd5KK90U1hWQ3GlgLOqlrs/rsQ2q45rFjq57q0yukc6sL3iYc62akBDR0fRNcGmq5oAQYSAyuQEibsPhnjgkMYD8T4ePOTnv/ZrfJrtBTWE4A3ibvRTJ3hx1jdRXddApbOeMoebEruL3Ao3p8vqOVVSR1JuDZkFtbywvgDb0zl0eqmanm+Wct2bFdhmlvP2Po/hH6qIrmiCTdNUAVVElTVeyfTz10My435UGHNE5JGfJIYf1ZiV4kFo8uILBKirD+LwBHC43Dhq6ymurqfAUU9ORS05RSU0NHmQVRW/JCMqOho6354U6DEri04z8+nxWim2fxSx8ZgLEAlJCqoiCzZZUwVZVECDjUVNDD8s8sRRlSmJOs8mwbPHZJ466iO2yI8aDNJU56a8tpGqaicOZx2FVfWcLa8lq7CMBn8IHfAGZQKSik/SQAoBOjEZtdiezqTTS/l0fzmPrFIBNB9CUCcoSYJN0TTBKymgS5TXBXn8pwCTj8lMT1WZmarx+nGR2Rk680+GOFleh9/bgMtZR3V1HYWVLvJKajiTV0pVjRsV8IVEgrLaLApeERSCAAx5/xS2+48zZvlZAmKIQFMTHq+PppAi2DRdFQIyyKIfRImoMz6ePO7lpUyJl08r/PN0iMjTEh9kS6zNEUgp92GvaaDAXstZh4DLG0JoChAMyviDMn5Jxi/K+EISIVnFr0h4JWPZ33a8mNteSCI6vhpZbMDhaqChyYfHHxRsmhYURBECoRDoMvkukVfTFN7IlHk7W+aDXIlVOSHW5ob4qhi2F4v8WNLIiSov5wLgkVVERSUYMqa2LyTjF1UCkkpQ1vGLImJAxCsai2SdKFJQ6aG0ooqK+gBuVxOCTxBsuq4IkqQSFCVCkgyqzg8lXt5J9/H+WViVJ7G+KMSOEoVdJSp77DJxdRrH3Rq5goLDJyMERRqCIt6QbPiHqBAQFSRJJSCrhGSZJklDUs/nIefsNRRXe3DWefE0NjUf21BURFEiGDRWVH9I5Nu8Rt7Pk/lXocbWIpFvKzT2VSr8YJdIcEqk1Svke2TsPhV3SMYTEmkISngDCr6QTFBSCUkqQUnFL2kEJUNLflFF1aGuyUepow6HuxG34DdyVkVRkCQFUVLxBWR0ScEfFPmuuIG1hTIxpSr/rpA46FBIqJHJdGmcqVPJa1Co9MrUBiTcQQlPQKYhoNAUUvCJCn5JJSApBCTZEr8oEVJU/IpKiaOOmnov9Q1+QyOqqiErGqKiIYk6/mAATQ4QalRItPvZU+EnvkrmxxqJRJdIVp1KTr1GQaNChVei2idTE9BwBRTqAzKeoEyjKNMkKvglhaCkNAMZogAeX4DS6npcDQE8jYHmM0aajqLqyLJOSNbwSTJev0woEKCxyU9OdZCEkgAJ1UGSBYWsBo3cRihq0qj0KVT5ZBwBjdqQRn1IRhBVGiWVRlklqOiIikZQ1hAV4ytjJE2n0ummqt6LU/AjNAYEm64jaBqoqo6iaEiKhiirBESVhkAQr9eH0ChSUu3nVGkdGY4mUmt8ZLoC5DWoFDUplHpVKnw6VT6ZWn+IuqCEJ6TQEFINzUgSflXFJ8nUe304XALVdQ3UNwaob/TT5A0ZILoO4TCyrBKSZHxBGcEfxNPgpdETwO32U+ZoIKesnrPlHrLtbn6urCfPXk+B3U2R3cO5qgbOVTVQUilwrkKgtEqguLKe4sp6yhwNlNg9VLkEhKYgjd4QTX6RYFA+X2Dpuo6maaiqiqqqKIqGKKn4QwrekERjIIC70YenMUBjk0S9EKK23our3ovb48Xj8SI0BfD4ROq9IdyNQeoa/Lg8AZxuPzV1PuobRASfguAN0egP4Q1KBEMykqwKNkAxMnpDNM1oSxhQGrKiI6oqTapIkyTiDYUIiDLBkEwoICOGjHghKxqKqqCoEooqEVJFgkqIkBIiKIsEpBB+MYA/FMAXkgiICiHRmK2KoilWo6bZRIKu61bjRdd1QdEQVBVBkzRBlVRBFhVBVTRBUXRBknVB1hAUECQQNF0XUHVB13RB0XRBVDRBUjRBUTVBUlRBlBRBlGQhJGuCJOuCouiCpuqCqqpl/7Eemqor5HnS2Ja/hPezpvCP1PuYlfo3vvo5EnfA0baH9qs+CKZpBIIh7DUuyuw1lNprqHDU4mnwoqoamq5xyn2YVTkv8cKJO3n+TH+eTB7Ao/H9eSr+TnbmrfyfgdiddZzKKaK0yklhuYN6oWVfvabay+6Tu3gzaSJPpPZm9E9XMmnvH1n60wKSanZypuEg35WuZlrCMLb9vPSXgzicdWTkFLX7vya5Dq/spk62s8v1AW+cu53ns29kSd6z/Fi9mZ/L8tpqVFfZeHYxBe7MSwdJy85v8Xd1oJwDFRtZlTeTD88+wcKsMSzMGsv8rL8wNbMnc7LuJN6xg6AcsF6TW1xBkzfQct9P8pDrSkfT1QuDKKrKz8UV1t+V3kKi89/m1YyhvHlyMPOz/ouFZ4fwYe59fJAzjLfO3s66wuep8p7jbF0iUTkzOe76/rzZ6jxUVteGtch06gL2C4PIikJFtcv6e3/ZeuamDOHNU//NivwxfFY8jnXlE/iyYiKflz/Eh4WD2Gv/CL/YQIJjI2+dvJvXTt7FtJS+LPt5OvVBY383KEoUlFaGzSz5wqb5ubC0WSsyG3PfZUbKnXzw8wOsKX6EdWUT+NI+nq8cY1nrGMnikjuJd0Xhld1sr3iTt37+IyuLHmZN0WMszxnPzLSBvJnxMMWNPxv7vUITLrdw8VlzMswnNud+xD+O3cGy3LF8ce5R1pZN4IuKsXzlGM0X1SP4uPJ2jgpraJAcfFb+CJHnbuOz8pF8UT6OL0om8nnRJFblPcrLaXfxxolROHzGd2idq7xIHBEavTQFQwAcLNvMP5Lu5JOcsawpmsRnJROIKnuYtVWjWVP9Vz6q7McRz0pUTSa2Zh6LSgeytOJPfGa/j3UVY1lTMoFPz01kdcEjLM95hNmp/8UHmU+j6MYnlrJyz3UMknHW0IbDW8rLyfexIGs4nxU8zqqi8Xx07gGiKkfyheN+ltnvJEFYGdYOFWlUqjniWcGK8iFElQ1jTek4Pi2awOqCR1iZ9wgfnx3Hs4l9+aHc+BqH2voGRFFqC+JpaEKSjOR2Y84iZqX8majcx1ieN57Xc+/hvXPD+aziAZaX30VGY0yH0/1s00E+KR7KquL7+ezceFbnT2BFzkSW5Uzg7VP38UbKQ3hCdc1aKWoLktHsG06/nbnJ9/H+6VGsyJnIC9l38kreMNaUPsKSkkHsdy26aABMcK3lw4L/5l9FY1mdP56lOeP55Ox4Psh+mOeT7+BAyUZj17O8qiWIKMkUlNoBOFQaw4zkQSw+M5bZp+7in7mPsKnkFVade4DPSsfTJNVeFCSk+lhbPIVl+Q+wMnccS8+OY/GZsXxwZjTTj9/OkqwXACi3O/H5A+dBKhy1lFQac33t2bf5R/KdvJnxFxadnkSyYzuf5j3BssIR/Kt4DBvLp/NF2dOsqXiSNRVPsKbyCeNnxZN8XjaFz4ufJrr4Bf5V8Agr8h5iWc5YPs4ey4enR/P+6YeYnfZn3kh9CAUfqgz2Gtd5kLOFpZTYjUMHH516jmlJA3jjxHCO2XexteBtFpwZyqqC0awo+huLCv7Eu4W38V7x73mvtD/vl/Xl/bJ+vFfye94tuo2F+X/g3dw/szT/b6zIHcMnZ0fz0ZmHWXT6ISKzRvJq5mBeSh5MSeNZyzyyrBggWTlFlNsNssiMKYz9oQe7i/9FmmM/r6bezZKfx7Is5yGW5f+NFYUjWHXuflaXDmN12V+JKhtGVNkwVpX9lZXFw1lRNILl+Q/ySc6DfHRmFIuyRhF5ciRvZ/6NNzPvZ3baIJ5N+AM/1xsfXcg9V47XH2wLMidpFE/9eAcVQg7Lsp7j9fShfHTmIT4+M4rIrKG8ljGAeSf78eaZfszP7sc/z/bln9n9mH+mH29m9eO1jP7MPfF7ZibfxvSE3zP1UD+eiruVxw/cxIT9fRj+764Mje3M6bqjAOQVl+MPhgyQvHPllFQapnkhfgRf5y7haNV3PJvwe945+QDvnnyAf2bcQ0zR22S7fySzbj+Z7n2cdO/jZP1eTtbvI9O9j8y6fWS49pHm3Edq9T6OV+0luXIPRyt2k1C+i/jybzhYupUfSrfjV40wX1zhQNN0A8RR66bEbjjr5p+Xc9IRz9snJvJ88h94O/N+3s64j1dS7mJLXuT/v0e/vT6qa93nnVXXdXLOlRtJi6qSWLmL8Yd682rGvcxLG8qbJ4byRuoQXj56L+UNuRcdoDHk5kDJNvaXbuZA2Rb2l21hX9nX7C3byNaCKJKr4pqnbw3+QLBlQDttxn4dPsh4hseP3sjcjP/m5dRBvJYymNdTBjMtvh8rT865KMja0wsZvqsr4/f3ZNyBnjx88CpGxV3BiAM2bt5iY8PPKwz/KKlsG1lDooTgCRJAYPKR/jyb2pcZaQOZdfyPzDn+J145/l/MSfojU364lW05yzuE2F30FU/80JcZSQN5+fifmH38Tmam3MGM1Dt4LOE6pv90DyHFCGLZ+SXtL3pn88rJCR5hbPy1TEq6jqnJv2XGsduZdfwPzD52By8n/5FZSX9g8sGbeDflGU7VHMUTqKMhVM/Z2hMsSZ/JY3G38I/E25l77I/MOv4HZhy/nRkptzE1+Rbu+beNhMrvjLEKSi+cj0T+8AaPZfTi2eQ/8Gj89fz96C3MSB7AjOTfMzPpNmYn3c7MowN4/IdrmXKoPy8l3MtLP/2Fpw7fxiMHr+HFxH7MTrqNmUm/56XkAbyY3I/pyb/jr/tsRJ542hqnOGydaRdkxv6J/DXBxvflX/Fd0Rru2W3jmYTrmZnUnxlJ/ZhxtB+zjg5g1tH+vJBwM1Pjr+fZ+Ot5PuFmZiX2Y9ZR43kvJfXlpeR+PJ90M3/da2Nm4gME5MZ2c5F2QV5OeYA/7rZxrOYgANE/f8S933ViTFxXZiX1ZfbRvsxK7MusxFuZnXgrs8JkZuKtzEi8lZlHf8espL48Gd+Lu3fbeDVpLA1BY+kvc7T7ZTktQUQlyLQjg/nzv20cyo+zrsdX7OKR/bcybLeNp368hpd+uok5ib9lbuKtzfI75ib+jtmJv2PGT7fwfMJveOj7zty/O4JPs+YjKsYUdTc04Wloav/YRusLz/04lAeTIsgsPENewfnc0is1EH32Qx47MICH913F+O//F+O/t/H4wW7877gIHtnfhXHfd2Hs91cyZl9v3k19lgLPaev15TV1NDR6Oz4/0vrC26ceYVhcL45X/GB4d2Eljf7Q+cJI9pHqiGPVqVeZd+wRZicOZ0bCvbyS9DAfpD3PnnNfUuO3ny9NVI2T+eVI8oVPGrUB2ZsfzX1HehJTtMK6FgyJZOYW0+gXf1EIz8wro9LhvKTn2lrugkMoFOS5n/7C0APXYK8tb3GepMrh5HB8Cmknz5JbXEpBSQVlFbVU2N0UlVWRW1RK1s95/JCQzMkzPyPLMpqm4ff7CQQChEIhJElCURQ0TcPsVOm6fn6tCT+oUOkq4bGE27n/qzv4KeMIwVCQQCBAbV0ttXW1VFRWkJ19lrS0DJKSj5F4NInk5OOcPHmK/Px8amtrcbvd1NTU4HQ6cbvdNDU1WTCyLKOqaguYDmvfgNzE4bIYdpWv4UT5EezuMkQl9B877PT/DQC7cLwx8LR3hQAAAABJRU5ErkJggg==) no-repeat;padding-left:40px}
- .browser .browser-firefox{background-position:0 -34px}
- .browser .browser-ie{background-position:0 -68px;margin-left:0px}
- .browser .browser-360{background-position:0 -170px;margin-left: -27px}
- </style>
-</head>
-<body style="margin-top:50px">
-<h1>请升级您的浏览器,以便我们更好的为您提供服务!</h1>
-<p>您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。</p>
-<hr>
-<h2>请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束</h2>
-<p>自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 <a href="https://www.microsoft.com/zh-cn/WindowsForBusiness/End-of-IE-support">微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明</a> 。</p>
-<hr>
-<h2>您可以选择更先进的浏览器</h2>
-<p>推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。</p>
-<ul class="browser">
- <li class="browser-chrome"><a href="https://www.google.cn/chrome/browser/desktop/index.html?hl=zh-CN&standalone=1"> 谷歌浏览器<span>Google Chrome</span></a></li>
- <li class="browser-firefox"><a href="https://www.mozilla.org/zh-CN/firefox/new/"> 火狐浏览器<span>Mozilla Firefox</span></a></li>
- <li class="browser-ie"><a href="https://windows.microsoft.com/zh-cn/internet-explorer/download-ie"> IE 11 浏览器<span>Internet Explorer</span></a></li>
- <li class="browser-360"><a href="http://se.360.cn/"> 360安全浏览器<span>360 Chrome</span></a></li>
- <div class="clean"></div>
-</ul>
-<hr>
-</body>
-</html>
\ No newline at end of file
diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html
deleted file mode 100644
index 56fd45b..0000000
--- a/ruoyi-ui/public/index.html
+++ /dev/null
@@ -1,208 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="renderer" content="webkit">
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
- <link rel="icon" href="<%= BASE_URL %>favicon.ico">
- <title><%= webpackConfig.name %></title>
- <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
- <style>
- html,
- body,
- #app {
- height: 100%;
- margin: 0px;
- padding: 0px;
- }
- .chromeframe {
- margin: 0.2em 0;
- background: #ccc;
- color: #000;
- padding: 0.2em 0;
- }
-
- #loader-wrapper {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 999999;
- }
-
- #loader {
- display: block;
- position: relative;
- left: 50%;
- top: 50%;
- width: 150px;
- height: 150px;
- margin: -75px 0 0 -75px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -webkit-animation: spin 2s linear infinite;
- -ms-animation: spin 2s linear infinite;
- -moz-animation: spin 2s linear infinite;
- -o-animation: spin 2s linear infinite;
- animation: spin 2s linear infinite;
- z-index: 1001;
- }
-
- #loader:before {
- content: "";
- position: absolute;
- top: 5px;
- left: 5px;
- right: 5px;
- bottom: 5px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -webkit-animation: spin 3s linear infinite;
- -moz-animation: spin 3s linear infinite;
- -o-animation: spin 3s linear infinite;
- -ms-animation: spin 3s linear infinite;
- animation: spin 3s linear infinite;
- }
-
- #loader:after {
- content: "";
- position: absolute;
- top: 15px;
- left: 15px;
- right: 15px;
- bottom: 15px;
- border-radius: 50%;
- border: 3px solid transparent;
- border-top-color: #FFF;
- -moz-animation: spin 1.5s linear infinite;
- -o-animation: spin 1.5s linear infinite;
- -ms-animation: spin 1.5s linear infinite;
- -webkit-animation: spin 1.5s linear infinite;
- animation: spin 1.5s linear infinite;
- }
-
-
- @-webkit-keyframes spin {
- 0% {
- -webkit-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- -ms-transform: rotate(360deg);
- transform: rotate(360deg);
- }
- }
-
- @keyframes spin {
- 0% {
- -webkit-transform: rotate(0deg);
- -ms-transform: rotate(0deg);
- transform: rotate(0deg);
- }
- 100% {
- -webkit-transform: rotate(360deg);
- -ms-transform: rotate(360deg);
- transform: rotate(360deg);
- }
- }
-
-
- #loader-wrapper .loader-section {
- position: fixed;
- top: 0;
- width: 51%;
- height: 100%;
- background: #7171C6;
- z-index: 1000;
- -webkit-transform: translateX(0);
- -ms-transform: translateX(0);
- transform: translateX(0);
- }
-
- #loader-wrapper .loader-section.section-left {
- left: 0;
- }
-
- #loader-wrapper .loader-section.section-right {
- right: 0;
- }
-
-
- .loaded #loader-wrapper .loader-section.section-left {
- -webkit-transform: translateX(-100%);
- -ms-transform: translateX(-100%);
- transform: translateX(-100%);
- -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- }
-
- .loaded #loader-wrapper .loader-section.section-right {
- -webkit-transform: translateX(100%);
- -ms-transform: translateX(100%);
- transform: translateX(100%);
- -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
- }
-
- .loaded #loader {
- opacity: 0;
- -webkit-transition: all 0.3s ease-out;
- transition: all 0.3s ease-out;
- }
-
- .loaded #loader-wrapper {
- visibility: hidden;
- -webkit-transform: translateY(-100%);
- -ms-transform: translateY(-100%);
- transform: translateY(-100%);
- -webkit-transition: all 0.3s 1s ease-out;
- transition: all 0.3s 1s ease-out;
- }
-
- .no-js #loader-wrapper {
- display: none;
- }
-
- .no-js h1 {
- color: #222222;
- }
-
- #loader-wrapper .load_title {
- font-family: 'Open Sans';
- color: #FFF;
- font-size: 19px;
- width: 100%;
- text-align: center;
- z-index: 9999999999999;
- position: absolute;
- top: 60%;
- opacity: 1;
- line-height: 30px;
- }
-
- #loader-wrapper .load_title span {
- font-weight: normal;
- font-style: italic;
- font-size: 13px;
- color: #FFF;
- opacity: 0.5;
- }
- </style>
- </head>
- <body>
- <div id="app">
- <div id="loader-wrapper">
- <div id="loader"></div>
- <div class="loader-section section-left"></div>
- <div class="loader-section section-right"></div>
- <div class="load_title">正在加载系统资源,请耐心等待</div>
- </div>
- </div>
- </body>
-</html>
diff --git a/ruoyi-ui/public/robots.txt b/ruoyi-ui/public/robots.txt
deleted file mode 100644
index c2aab7e..0000000
--- a/ruoyi-ui/public/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /
\ No newline at end of file
diff --git a/ruoyi-ui/src/App.vue b/ruoyi-ui/src/App.vue
deleted file mode 100644
index 29e2c6c..0000000
--- a/ruoyi-ui/src/App.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<template>
- <div id="app">
- <router-view />
- <theme-picker />
- </div>
-</template>
-
-<script>
-import ThemePicker from "@/components/ThemePicker"
-
-export default {
- name: "App",
- components: { ThemePicker }
-}
-</script>
-<style scoped>
-#app .theme-picker {
- display: none;
-}
-</style>
diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js
deleted file mode 100644
index 5d282dc..0000000
--- a/ruoyi-ui/src/api/login.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import request from '@/utils/request'
-
-// 登录方法
-export function login(username, password, code, uuid) {
- return request({
- url: '/auth/login',
- headers: {
- isToken: false,
- repeatSubmit: false
- },
- method: 'post',
- data: { username, password, code, uuid }
- })
-}
-
-// 注册方法
-export function register(data) {
- return request({
- url: '/auth/register',
- headers: {
- isToken: false
- },
- method: 'post',
- data: data
- })
-}
-
-// 解锁屏幕
-export function unlockScreen(password) {
- return request({
- url: '/auth/unlockscreen',
- method: 'post',
- data: { password }
- })
-}
-
-// 刷新方法
-export function refreshToken() {
- return request({
- url: '/auth/refresh',
- method: 'post'
- })
-}
-
-// 获取用户详细信息
-export function getInfo() {
- return request({
- url: '/system/user/getInfo',
- method: 'get'
- })
-}
-
-// 退出方法
-export function logout() {
- return request({
- url: '/auth/logout',
- method: 'delete'
- })
-}
-
-// 获取验证码
-export function getCodeImg() {
- return request({
- url: '/code',
- headers: {
- isToken: false
- },
- method: 'get',
- timeout: 20000
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/menu.js b/ruoyi-ui/src/api/menu.js
deleted file mode 100644
index ec9511d..0000000
--- a/ruoyi-ui/src/api/menu.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import request from '@/utils/request'
-
-// 获取路由
-export const getRouters = () => {
- return request({
- url: '/system/menu/getRouters',
- method: 'get'
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/job.js b/ruoyi-ui/src/api/monitor/job.js
deleted file mode 100644
index 3ee56b2..0000000
--- a/ruoyi-ui/src/api/monitor/job.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import request from '@/utils/request'
-
-// 查询定时任务调度列表
-export function listJob(query) {
- return request({
- url: '/schedule/job/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询定时任务调度详细
-export function getJob(jobId) {
- return request({
- url: '/schedule/job/' + jobId,
- method: 'get'
- })
-}
-
-// 新增定时任务调度
-export function addJob(data) {
- return request({
- url: '/schedule/job',
- method: 'post',
- data: data
- })
-}
-
-// 修改定时任务调度
-export function updateJob(data) {
- return request({
- url: '/schedule/job',
- method: 'put',
- data: data
- })
-}
-
-// 删除定时任务调度
-export function delJob(jobId) {
- return request({
- url: '/schedule/job/' + jobId,
- method: 'delete'
- })
-}
-
-// 任务状态修改
-export function changeJobStatus(jobId, status) {
- const data = {
- jobId,
- status
- }
- return request({
- url: '/schedule/job/changeStatus',
- method: 'put',
- data: data
- })
-}
-
-
-// 定时任务立即执行一次
-export function runJob(jobId, jobGroup) {
- const data = {
- jobId,
- jobGroup
- }
- return request({
- url: '/schedule/job/run',
- method: 'put',
- data: data
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/jobLog.js b/ruoyi-ui/src/api/monitor/jobLog.js
deleted file mode 100644
index 732cc05..0000000
--- a/ruoyi-ui/src/api/monitor/jobLog.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import request from '@/utils/request'
-
-// 查询调度日志列表
-export function listJobLog(query) {
- return request({
- url: '/schedule/job/log/list',
- method: 'get',
- params: query
- })
-}
-
-// 删除调度日志
-export function delJobLog(jobLogId) {
- return request({
- url: '/schedule/job/log/' + jobLogId,
- method: 'delete'
- })
-}
-
-// 清空调度日志
-export function cleanJobLog() {
- return request({
- url: '/schedule/job/log/clean',
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/monitor/online.js b/ruoyi-ui/src/api/monitor/online.js
deleted file mode 100644
index 228fe3b..0000000
--- a/ruoyi-ui/src/api/monitor/online.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import request from '@/utils/request'
-
-// 查询在线用户列表
-export function list(query) {
- return request({
- url: '/system/online/list',
- method: 'get',
- params: query
- })
-}
-
-// 强退用户
-export function forceLogout(tokenId) {
- return request({
- url: '/system/online/' + tokenId,
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/config.js b/ruoyi-ui/src/api/system/config.js
deleted file mode 100644
index 7858c69..0000000
--- a/ruoyi-ui/src/api/system/config.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import request from '@/utils/request'
-
-// 查询参数列表
-export function listConfig(query) {
- return request({
- url: '/system/config/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询参数详细
-export function getConfig(configId) {
- return request({
- url: '/system/config/' + configId,
- method: 'get'
- })
-}
-
-// 根据参数键名查询参数值
-export function getConfigKey(configKey) {
- return request({
- url: '/system/config/configKey/' + configKey,
- method: 'get'
- })
-}
-
-// 新增参数配置
-export function addConfig(data) {
- return request({
- url: '/system/config',
- method: 'post',
- data: data
- })
-}
-
-// 修改参数配置
-export function updateConfig(data) {
- return request({
- url: '/system/config',
- method: 'put',
- data: data
- })
-}
-
-// 删除参数配置
-export function delConfig(configId) {
- return request({
- url: '/system/config/' + configId,
- method: 'delete'
- })
-}
-
-// 刷新参数缓存
-export function refreshCache() {
- return request({
- url: '/system/config/refreshCache',
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/dept.js b/ruoyi-ui/src/api/system/dept.js
deleted file mode 100644
index b9ac75e..0000000
--- a/ruoyi-ui/src/api/system/dept.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import request from '@/utils/request'
-
-// 查询部门列表
-export function listDept(query) {
- return request({
- url: '/system/dept/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询部门列表(排除节点)
-export function listDeptExcludeChild(deptId) {
- return request({
- url: '/system/dept/list/exclude/' + deptId,
- method: 'get'
- })
-}
-
-// 查询部门详细
-export function getDept(deptId) {
- return request({
- url: '/system/dept/' + deptId,
- method: 'get'
- })
-}
-
-// 新增部门
-export function addDept(data) {
- return request({
- url: '/system/dept',
- method: 'post',
- data: data
- })
-}
-
-// 修改部门
-export function updateDept(data) {
- return request({
- url: '/system/dept',
- method: 'put',
- data: data
- })
-}
-
-// 保存部门排序
-export function updateDeptSort(data) {
- return request({
- url: '/system/dept/updateSort',
- method: 'put',
- data: data
- })
-}
-
-// 删除部门
-export function delDept(deptId) {
- return request({
- url: '/system/dept/' + deptId,
- method: 'delete'
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js
deleted file mode 100644
index 2a6e481..0000000
--- a/ruoyi-ui/src/api/system/dict/data.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import request from '@/utils/request'
-
-// 查询字典数据列表
-export function listData(query) {
- return request({
- url: '/system/dict/data/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询字典数据详细
-export function getData(dictCode) {
- return request({
- url: '/system/dict/data/' + dictCode,
- method: 'get'
- })
-}
-
-// 根据字典类型查询字典数据信息
-export function getDicts(dictType) {
- return request({
- url: '/system/dict/data/type/' + dictType,
- method: 'get'
- })
-}
-
-// 新增字典数据
-export function addData(data) {
- return request({
- url: '/system/dict/data',
- method: 'post',
- data: data
- })
-}
-
-// 修改字典数据
-export function updateData(data) {
- return request({
- url: '/system/dict/data',
- method: 'put',
- data: data
- })
-}
-
-// 删除字典数据
-export function delData(dictCode) {
- return request({
- url: '/system/dict/data/' + dictCode,
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/dict/type.js b/ruoyi-ui/src/api/system/dict/type.js
deleted file mode 100644
index 526977d..0000000
--- a/ruoyi-ui/src/api/system/dict/type.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import request from '@/utils/request'
-
-// 查询字典类型列表
-export function listType(query) {
- return request({
- url: '/system/dict/type/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询字典类型详细
-export function getType(dictId) {
- return request({
- url: '/system/dict/type/' + dictId,
- method: 'get'
- })
-}
-
-// 新增字典类型
-export function addType(data) {
- return request({
- url: '/system/dict/type',
- method: 'post',
- data: data
- })
-}
-
-// 修改字典类型
-export function updateType(data) {
- return request({
- url: '/system/dict/type',
- method: 'put',
- data: data
- })
-}
-
-// 删除字典类型
-export function delType(dictId) {
- return request({
- url: '/system/dict/type/' + dictId,
- method: 'delete'
- })
-}
-
-// 刷新字典缓存
-export function refreshCache() {
- return request({
- url: '/system/dict/type/refreshCache',
- method: 'delete'
- })
-}
-
-// 获取字典选择框列表
-export function optionselect() {
- return request({
- url: '/system/dict/type/optionselect',
- method: 'get'
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/logininfor.js b/ruoyi-ui/src/api/system/logininfor.js
deleted file mode 100644
index 755e6bc..0000000
--- a/ruoyi-ui/src/api/system/logininfor.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import request from '@/utils/request'
-
-// 查询登录日志列表
-export function list(query) {
- return request({
- url: '/system/logininfor/list',
- method: 'get',
- params: query
- })
-}
-
-// 删除登录日志
-export function delLogininfor(infoId) {
- return request({
- url: '/system/logininfor/' + infoId,
- method: 'delete'
- })
-}
-
-// 解锁用户登录状态
-export function unlockLogininfor(userName) {
- return request({
- url: '/system/logininfor/unlock/' + userName,
- method: 'get'
- })
-}
-// 清空登录日志
-export function cleanLogininfor() {
- return request({
- url: '/system/logininfor/clean',
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/menu.js b/ruoyi-ui/src/api/system/menu.js
deleted file mode 100644
index 2fdeb21..0000000
--- a/ruoyi-ui/src/api/system/menu.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import request from '@/utils/request'
-
-// 查询菜单列表
-export function listMenu(query) {
- return request({
- url: '/system/menu/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询菜单详细
-export function getMenu(menuId) {
- return request({
- url: '/system/menu/' + menuId,
- method: 'get'
- })
-}
-
-// 查询菜单下拉树结构
-export function treeselect() {
- return request({
- url: '/system/menu/treeselect',
- method: 'get'
- })
-}
-
-// 根据角色ID查询菜单下拉树结构
-export function roleMenuTreeselect(roleId) {
- return request({
- url: '/system/menu/roleMenuTreeselect/' + roleId,
- method: 'get'
- })
-}
-
-// 新增菜单
-export function addMenu(data) {
- return request({
- url: '/system/menu',
- method: 'post',
- data: data
- })
-}
-
-// 修改菜单
-export function updateMenu(data) {
- return request({
- url: '/system/menu',
- method: 'put',
- data: data
- })
-}
-
-// 保存菜单排序
-export function updateMenuSort(data) {
- return request({
- url: '/system/menu/updateSort',
- method: 'put',
- data: data
- })
-}
-
-// 删除菜单
-export function delMenu(menuId) {
- return request({
- url: '/system/menu/' + menuId,
- method: 'delete'
- })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/notice.js b/ruoyi-ui/src/api/system/notice.js
deleted file mode 100644
index 6f04807..0000000
--- a/ruoyi-ui/src/api/system/notice.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import request from '@/utils/request'
-
-// 查询公告列表
-export function listNotice(query) {
- return request({
- url: '/system/notice/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询公告详细
-export function getNotice(noticeId) {
- return request({
- url: '/system/notice/' + noticeId,
- method: 'get'
- })
-}
-
-// 新增公告
-export function addNotice(data) {
- return request({
- url: '/system/notice',
- method: 'post',
- data: data
- })
-}
-
-// 修改公告
-export function updateNotice(data) {
- return request({
- url: '/system/notice',
- method: 'put',
- data: data
- })
-}
-
-// 删除公告
-export function delNotice(noticeId) {
- return request({
- url: '/system/notice/' + noticeId,
- method: 'delete'
- })
-}
-
-// 首页顶部公告列表(带已读状态)
-export function listNoticeTop() {
- return request({
- url: '/system/notice/listTop',
- method: 'get'
- })
-}
-
-// 标记公告已读
-export function markNoticeRead(noticeId) {
- return request({
- url: '/system/notice/markRead',
- method: 'post',
- params: { noticeId }
- })
-}
-
-// 批量标记已读
-export function markNoticeReadAll(ids) {
- return request({
- url: '/system/notice/markReadAll',
- method: 'post',
- params: { ids }
- })
-}
-
-// 查询公告已读用户列表
-export function listNoticeReadUsers(query) {
- return request({
- url: '/system/notice/readUsers/list',
- method: 'get',
- params: query
- })
-}
diff --git a/ruoyi-ui/src/api/system/operlog.js b/ruoyi-ui/src/api/system/operlog.js
deleted file mode 100644
index 07a44b0..0000000
--- a/ruoyi-ui/src/api/system/operlog.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import request from '@/utils/request'
-
-// 查询操作日志列表
-export function list(query) {
- return request({
- url: '/system/operlog/list',
- method: 'get',
- params: query
- })
-}
-
-// 删除操作日志
-export function delOperlog(operId) {
- return request({
- url: '/system/operlog/' + operId,
- method: 'delete'
- })
-}
-
-// 清空操作日志
-export function cleanOperlog() {
- return request({
- url: '/system/operlog/clean',
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/post.js b/ruoyi-ui/src/api/system/post.js
deleted file mode 100644
index 8faa266..0000000
--- a/ruoyi-ui/src/api/system/post.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import request from '@/utils/request'
-
-// 查询岗位列表
-export function listPost(query) {
- return request({
- url: '/system/post/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询岗位详细
-export function getPost(postId) {
- return request({
- url: '/system/post/' + postId,
- method: 'get'
- })
-}
-
-// 新增岗位
-export function addPost(data) {
- return request({
- url: '/system/post',
- method: 'post',
- data: data
- })
-}
-
-// 修改岗位
-export function updatePost(data) {
- return request({
- url: '/system/post',
- method: 'put',
- data: data
- })
-}
-
-// 删除岗位
-export function delPost(postId) {
- return request({
- url: '/system/post/' + postId,
- method: 'delete'
- })
-}
diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js
deleted file mode 100644
index 528cd18..0000000
--- a/ruoyi-ui/src/api/system/role.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import request from '@/utils/request'
-
-// 查询角色列表
-export function listRole(query) {
- return request({
- url: '/system/role/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询角色详细
-export function getRole(roleId) {
- return request({
- url: '/system/role/' + roleId,
- method: 'get'
- })
-}
-
-// 新增角色
-export function addRole(data) {
- return request({
- url: '/system/role',
- method: 'post',
- data: data
- })
-}
-
-// 修改角色
-export function updateRole(data) {
- return request({
- url: '/system/role',
- method: 'put',
- data: data
- })
-}
-
-// 角色数据权限
-export function dataScope(data) {
- return request({
- url: '/system/role/dataScope',
- method: 'put',
- data: data
- })
-}
-
-// 角色状态修改
-export function changeRoleStatus(roleId, status) {
- const data = {
- roleId,
- status
- }
- return request({
- url: '/system/role/changeStatus',
- method: 'put',
- data: data
- })
-}
-
-// 删除角色
-export function delRole(roleId) {
- return request({
- url: '/system/role/' + roleId,
- method: 'delete'
- })
-}
-
-// 查询角色已授权用户列表
-export function allocatedUserList(query) {
- return request({
- url: '/system/role/authUser/allocatedList',
- method: 'get',
- params: query
- })
-}
-
-// 查询角色未授权用户列表
-export function unallocatedUserList(query) {
- return request({
- url: '/system/role/authUser/unallocatedList',
- method: 'get',
- params: query
- })
-}
-
-// 取消用户授权角色
-export function authUserCancel(data) {
- return request({
- url: '/system/role/authUser/cancel',
- method: 'put',
- data: data
- })
-}
-
-// 批量取消用户授权角色
-export function authUserCancelAll(data) {
- return request({
- url: '/system/role/authUser/cancelAll',
- method: 'put',
- params: data
- })
-}
-
-// 授权用户选择
-export function authUserSelectAll(data) {
- return request({
- url: '/system/role/authUser/selectAll',
- method: 'put',
- params: data
- })
-}
-
-// 根据角色ID查询部门树结构
-export function deptTreeSelect(roleId) {
- return request({
- url: '/system/role/deptTree/' + roleId,
- method: 'get'
- })
-}
diff --git a/ruoyi-ui/src/api/tool/gen.js b/ruoyi-ui/src/api/tool/gen.js
deleted file mode 100644
index a17f1f2..0000000
--- a/ruoyi-ui/src/api/tool/gen.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import request from '@/utils/request'
-
-// 查询生成表数据
-export function listTable(query) {
- return request({
- url: '/code/gen/list',
- method: 'get',
- params: query
- })
-}
-// 查询db数据库列表
-export function listDbTable(query) {
- return request({
- url: '/code/gen/db/list',
- method: 'get',
- params: query
- })
-}
-
-// 查询表详细信息
-export function getGenTable(tableId) {
- return request({
- url: '/code/gen/' + tableId,
- method: 'get'
- })
-}
-
-// 修改代码生成信息
-export function updateGenTable(data) {
- return request({
- url: '/code/gen',
- method: 'put',
- data: data
- })
-}
-
-// 导入表
-export function importTable(data) {
- return request({
- url: '/code/gen/importTable',
- method: 'post',
- params: data
- })
-}
-
-// 预览生成代码
-export function previewTable(tableId) {
- return request({
- url: '/code/gen/preview/' + tableId,
- method: 'get'
- })
-}
-
-// 删除表数据
-export function delTable(tableId) {
- return request({
- url: '/code/gen/' + tableId,
- method: 'delete'
- })
-}
-
-// 生成代码(自定义路径)
-export function genCode(tableName) {
- return request({
- url: '/code/gen/genCode/' + tableName,
- method: 'get'
- })
-}
-
-// 同步数据库
-export function synchDb(tableName) {
- return request({
- url: '/code/gen/synchDb/' + tableName,
- method: 'get'
- })
-}
diff --git a/ruoyi-ui/src/assets/icons/index.js b/ruoyi-ui/src/assets/icons/index.js
deleted file mode 100644
index d79e164..0000000
--- a/ruoyi-ui/src/assets/icons/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import Vue from 'vue'
-import SvgIcon from '@/components/SvgIcon'// svg component
-
-// register globally
-Vue.component('svg-icon', SvgIcon)
-
-const req = require.context('./svg', false, /\.svg$/)
-const requireAll = requireContext => requireContext.keys().map(requireContext)
-requireAll(req)
diff --git a/ruoyi-ui/src/assets/icons/svg/monitor.svg b/ruoyi-ui/src/assets/icons/svg/monitor.svg
deleted file mode 100644
index 70db62b..0000000
--- a/ruoyi-ui/src/assets/icons/svg/monitor.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
-</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/system.svg b/ruoyi-ui/src/assets/icons/svg/system.svg
deleted file mode 100644
index 76d41ba..0000000
--- a/ruoyi-ui/src/assets/icons/svg/system.svg
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827724451" class="icon" style="" viewBox="0 0 1084 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10233" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
-</style></defs><path d="M1080.09609 434.500756c-4.216302-23.731757-26.9241-47.945376-50.595623-53.185637l-17.648235-4.095836a175.940257 175.940257 0 0 1-101.612877-80.832531 177.807476 177.807476 0 0 1-18.732427-129.801867l5.541425-16.684509c7.10748-23.129428-2.108151-54.992624-20.599646-70.833873 0 0-16.624276-14.094495-63.244529-41.199293-46.800951-26.984332-66.858502-34.513443-66.858502-34.513443-22.76803-8.372371-54.631227-0.361397-71.255503 17.407304l-12.287509 13.251234a173.470708 173.470708 0 0 1-120.465769 48.065842A174.13327 174.13327 0 0 1 421.329029 33.590675L409.583617 20.761071C393.140039 2.99237 361.096144-4.898138 338.267881 3.353767c0 0-20.358715 7.529111-67.099434 34.513443-46.800951 27.34573-63.244529 41.440225-63.244529 41.440225-18.431263 15.66055-27.646894 47.222582-20.539413 70.592941l5.059562 16.865207a178.048407 178.048407 0 0 1-18.672194 129.621169 174.916297 174.916297 0 0 1-102.275439 81.073463l-17.045906 3.854904c-23.310126 5.42096-46.258856 29.333415-50.595623 53.185637 0 0-3.854905 21.382674-3.854905 75.712737 0 54.330062 3.854905 75.712736 3.854905 75.712736 4.216302 23.972688 26.9241 47.945376 50.595623 53.185637l16.624276 3.854905a174.253736 174.253736 0 0 1 102.395904 81.314394c23.310126 40.837896 28.911785 87.337683 18.732427 129.801867l-4.81863 16.443578c-7.10748 23.129428 2.108151 54.992624 20.599646 70.833872 0 0 16.624276 14.094495 63.244529 41.199293 46.800951 27.104798 66.918735 34.513443 66.918735 34.513443 22.707798 8.372371 54.631227 0.361397 71.255503-17.407303l11.624947-12.588673a175.096996 175.096996 0 0 1 242.256662 0.120465l11.624947 12.648906c16.383345 17.708468 48.427239 25.598976 71.255503 17.347071 0 0 20.358715-7.529111 67.159666-34.513443 46.740719-27.104798 63.124063-41.199293 63.124064-41.199293 18.491496-15.600317 27.707127-47.463513 20.599646-70.833873l-5.059562-17.106139a176.723284 176.723284 0 0 1 18.672194-129.139305 176.060722 176.060722 0 0 1 102.395904-81.314394l16.68451-3.854905c23.310126-5.42096 46.258856-29.333415 50.595623-53.185637 0 0 3.854905-21.382674 3.854904-75.712737-0.240932-54.330062-4.095836-75.833202-4.095836-75.833202z m-537.819428 293.334149c-119.261112 0-216.175824-97.336342-216.175824-217.621412a216.657687 216.657687 0 0 1 216.236057-217.320249c119.200879 0 216.115591 97.276109 216.11559 217.56118-0.240932 120.044139-96.974945 217.320248-216.175823 217.320249z" p-id="10234"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svgo.yml b/ruoyi-ui/src/assets/icons/svgo.yml
deleted file mode 100644
index 14f8f5c..0000000
--- a/ruoyi-ui/src/assets/icons/svgo.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-# replace default config
-
-# multipass: true
-# full: true
-
-plugins:
-
- # - name
- #
- # or:
- # - name: false
- # - name: true
- #
- # or:
- # - name:
- # param1: 1
- # param2: 2
-
-- removeAttrs:
- attrs:
- - 'fill'
- - 'fill-rule'
diff --git a/ruoyi-ui/src/assets/images/dark.svg b/ruoyi-ui/src/assets/images/dark.svg
deleted file mode 100644
index 36b58b5..0000000
--- a/ruoyi-ui/src/assets/images/dark.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
- <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
- <feMerge>
- <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
- <feMergeNode in="SourceGraphic"></feMergeNode>
- </feMerge>
- </filter>
- <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
- <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
- <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
- </filter>
- </defs>
- <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
- <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
- <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
- <mask id="mask-3" fill="white">
- <use xlink:href="#path-2"></use>
- </mask>
- <g id="Rectangle-18">
- <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
- <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
- </g>
- <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
- <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
- </g>
- </g>
- </g>
- </g>
-</svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/images/light.svg b/ruoyi-ui/src/assets/images/light.svg
deleted file mode 100644
index efd52c6..0000000
--- a/ruoyi-ui/src/assets/images/light.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
- <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
- <feMerge>
- <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
- <feMergeNode in="SourceGraphic"></feMergeNode>
- </feMerge>
- </filter>
- <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
- <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
- <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
- </filter>
- </defs>
- <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
- <g id="Group-8" transform="translate(1167.000000, 0.000000)">
- <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
- <mask id="mask-3" fill="white">
- <use xlink:href="#path-2"></use>
- </mask>
- <g id="Rectangle-18">
- <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
- <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
- </g>
- <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
- <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
- </g>
- </g>
- </g>
- </g>
-</svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/btn.scss b/ruoyi-ui/src/assets/styles/btn.scss
deleted file mode 100644
index 1ccb57d..0000000
--- a/ruoyi-ui/src/assets/styles/btn.scss
+++ /dev/null
@@ -1,99 +0,0 @@
-@import './variables.scss';
-
-@mixin colorBtn($color) {
- background: $color;
-
- &:hover {
- color: $color;
-
- &:before,
- &:after {
- background: $color;
- }
- }
-}
-
-.blue-btn {
- @include colorBtn($blue)
-}
-
-.light-blue-btn {
- @include colorBtn($light-blue)
-}
-
-.red-btn {
- @include colorBtn($red)
-}
-
-.pink-btn {
- @include colorBtn($pink)
-}
-
-.green-btn {
- @include colorBtn($green)
-}
-
-.tiffany-btn {
- @include colorBtn($tiffany)
-}
-
-.yellow-btn {
- @include colorBtn($yellow)
-}
-
-.pan-btn {
- font-size: 14px;
- color: #fff;
- padding: 14px 36px;
- border-radius: 8px;
- border: none;
- outline: none;
- transition: 600ms ease all;
- position: relative;
- display: inline-block;
-
- &:hover {
- background: #fff;
-
- &:before,
- &:after {
- width: 100%;
- transition: 600ms ease all;
- }
- }
-
- &:before,
- &:after {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- height: 2px;
- width: 0;
- transition: 400ms ease all;
- }
-
- &::after {
- right: inherit;
- top: inherit;
- left: 0;
- bottom: 0;
- }
-}
-
-.custom-button {
- display: inline-block;
- line-height: 1;
- white-space: nowrap;
- cursor: pointer;
- background: #fff;
- color: #fff;
- -webkit-appearance: none;
- text-align: center;
- box-sizing: border-box;
- outline: 0;
- margin: 0;
- padding: 10px 15px;
- font-size: 14px;
- border-radius: 4px;
-}
diff --git a/ruoyi-ui/src/assets/styles/element-ui.scss b/ruoyi-ui/src/assets/styles/element-ui.scss
deleted file mode 100644
index 9ff2c87..0000000
--- a/ruoyi-ui/src/assets/styles/element-ui.scss
+++ /dev/null
@@ -1,92 +0,0 @@
-// cover some element-ui styles
-
-.el-breadcrumb__inner,
-.el-breadcrumb__inner a {
- font-weight: 400 !important;
-}
-
-.el-upload {
- input[type="file"] {
- display: none !important;
- }
-}
-
-.el-upload__input {
- display: none;
-}
-
-.cell {
- .el-tag {
- margin-right: 0px;
- }
-}
-
-.small-padding {
- .cell {
- padding-left: 5px;
- padding-right: 5px;
- }
-}
-
-.fixed-width {
- .el-button--mini {
- padding: 7px 10px;
- width: 60px;
- }
-}
-
-.status-col {
- .cell {
- padding: 0 10px;
- text-align: center;
-
- .el-tag {
- margin-right: 0px;
- }
- }
-}
-
-// to fixed https://github.com/ElemeFE/element/issues/2461
-.el-dialog {
- transform: none;
- left: 0;
- position: relative;
- margin: 0 auto;
-}
-
-// refine element ui upload
-.upload-container {
- .el-upload {
- width: 100%;
-
- .el-upload-dragger {
- width: 100%;
- height: 200px;
- }
- }
-}
-
-// dropdown
-.el-dropdown-menu {
- a {
- display: block
- }
-}
-
-// fix date-picker ui bug in filter-item
-.el-range-editor.el-input__inner {
- display: inline-flex !important;
-}
-
-// to fix el-date-picker css style
-.el-range-separator {
- box-sizing: content-box;
-}
-
-.el-menu--collapse
- > div
- > .el-submenu
- > .el-submenu__title
- .el-submenu__icon-arrow {
- display: none;
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/element-variables.scss b/ruoyi-ui/src/assets/styles/element-variables.scss
deleted file mode 100644
index 5bf2fbb..0000000
--- a/ruoyi-ui/src/assets/styles/element-variables.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
-* I think element-ui's default theme color is too light for long-term use.
-* So I modified the default color and you can modify it to your liking.
-**/
-
-/* theme color */
-$--color-primary: #1890ff;
-$--color-success: #13ce66;
-$--color-warning: #ffba00;
-$--color-danger: #ff4949;
-// $--color-info: #1E1E1E;
-
-$--button-font-weight: 400;
-
-// $--color-text-regular: #1f2d3d;
-
-$--border-color-light: #dfe4ed;
-$--border-color-lighter: #e6ebf5;
-
-$--table-border: 1px solid #dfe6ec;
-
-/* icon font path, required */
-$--font-path: '~element-ui/lib/theme-chalk/fonts';
-
-@import "~element-ui/packages/theme-chalk/src/index";
-
-// the :export directive is the magic sauce for webpack
-// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
-:export {
- theme: $--color-primary;
-}
diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss
deleted file mode 100644
index e3e5e0b..0000000
--- a/ruoyi-ui/src/assets/styles/index.scss
+++ /dev/null
@@ -1,178 +0,0 @@
-@import './variables.scss';
-@import './mixin.scss';
-@import './transition.scss';
-@import './element-ui.scss';
-@import './sidebar.scss';
-@import './btn.scss';
-
-body {
- height: 100%;
- -moz-osx-font-smoothing: grayscale;
- -webkit-font-smoothing: antialiased;
- text-rendering: optimizeLegibility;
- font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
-}
-
-label {
- font-weight: 700;
-}
-
-html {
- height: 100%;
- box-sizing: border-box;
-}
-
-#app {
- height: 100%;
-}
-
-*,
-*:before,
-*:after {
- box-sizing: inherit;
-}
-
-.no-padding {
- padding: 0px !important;
-}
-
-.padding-content {
- padding: 4px 0;
-}
-
-a:focus,
-a:active {
- outline: none;
-}
-
-a,
-a:focus,
-a:hover {
- cursor: pointer;
- color: inherit;
- text-decoration: none;
-}
-
-div:focus {
- outline: none;
-}
-
-.fr {
- float: right;
-}
-
-.fl {
- float: left;
-}
-
-.pr-5 {
- padding-right: 5px;
-}
-
-.pl-5 {
- padding-left: 5px;
-}
-
-.block {
- display: block;
-}
-
-.pointer {
- cursor: pointer;
-}
-
-.inlineBlock {
- display: block;
-}
-
-.clearfix {
- &:after {
- visibility: hidden;
- display: block;
- font-size: 0;
- content: " ";
- clear: both;
- height: 0;
- }
-}
-
-aside {
- background: #eef1f6;
- padding: 8px 24px;
- margin-bottom: 20px;
- border-radius: 2px;
- display: block;
- line-height: 32px;
- font-size: 16px;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
- color: #2c3e50;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-
- a {
- color: #337ab7;
- cursor: pointer;
-
- &:hover {
- color: rgb(32, 160, 255);
- }
- }
-}
-
-//main-container全局样式
-.app-container {
- padding: 20px;
-}
-
-.components-container {
- margin: 30px 50px;
- position: relative;
-}
-
-.text-center {
- text-align: center
-}
-
-.sub-navbar {
- height: 50px;
- line-height: 50px;
- position: relative;
- width: 100%;
- text-align: right;
- padding-right: 20px;
- transition: 600ms ease position;
- background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
-
- .subtitle {
- font-size: 20px;
- color: #fff;
- }
-
- &.draft {
- background: #d0d0d0;
- }
-
- &.deleted {
- background: #d0d0d0;
- }
-}
-
-.link-type,
-.link-type:focus {
- color: #337ab7;
- cursor: pointer;
-
- &:hover {
- color: rgb(32, 160, 255);
- }
-}
-
-.filter-container {
- padding-bottom: 10px;
-
- .filter-item {
- display: inline-block;
- vertical-align: middle;
- margin-bottom: 10px;
- }
-}
diff --git a/ruoyi-ui/src/assets/styles/mixin.scss b/ruoyi-ui/src/assets/styles/mixin.scss
deleted file mode 100644
index 64d9cf6..0000000
--- a/ruoyi-ui/src/assets/styles/mixin.scss
+++ /dev/null
@@ -1,66 +0,0 @@
-@mixin clearfix {
- &:after {
- content: "";
- display: table;
- clear: both;
- }
-}
-
-@mixin scrollBar {
- &::-webkit-scrollbar-track-piece {
- background: #d3dce6;
- }
-
- &::-webkit-scrollbar {
- width: 6px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: #99a9bf;
- border-radius: 20px;
- }
-}
-
-@mixin relative {
- position: relative;
- width: 100%;
- height: 100%;
-}
-
-@mixin pct($pct) {
- width: #{$pct};
- position: relative;
- margin: 0 auto;
-}
-
-@mixin triangle($width, $height, $color, $direction) {
- $width: $width/2;
- $color-border-style: $height solid $color;
- $transparent-border-style: $width solid transparent;
- height: 0;
- width: 0;
-
- @if $direction==up {
- border-bottom: $color-border-style;
- border-left: $transparent-border-style;
- border-right: $transparent-border-style;
- }
-
- @else if $direction==right {
- border-left: $color-border-style;
- border-top: $transparent-border-style;
- border-bottom: $transparent-border-style;
- }
-
- @else if $direction==down {
- border-top: $color-border-style;
- border-left: $transparent-border-style;
- border-right: $transparent-border-style;
- }
-
- @else if $direction==left {
- border-right: $color-border-style;
- border-top: $transparent-border-style;
- border-bottom: $transparent-border-style;
- }
-}
diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss
deleted file mode 100644
index 0ea78b4..0000000
--- a/ruoyi-ui/src/assets/styles/ruoyi.scss
+++ /dev/null
@@ -1,484 +0,0 @@
-/**
-* 通用css样式布局处理
-* Copyright (c) 2019 ruoyi
-*/
-
-/** 基础通用 **/
-.pt5 {
- padding-top: 5px;
-}
-
-.pr5 {
- padding-right: 5px;
-}
-
-.pb5 {
- padding-bottom: 5px;
-}
-
-.mt5 {
- margin-top: 5px;
-}
-
-.mr5 {
- margin-right: 5px;
-}
-
-.mb5 {
- margin-bottom: 5px;
-}
-
-.mb8 {
- margin-bottom: 8px;
-}
-
-.ml5 {
- margin-left: 5px;
-}
-
-.mt10 {
- margin-top: 10px;
-}
-
-.mr10 {
- margin-right: 10px;
-}
-
-.mb10 {
- margin-bottom: 10px;
-}
-.ml10 {
- margin-left: 10px;
-}
-
-.mt20 {
- margin-top: 20px;
-}
-
-.mr20 {
- margin-right: 20px;
-}
-
-.mb20 {
- margin-bottom: 20px;
-}
-.ml20 {
- margin-left: 20px;
-}
-
-.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
- font-family: inherit;
- font-weight: 500;
- line-height: 1.1;
- color: inherit;
-}
-
-.el-message-box__status + .el-message-box__message{
- word-break: break-word;
-}
-
-.el-dialog:not(.is-fullscreen) {
- margin-top: 6vh !important;
-}
-
-.el-dialog__body {
- padding: 8px 20px !important;
-}
-
-.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
- overflow: auto;
- overflow-x: hidden;
- max-height: 70vh;
- padding: 10px 20px 0;
-}
-
-.el-table {
- .el-table__header-wrapper, .el-table__fixed-header-wrapper {
- th {
- word-break: break-word;
- background-color: #f8f8f9;
- color: #515a6e;
- height: 40px;
- font-size: 13px;
- }
- }
-
- .el-table__body-wrapper {
- .el-button [class*="el-icon-"] + span {
- margin-left: 1px;
- }
- }
-}
-
-/** 表单布局 **/
-.form-header {
- font-size: 15px;
- color: #6379bb;
- border-bottom: 1px solid #ddd;
- margin: 8px 10px 25px 10px;
- padding-bottom: 5px
-}
-
-/** 表格布局 **/
-.pagination-container {
- display: flex;
- justify-content: flex-end;
- margin-top: 20px;
-}
-
-/* tree border */
-.tree-border {
- margin-top: 5px;
- border: 1px solid #e5e6e7;
- background: #FFFFFF none;
- border-radius: 4px;
-}
-
-/* horizontal el menu */
-.el-menu--horizontal .el-menu-item .svg-icon + span,
-.el-menu--horizontal .el-submenu__title .svg-icon + span {
- margin-left: 3px;
-}
-
-.el-menu--horizontal .el-menu--popup {
- min-width: 120px !important;
-}
-
-@media (max-width: 768px) {
- .pagination-container .el-pagination > .el-pagination__jump {
- display: none !important;
- }
- .pagination-container .el-pagination > .el-pagination__sizes {
- display: none !important;
- }
-}
-
-.el-table .fixed-width .el-button--mini {
- padding-left: 0;
- padding-right: 0;
- width: inherit;
-}
-
-/** 表格更多操作下拉样式 */
-.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
- cursor: pointer;
- margin-left: 5px;
-}
-
-.el-table .el-dropdown, .el-icon-arrow-down {
- font-size: 12px;
-}
-
-.el-tree-node__content > .el-checkbox {
- margin-right: 8px;
-}
-
-.list-group-striped > .list-group-item {
- border-left: 0;
- border-right: 0;
- border-radius: 0;
- padding-left: 0;
- padding-right: 0;
-}
-
-.list-group {
- padding-left: 0px;
- list-style: none;
-}
-
-.list-group-item {
- border-bottom: 1px solid #e7eaec;
- border-top: 1px solid #e7eaec;
- margin-bottom: -1px;
- padding: 11px 0px;
- font-size: 13px;
-}
-
-.pull-right {
- float: right !important;
-}
-
-.el-card__header {
- padding: 14px 15px 7px;
- min-height: 40px;
-}
-
-.el-card__body {
- padding: 15px 20px 20px 20px;
-}
-
-.card-box {
- margin-bottom: 10px;
-}
-
-/* button color */
-.el-button--cyan.is-active,
-.el-button--cyan:active {
- background: #20B2AA;
- border-color: #20B2AA;
- color: #FFFFFF;
-}
-
-.el-button--cyan:focus,
-.el-button--cyan:hover {
- background: #48D1CC;
- border-color: #48D1CC;
- color: #FFFFFF;
-}
-
-.el-button--cyan {
- background-color: #20B2AA;
- border-color: #20B2AA;
- color: #FFFFFF;
-}
-
-/** 详细卡片样式 */
-.detail-drawer {
- .el-drawer__header {
- margin-bottom: 6px;
- padding: 8px 12px 6px;
- font-size: 15px;
- color: #303133;
- background: #f8f8f8;
- }
- .section-header {
- font-size: 15px;
- color: #6379bb;
- border-bottom: 1px solid #ddd;
- margin: 12px 0 16px 0;
- padding-bottom: 8px;
- }
- .drawer-content {
- padding: 0 20px 20px 20px;
- .info-item {
- display: flex;
- align-items: flex-start;
- padding: 8px 0;
- min-height: 40px;
- }
- .info-label {
- flex-shrink: 0;
- width: 200px;
- color: #606266;
- font-size: 13px;
- line-height: 1.6;
- padding-top: 4px;
- text-align: right;
- margin-right: 14px;
- }
- .info-value {
- flex: 1;
- color: #303133;
- font-size: 13px;
- font-weight: 500;
- line-height: 1.6;
- word-break: break-all;
- padding-top: 4px;
- min-height: 1.6em;
- &.plaintext {
- border-bottom: 1px dashed #dde1e6;
- }
- }
- }
-}
-
-.detail-wrap { padding: 0 4px; }
-
-.detail-card {
- border: 1px solid #ebeef5;
- border-radius: 6px;
- margin-bottom: 14px;
- overflow: hidden;
-}
-
-.detail-card-title {
- background: #f7f9fb;
- padding: 8px 16px;
- font-size: 13px;
- font-weight: 600;
- color: #333;
- border-bottom: 1px solid #ebeef5;
-}
-.detail-card-title i { margin-right: 5px; color: #409EFF; }
-
-.detail-row { padding: 0 8px; }
-
-.detail-item {
- display: flex;
- align-items: flex-start;
- padding: 10px 8px;
- font-size: 13px;
- border-bottom: 1px solid #f5f7fa;
-}
-.detail-item:last-child { border-bottom: none; }
-
-.detail-label {
- flex-shrink: 0;
- width: 72px;
- color: #909399;
- margin-right: 12px;
-}
-.detail-value { color: #303133; flex: 1; word-break: break-all; }
-.detail-location { color: #999; font-size: 12px; }
-
-.method-tag {
- display: inline-block;
- padding: 1px 7px;
- border-radius: 3px;
- font-size: 11px;
- font-weight: 700;
- margin-right: 6px;
- vertical-align: middle;
-}
-.mono { font-family: Consolas, 'SFMono-Regular', monospace; font-size: 12px; }
-.code-body { padding: 14px; }
-.code-wrap {
- background: #f7f9fb;
- border: 1px solid #e8ecf0;
- border-radius: 4px;
- overflow: hidden;
- max-height: 260px;
- position: relative;
-}
-.code-action {
- position: absolute;
- top: 8px;
- right: 8px;
- z-index: 10;
- margin: 0;
- padding: 0;
-}
-.code-action .el-button {
- height: 24px;
- font-size: 12px;
- padding: 4px 8px;
- background: rgba(255, 255, 255, 0.9);
- border: 1px solid #dcdcdc;
-}
-.code-action .el-button:hover {
- background: #ffffff;
- border-color: #409EFF;
-}
-.code-pre {
- margin: 0;
- padding: 12px 14px;
- font-size: 12px;
- line-height: 1.6;
- font-family: Consolas, 'SFMono-Regular', monospace;
- color: #444;
- white-space: pre-wrap;
- word-break: break-all;
- overflow: auto;
- max-height: 240px;
- display: block;
-}
-
-/* tree-sidebar content */
-.tree-sidebar-manage-wrap {
- display: flex;
- gap: 0;
- min-height: calc(100vh - 130px);
- padding: 0 !important;
- overflow: hidden;
-}
-
-.tree-sidebar-content {
- flex: 1;
- min-width: 0;
- overflow: hidden;
- background: #fff;
-
- .content-inner {
- padding: 12px 16px;
- height: 100%;
- overflow-y: auto;
- }
-}
-
-/* error */
-.error-title { color: #c0392b !important; }
-.error-title i { color: #c0392b !important; }
-.error-body { padding: 12px 16px; }
-.error-msg {
- background: #fff8f8;
- border-left: 3px solid #e74c3c;
- border-radius: 3px;
- padding: 8px 12px;
- color: #c0392b;
- font-size: 12px;
- line-height: 1.7;
- word-break: break-all;
- white-space: pre-wrap;
-}
-
-/* http method */
-.method-GET { background: #e8f5e9; color: #27ae60; }
-.method-POST { background: #e3f2fd; color: #1565c0; }
-.method-PUT { background: #fff3e0; color: #e65100; }
-.method-DELETE { background: #ffebee; color: #c62828; }
-
-/* text color */
-.text-navy {
- color: #1ab394;
-}
-
-.text-primary {
- color: inherit;
-}
-
-.text-success {
- color: #1c84c6;
-}
-
-.text-info {
- color: #23c6c8;
-}
-
-.text-warning {
- color: #f8ac59;
-}
-
-.text-danger {
- color: #ed5565;
-}
-
-.text-muted {
- color: #888888;
-}
-
-/* image */
-.img-circle {
- border-radius: 50%;
-}
-
-.img-lg {
- width: 120px;
- height: 120px;
-}
-
-.avatar-upload-preview {
- position: relative;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 200px;
- height: 200px;
- border-radius: 50%;
- box-shadow: 0 0 4px #ccc;
- overflow: hidden;
-}
-
-/* 拖拽列样式 */
-.allowDrag { cursor: grab; }
-.allowDrag:active { cursor: grabbing; }
-
-.sortable-ghost {
- opacity: .8;
- color: #fff !important;
- background: #42b983 !important;
-}
-
-.top-right-btn {
- position: relative;
- float: right;
-}
diff --git a/ruoyi-ui/src/assets/styles/sidebar.scss b/ruoyi-ui/src/assets/styles/sidebar.scss
deleted file mode 100644
index 6c4f47d..0000000
--- a/ruoyi-ui/src/assets/styles/sidebar.scss
+++ /dev/null
@@ -1,321 +0,0 @@
-#app {
-
- .main-container {
- height: 100%;
- transition: margin-left .28s;
- margin-left: $base-sidebar-width;
- position: relative;
- }
-
- .sidebarHide {
- margin-left: 0!important;
- }
-
- .sidebar-container {
- -webkit-transition: width .28s;
- transition: width 0.28s;
- width: $base-sidebar-width !important;
- background-color: $base-menu-background;
- height: 100%;
- position: fixed;
- font-size: 0px;
- top: 0;
- bottom: 0;
- left: 0;
- z-index: 1001;
- overflow: hidden;
- -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
- box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
-
- // reset element-ui css
- .horizontal-collapse-transition {
- transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
- }
-
- .scrollbar-wrapper {
- overflow-x: hidden !important;
- }
-
- .el-scrollbar__bar.is-vertical {
- right: 0px;
- }
-
- .el-scrollbar {
- height: 100%;
- }
-
- &.has-logo {
- .el-scrollbar {
- height: calc(100% - 50px);
- }
- }
-
- .is-horizontal {
- display: none;
- }
-
- a {
- display: inline-block;
- width: 100%;
- overflow: hidden;
- }
-
- .svg-icon {
- margin-right: 10px !important;
- }
-
- .el-menu {
- border: none;
- height: 100%;
- width: 100% !important;
- }
-
- .el-menu-item, .el-submenu__title {
- overflow: hidden !important;
- text-overflow: ellipsis !important;
- white-space: nowrap !important;
- height: 44px !important;
- line-height: 44px !important;
- }
-
- // menu hover
- .submenu-title-noDropdown,
- .el-submenu__title {
- &:hover {
- background-color: rgba(0, 0, 0, 0.06) !important;
- }
- }
-
- & .theme-dark .is-active > .el-submenu__title {
- color: $base-menu-color-active !important;
- }
-
- & .nest-menu .el-submenu>.el-submenu__title,
- & .el-submenu .el-menu-item {
- min-width: $base-sidebar-width !important;
-
- &:hover {
- background-color: rgba(0, 0, 0, 0.06) !important;
- }
- }
-
- & .theme-dark .nest-menu .el-submenu>.el-submenu__title,
- & .theme-dark .el-submenu .el-menu-item {
- background-color: $base-sub-menu-background !important;
-
- &:hover {
- background-color: $base-sub-menu-hover !important;
- }
- }
-
- // theme-dark 深色主题
- &.theme-dark {
- box-shadow: 2px 0 8px rgba(0, 0, 0, 0.4);
- border-right: none;
-
- .el-menu-item.is-active {
- position: relative;
-
- &::before {
- content: '';
- position: absolute;
- inset: 0;
- background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
- border-right: 3px solid var(--current-color, #409eff);
- pointer-events: none;
- z-index: 1;
- }
- }
-
- .el-submenu.is-active > .el-submenu__title {
- color: var(--current-color, #409eff) !important;
- }
-
- .el-menu-item:not(.is-active),
- .submenu-title-noDropdown,
- .el-submenu__title {
- position: relative;
-
- &::before {
- content: '';
- position: absolute;
- inset: 0;
- background-color: transparent;
- pointer-events: none;
- z-index: 1;
- transition: background-color 0.2s;
- }
-
- &:hover::before {
- background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
- }
- }
- }
-
- // theme-light 浅色主题
- &.theme-light {
- border-right: 1px solid #e8eaf0;
- box-shadow: none;
-
- .el-menu-item,
- .el-submenu__title {
- color: rgba(0, 0, 0, 0.65);
- }
-
- .el-menu-item.is-active {
- color: var(--current-color, #409eff) !important;
- position: relative;
-
- &::before {
- content: '';
- position: absolute;
- inset: 0;
- background-color: var(--current-color-light, #ecf5ff);
- border-right: 3px solid var(--current-color, #409eff);
- pointer-events: none;
- z-index: 1;
- }
- }
-
- .el-submenu.is-active > .el-submenu__title {
- color: var(--current-color, #409eff) !important;
- }
-
- .el-menu-item:not(.is-active):hover,
- .submenu-title-noDropdown:hover,
- .el-submenu__title:hover {
- background-color: #f5f7fa !important;
- color: rgba(0, 0, 0, 0.85) !important;
- }
-
- .nest-menu .el-submenu > .el-submenu__title,
- .el-submenu .el-menu-item {
- background-color: #fafafa !important;
-
- &:hover {
- background-color: #f0f5ff !important;
- }
- }
- }
- }
-
- .hideSidebar {
- .sidebar-container {
- width: 54px !important;
- }
-
- .main-container {
- margin-left: 54px;
- }
-
- .el-menu:not(.el-menu--horizontal) {
- .submenu-title-noDropdown {
- padding: 0 !important;
- position: relative;
-
- .el-tooltip {
- padding: 0 !important;
-
- .svg-icon {
- margin-left: 20px;
- }
- }
- }
- }
-
- .el-submenu {
- overflow: hidden;
-
- &>.el-submenu__title {
- padding: 0 !important;
-
- .svg-icon {
- margin-left: 20px;
- }
-
- }
- }
-
- .el-menu--collapse {
- .el-submenu {
- &>.el-submenu__title {
- &>span {
- height: 0;
- width: 0;
- overflow: hidden;
- visibility: hidden;
- display: inline-block;
- }
- }
- }
- }
- }
-
- .el-menu--collapse .el-menu .el-submenu {
- min-width: $base-sidebar-width !important;
- }
-
- // mobile responsive
- .mobile {
- .main-container {
- margin-left: 0px;
- }
-
- .sidebar-container {
- transition: transform .28s;
- width: $base-sidebar-width !important;
- }
-
- &.hideSidebar {
- .sidebar-container {
- pointer-events: none;
- transition-duration: 0.3s;
- transform: translate3d(-$base-sidebar-width, 0, 0);
- }
- }
- }
-
- .withoutAnimation {
-
- .main-container,
- .sidebar-container {
- transition: none;
- }
- }
-}
-
-// when menu collapsed
-.el-menu--vertical {
- &>.el-menu {
- .svg-icon {
- margin-right: 16px;
- }
- }
-
- .nest-menu .el-submenu>.el-submenu__title,
- .el-menu-item {
- &:hover {
- // you can use $subMenuHover
- background-color: rgba(0, 0, 0, 0.06) !important;
- }
- }
-
- // the scroll bar appears when the subMenu is too long
- >.el-menu--popup {
- max-height: 100vh;
- overflow-y: auto;
-
- &::-webkit-scrollbar-track-piece {
- background: #d3dce6;
- }
-
- &::-webkit-scrollbar {
- width: 6px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: #99a9bf;
- border-radius: 20px;
- }
- }
-}
diff --git a/ruoyi-ui/src/assets/styles/transition.scss b/ruoyi-ui/src/assets/styles/transition.scss
deleted file mode 100644
index 7e1b103..0000000
--- a/ruoyi-ui/src/assets/styles/transition.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-// global transition css
-
-/* fade */
-.fade-enter-active,
-.fade-leave-active {
- transition: opacity 0.28s;
-}
-
-.fade-enter,
-.fade-leave-active {
- opacity: 0;
-}
-
-/* fade-transform */
-.fade-transform--move,
-.fade-transform-leave-active,
-.fade-transform-enter-active {
- transition: all .5s;
-}
-
-.fade-transform-enter {
- opacity: 0;
- transform: translateX(-30px);
-}
-
-.fade-transform-leave-to {
- opacity: 0;
- transform: translateX(30px);
-}
-
-/* breadcrumb transition */
-.breadcrumb-enter-active,
-.breadcrumb-leave-active {
- transition: all .5s;
-}
-
-.breadcrumb-enter,
-.breadcrumb-leave-active {
- opacity: 0;
- transform: translateX(20px);
-}
-
-.breadcrumb-move {
- transition: all .5s;
-}
-
-.breadcrumb-leave-active {
- position: absolute;
-}
diff --git a/ruoyi-ui/src/assets/styles/variables.scss b/ruoyi-ui/src/assets/styles/variables.scss
deleted file mode 100644
index 6292006..0000000
--- a/ruoyi-ui/src/assets/styles/variables.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-// base color
-$blue:#324157;
-$light-blue:#3A71A8;
-$red:#C03639;
-$pink: #E65D6E;
-$green: #30B08F;
-$tiffany: #4AB7BD;
-$yellow:#FEC171;
-$panGreen: #30B08F;
-
-// 默认菜单主题风格
-$base-menu-color: #bfcbd9;
-$base-menu-color-active: #ffffff;
-$base-menu-background: #1a1f2e;
-$base-logo-title-color: #ffffff;
-
-$base-menu-light-color:rgba(0,0,0,.70);
-$base-menu-light-background:#ffffff;
-$base-logo-light-title-color: #001529;
-
-$base-sub-menu-background: #141824;
-$base-sub-menu-hover: rgba(255,255,255,.06);
-
-$base-sidebar-width: 200px;
-
-// the :export directive is the magic sauce for webpack
-// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
-:export {
- menuColor: $base-menu-color;
- menuLightColor: $base-menu-light-color;
- menuColorActive: $base-menu-color-active;
- menuBackground: $base-menu-background;
- menuLightBackground: $base-menu-light-background;
- subMenuBackground: $base-sub-menu-background;
- subMenuHover: $base-sub-menu-hover;
- sideBarWidth: $base-sidebar-width;
- logoTitleColor: $base-logo-title-color;
- logoLightTitleColor: $base-logo-light-title-color
-}
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
deleted file mode 100644
index 6b56f51..0000000
--- a/ruoyi-ui/src/components/Breadcrumb/index.vue
+++ /dev/null
@@ -1,102 +0,0 @@
-<template>
- <el-breadcrumb class="app-breadcrumb" separator="/">
- <transition-group name="breadcrumb">
- <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
- <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
- <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
- </el-breadcrumb-item>
- </transition-group>
- </el-breadcrumb>
-</template>
-
-<script>
-export default {
- data() {
- return {
- levelList: null
- }
- },
- watch: {
- $route(route) {
- // if you go to the redirect page, do not update the breadcrumbs
- if (route.path.startsWith('/redirect/')) {
- return
- }
- this.getBreadcrumb()
- }
- },
- created() {
- this.getBreadcrumb()
- },
- methods: {
- getBreadcrumb() {
- // only show routes with meta.title
- let matched = []
- const router = this.$route
- const pathNum = this.findPathNum(router.path)
- // multi-level menu
- if (pathNum > 2) {
- const reg = /\/\w+/gi
- const pathList = router.path.match(reg).map((item, index) => {
- if (index !== 0) item = item.slice(1)
- return item
- })
- this.getMatched(pathList, this.$store.getters.defaultRoutes, matched)
- } else {
- matched = router.matched.filter(item => item.meta && item.meta.title)
- }
- // 判断是否为首页
- if (!this.isDashboard(matched[0])) {
- matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
- }
- this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
- },
- findPathNum(str, char = "/") {
- let index = str.indexOf(char)
- let num = 0
- while (index !== -1) {
- num++
- index = str.indexOf(char, index + 1)
- }
- return num
- },
- getMatched(pathList, routeList, matched) {
- let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0])
- if (data) {
- matched.push(data)
- if (data.children && pathList.length) {
- pathList.shift()
- this.getMatched(pathList, data.children, matched)
- }
- }
- },
- isDashboard(route) {
- const name = route && route.name
- if (!name) {
- return false
- }
- return name.trim() === 'Index'
- },
- handleLink(item) {
- const { redirect, path } = item
- if (redirect) {
- this.$router.push(redirect)
- return
- }
- this.$router.push(path)
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.app-breadcrumb.el-breadcrumb {
- display: inline-block;
- font-size: 14px;
- line-height: 50px;
- .no-redirect {
- color: #97a8be;
- cursor: text;
- }
-}
-</style>
diff --git a/ruoyi-ui/src/components/Crontab/month.vue b/ruoyi-ui/src/components/Crontab/month.vue
deleted file mode 100644
index 8f05d95..0000000
--- a/ruoyi-ui/src/components/Crontab/month.vue
+++ /dev/null
@@ -1,114 +0,0 @@
-<template>
- <el-form size='small'>
- <el-form-item>
- <el-radio v-model='radioValue' :label="1">
- 月,允许的通配符[, - * /]
- </el-radio>
- </el-form-item>
-
- <el-form-item>
- <el-radio v-model='radioValue' :label="2">
- 周期从
- <el-input-number v-model='cycle01' :min="1" :max="11" /> -
- <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> 月
- </el-radio>
- </el-form-item>
-
- <el-form-item>
- <el-radio v-model='radioValue' :label="3">
- 从
- <el-input-number v-model='average01' :min="1" :max="11" /> 月开始,每
- <el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> 月月执行一次
- </el-radio>
- </el-form-item>
-
- <el-form-item>
- <el-radio v-model='radioValue' :label="4">
- 指定
- <el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
- <el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option>
- </el-select>
- </el-radio>
- </el-form-item>
- </el-form>
-</template>
-
-<script>
-export default {
- data() {
- return {
- radioValue: 1,
- cycle01: 1,
- cycle02: 2,
- average01: 1,
- average02: 1,
- checkboxList: [],
- checkNum: this.check
- }
- },
- name: 'crontab-month',
- props: ['check', 'cron'],
- methods: {
- // 单选按钮值变化时
- radioChange() {
- switch (this.radioValue) {
- case 1:
- this.$emit('update', 'month', '*')
- break
- case 2:
- this.$emit('update', 'month', this.cycleTotal)
- break
- case 3:
- this.$emit('update', 'month', this.averageTotal)
- break
- case 4:
- this.$emit('update', 'month', this.checkboxString)
- break
- }
- },
- // 周期两个值变化时
- cycleChange() {
- if (this.radioValue == '2') {
- this.$emit('update', 'month', this.cycleTotal)
- }
- },
- // 平均两个值变化时
- averageChange() {
- if (this.radioValue == '3') {
- this.$emit('update', 'month', this.averageTotal)
- }
- },
- // checkbox值变化时
- checkboxChange() {
- if (this.radioValue == '4') {
- this.$emit('update', 'month', this.checkboxString)
- }
- }
- },
- watch: {
- 'radioValue': 'radioChange',
- 'cycleTotal': 'cycleChange',
- 'averageTotal': 'averageChange',
- 'checkboxString': 'checkboxChange'
- },
- computed: {
- // 计算两个周期值
- cycleTotal: function () {
- const cycle01 = this.checkNum(this.cycle01, 1, 11)
- const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
- return cycle01 + '-' + cycle02
- },
- // 计算平均用到的值
- averageTotal: function () {
- const average01 = this.checkNum(this.average01, 1, 11)
- const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
- return average01 + '/' + average02
- },
- // 计算勾选的checkbox值合集
- checkboxString: function () {
- let str = this.checkboxList.join()
- return str == '' ? '*' : str
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/components/DictData/index.js b/ruoyi-ui/src/components/DictData/index.js
deleted file mode 100644
index d43d816..0000000
--- a/ruoyi-ui/src/components/DictData/index.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Vue from 'vue'
-import store from '@/store'
-import DataDict from '@/utils/dict'
-import { getDicts as getDicts } from '@/api/system/dict/data'
-
-function searchDictByKey(dict, key) {
- if (key == null && key == "") {
- return null
- }
- try {
- for (let i = 0; i < dict.length; i++) {
- if (dict[i].key == key) {
- return dict[i].value
- }
- }
- } catch (e) {
- return null
- }
-}
-
-function install() {
- Vue.use(DataDict, {
- metas: {
- '*': {
- labelField: 'dictLabel',
- valueField: 'dictValue',
- request(dictMeta) {
- const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
- if (storeDict) {
- return new Promise(resolve => { resolve(storeDict) })
- } else {
- return new Promise((resolve, reject) => {
- getDicts(dictMeta.type).then(res => {
- store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
- resolve(res.data)
- }).catch(error => {
- reject(error)
- })
- })
- }
- },
- },
- },
- })
-}
-
-export default {
- install,
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/DictTag/index.vue b/ruoyi-ui/src/components/DictTag/index.vue
deleted file mode 100644
index 3b630ff..0000000
--- a/ruoyi-ui/src/components/DictTag/index.vue
+++ /dev/null
@@ -1,93 +0,0 @@
-<template>
- <div>
- <template v-for="(item, index) in options">
- <template v-if="isValueMatch(item.value)">
- <span
- v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
- :key="item.value"
- :index="index"
- :class="item.raw.cssClass"
- >{{ item.label + ' ' }}</span
- >
- <el-tag
- v-else
- :disable-transitions="true"
- :key="item.value"
- :index="index"
- :type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
- :class="item.raw.cssClass"
- >
- {{ item.label + ' ' }}
- </el-tag>
- </template>
- </template>
- <template v-if="unmatch && showValue">
- {{ unmatchArray | handleArray }}
- </template>
- </div>
-</template>
-
-<script>
-export default {
- name: "DictTag",
- props: {
- options: {
- type: Array,
- default: null,
- },
- value: [Number, String, Array],
- showValue: {
- type: Boolean,
- default: true,
- },
- separator: {
- type: String,
- default: ","
- }
- },
- data() {
- return {
- unmatchArray: [], // 记录未匹配的项
- }
- },
- computed: {
- values() {
- if (this.value === null || typeof this.value === 'undefined' || this.value === '') return []
- if (typeof this.value === 'number' || typeof this.value === 'boolean') return [this.value]
- return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator)
- },
- unmatch() {
- this.unmatchArray = []
- // 没有value不显示
- if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false
- // 传入值为数组
- let unmatch = false // 添加一个标志来判断是否有未匹配项
- this.values.forEach(item => {
- if (!this.options.some(v => v.value == item)) {
- this.unmatchArray.push(item)
- unmatch = true // 如果有未匹配项,将标志设置为true
- }
- })
- return unmatch // 返回标志的值
- },
- },
- methods: {
- isValueMatch(itemValue) {
- return this.values.some(val => val == itemValue)
- }
- },
- filters: {
- handleArray(array) {
- if (array.length === 0) return ''
- return array.reduce((pre, cur) => {
- return pre + ' ' + cur
- })
- },
- }
-}
-</script>
-<style scoped>
-.el-tag + .el-tag {
- margin-left: 10px;
-}
-</style>
diff --git a/ruoyi-ui/src/components/Editor/index.vue b/ruoyi-ui/src/components/Editor/index.vue
deleted file mode 100644
index a415015..0000000
--- a/ruoyi-ui/src/components/Editor/index.vue
+++ /dev/null
@@ -1,297 +0,0 @@
-<template>
- <div>
- <el-upload
- :action="uploadUrl"
- :before-upload="handleBeforeUpload"
- :on-success="handleUploadSuccess"
- :on-error="handleUploadError"
- name="file"
- :show-file-list="false"
- :headers="headers"
- style="display: none"
- ref="upload"
- v-if="this.type == 'url'"
- >
- </el-upload>
- <div class="editor" ref="editor" :style="styles"></div>
- </div>
-</template>
-
-<script>
-import axios from "axios"
-import Quill from "quill"
-import "quill/dist/quill.core.css"
-import "quill/dist/quill.snow.css"
-import "quill/dist/quill.bubble.css"
-import { getToken } from "@/utils/auth"
-
-export default {
- name: "Editor",
- props: {
- /* 编辑器的内容 */
- value: {
- type: String,
- default: "",
- },
- /* 高度 */
- height: {
- type: Number,
- default: null,
- },
- /* 最小高度 */
- minHeight: {
- type: Number,
- default: null,
- },
- /* 只读 */
- readOnly: {
- type: Boolean,
- default: false,
- },
- /* 上传文件大小限制(MB) */
- fileSize: {
- type: Number,
- default: 5,
- },
- /* 类型(base64格式、url格式) */
- type: {
- type: String,
- default: "url",
- }
- },
- data() {
- return {
- uploadUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
- headers: {
- Authorization: "Bearer " + getToken()
- },
- Quill: null,
- currentValue: "",
- options: {
- theme: "snow",
- bounds: document.body,
- debug: "warn",
- modules: {
- // 工具栏配置
- toolbar: [
- ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
- ["blockquote", "code-block"], // 引用 代码块
- [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
- [{ indent: "-1" }, { indent: "+1" }], // 缩进
- [{ size: ["small", false, "large", "huge"] }], // 字体大小
- [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
- [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
- [{ align: [] }], // 对齐方式
- ["clean"], // 清除文本格式
- ["link", "image", "video"] // 链接、图片、视频
- ],
- },
- placeholder: "请输入内容",
- readOnly: this.readOnly,
- },
- }
- },
- computed: {
- styles() {
- let style = {}
- if (this.minHeight) {
- style.minHeight = `${this.minHeight}px`
- }
- if (this.height) {
- style.height = `${this.height}px`
- }
- return style
- }
- },
- watch: {
- value: {
- handler(val) {
- if (val !== this.currentValue) {
- this.currentValue = val === null ? "" : val
- if (this.Quill) {
- this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
- }
- }
- },
- immediate: true,
- },
- },
- mounted() {
- this.init()
- },
- beforeDestroy() {
- this.Quill = null
- },
- methods: {
- init() {
- const editor = this.$refs.editor
- this.Quill = new Quill(editor, this.options)
- // 如果设置了上传地址则自定义图片上传事件
- if (this.type == 'url') {
- let toolbar = this.Quill.getModule("toolbar")
- toolbar.addHandler("image", (value) => {
- if (value) {
- this.$refs.upload.$children[0].$refs.input.click()
- } else {
- this.quill.format("image", false)
- }
- })
- this.Quill.root.addEventListener('paste', this.handlePasteCapture, true)
- }
- this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
- this.Quill.on("text-change", (delta, oldDelta, source) => {
- const html = this.$refs.editor.children[0].innerHTML
- const text = this.Quill.getText()
- const quill = this.Quill
- this.currentValue = html
- this.$emit("input", html)
- this.$emit("on-change", { html, text, quill })
- })
- this.Quill.on("text-change", (delta, oldDelta, source) => {
- this.$emit("on-text-change", delta, oldDelta, source)
- })
- this.Quill.on("selection-change", (range, oldRange, source) => {
- this.$emit("on-selection-change", range, oldRange, source)
- })
- this.Quill.on("editor-change", (eventName, ...args) => {
- this.$emit("on-editor-change", eventName, ...args)
- })
- },
- // 上传前校检格式和大小
- handleBeforeUpload(file) {
- const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]
- const isJPG = type.includes(file.type)
- // 检验文件格式
- if (!isJPG) {
- this.$message.error(`图片格式错误!`)
- return false
- }
- // 校检文件大小
- if (this.fileSize) {
- const isLt = file.size / 1024 / 1024 < this.fileSize
- if (!isLt) {
- this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`)
- return false
- }
- }
- return true
- },
- handleUploadSuccess(res, file) {
- // 如果上传成功
- if (res.code == 200) {
- // 获取富文本组件实例
- let quill = this.Quill
- // 获取光标所在位置
- let length = quill.getSelection().index
- // 插入图片 res.url为服务器返回的图片地址
- quill.insertEmbed(length, "image", res.data.url)
- // 调整光标到最后
- quill.setSelection(length + 1)
- } else {
- this.$message.error("图片插入失败")
- }
- },
- handleUploadError() {
- this.$message.error("图片插入失败")
- },
- // 复制粘贴图片处理
- handlePasteCapture(e) {
- const clipboard = e.clipboardData || window.clipboardData
- if (clipboard && clipboard.items) {
- for (let i = 0; i < clipboard.items.length; i++) {
- const item = clipboard.items[i]
- if (item.type.indexOf('image') !== -1) {
- e.preventDefault()
- const file = item.getAsFile()
- this.insertImage(file)
- }
- }
- }
- },
- insertImage(file) {
- const formData = new FormData()
- formData.append("file", file)
- axios.post(this.uploadUrl, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: this.headers.Authorization } }).then(res => {
- this.handleUploadSuccess(res.data)
- })
- }
- }
-}
-</script>
-
-<style>
-.editor, .ql-toolbar {
- white-space: pre-wrap !important;
- line-height: normal !important;
-}
-.quill-img {
- display: none;
-}
-.ql-snow .ql-tooltip[data-mode="link"]::before {
- content: "请输入链接地址:";
-}
-.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
- border-right: 0px;
- content: "保存";
- padding-right: 0px;
-}
-.ql-snow .ql-tooltip[data-mode="video"]::before {
- content: "请输入视频地址:";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item::before {
- content: "14px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
- content: "10px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
- content: "18px";
-}
-.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
-.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
- content: "32px";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item::before {
- content: "文本";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
- content: "标题1";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
- content: "标题2";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
- content: "标题3";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
- content: "标题4";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
- content: "标题5";
-}
-.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
-.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
- content: "标题6";
-}
-.ql-snow .ql-picker.ql-font .ql-picker-label::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item::before {
- content: "标准字体";
-}
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
- content: "衬线字体";
-}
-.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
-.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
- content: "等宽字体";
-}
-</style>
diff --git a/ruoyi-ui/src/components/FileUpload/index.vue b/ruoyi-ui/src/components/FileUpload/index.vue
deleted file mode 100644
index c709f6d..0000000
--- a/ruoyi-ui/src/components/FileUpload/index.vue
+++ /dev/null
@@ -1,261 +0,0 @@
-<template>
- <div class="upload-file">
- <el-upload
- multiple
- :action="uploadFileUrl"
- :before-upload="handleBeforeUpload"
- :file-list="fileList"
- :data="data"
- :limit="limit"
- :on-error="handleUploadError"
- :on-exceed="handleExceed"
- :on-success="handleUploadSuccess"
- :show-file-list="false"
- :headers="headers"
- class="upload-file-uploader"
- ref="fileUpload"
- v-if="!disabled"
- >
- <!-- 上传按钮 -->
- <el-button size="mini" type="primary">选取文件</el-button>
- <!-- 上传提示 -->
- <div class="el-upload__tip" slot="tip" v-if="showTip">
- 请上传
- <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
- <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
- 的文件
- </div>
- </el-upload>
-
- <!-- 文件列表 -->
- <transition-group ref="uploadFileList" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
- <li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
- <el-link :href="file.url" :underline="false" target="_blank">
- <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
- </el-link>
- <div class="ele-upload-list__item-content-action">
- <el-link :underline="false" @click="handleDelete(index)" type="danger" v-if="!disabled">删除</el-link>
- </div>
- </li>
- </transition-group>
- </div>
-</template>
-
-<script>
-import { getToken } from "@/utils/auth"
-import Sortable from 'sortablejs'
-
-export default {
- name: "FileUpload",
- props: {
- // 值
- value: [String, Object, Array],
- // 上传接口地址
- action: {
- type: String,
- default: "/file/upload"
- },
- // 上传携带的参数
- data: {
- type: Object
- },
- // 数量限制
- limit: {
- type: Number,
- default: 5
- },
- // 大小限制(MB)
- fileSize: {
- type: Number,
- default: 5
- },
- // 文件类型, 例如['png', 'jpg', 'jpeg']
- fileType: {
- type: Array,
- default: () => ["doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "pdf"]
- },
- // 是否显示提示
- isShowTip: {
- type: Boolean,
- default: true
- },
- // 禁用组件(仅查看文件)
- disabled: {
- type: Boolean,
- default: false
- },
- // 拖动排序
- drag: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- number: 0,
- uploadList: [],
- uploadFileUrl: process.env.VUE_APP_BASE_API + this.action, // 上传文件服务器地址
- headers: {
- Authorization: "Bearer " + getToken(),
- },
- fileList: []
- }
- },
- mounted() {
- if (this.drag && !this.disabled) {
- this.$nextTick(() => {
- const element = this.$refs.uploadFileList?.$el || this.$refs.uploadFileList
- Sortable.create(element, {
- ghostClass: 'file-upload-darg',
- onEnd: (evt) => {
- const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
- this.fileList.splice(evt.newIndex, 0, movedItem)
- this.$emit("input", this.listToString(this.fileList))
- }
- })
- })
- }
- },
- watch: {
- value: {
- handler(val) {
- if (val) {
- let temp = 1
- // 首先将值转为数组
- const list = Array.isArray(val) ? val : this.value.split(',')
- // 然后将数组转为对象数组
- this.fileList = list.map(item => {
- if (typeof item === "string") {
- item = { name: item, url: item }
- }
- item.uid = item.uid || new Date().getTime() + temp++
- return item
- })
- } else {
- this.fileList = []
- return []
- }
- },
- deep: true,
- immediate: true
- }
- },
- computed: {
- // 是否显示提示
- showTip() {
- return this.isShowTip && (this.fileType || this.fileSize)
- },
- },
- methods: {
- // 上传前校检格式和大小
- handleBeforeUpload(file) {
- // 校检文件类型
- if (this.fileType) {
- const fileName = file.name.split('.')
- const fileExt = fileName[fileName.length - 1]
- const isTypeOk = this.fileType.indexOf(fileExt) >= 0
- if (!isTypeOk) {
- this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}格式文件!`)
- return false
- }
- }
- // 校检文件名是否包含特殊字符
- if (file.name.includes(',')) {
- this.$modal.msgError('文件名不正确,不能包含英文逗号!')
- return false
- }
- // 校检文件大小
- if (this.fileSize) {
- const isLt = file.size / 1024 / 1024 < this.fileSize
- if (!isLt) {
- this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`)
- return false
- }
- }
- this.$modal.loading("正在上传文件,请稍候...")
- this.number++
- return true
- },
- // 文件个数超出
- handleExceed() {
- this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
- },
- // 上传失败
- handleUploadError(err) {
- this.$modal.msgError("上传文件失败,请重试")
- this.$modal.closeLoading()
- },
- // 上传成功回调
- handleUploadSuccess(res, file) {
- if (res.code === 200) {
- this.uploadList.push({ name: res.data.url, url: res.data.url })
- this.uploadedSuccessfully()
- } else {
- this.number--
- this.$modal.closeLoading()
- this.$modal.msgError(res.msg)
- this.$refs.fileUpload.handleRemove(file)
- this.uploadedSuccessfully()
- }
- },
- // 删除文件
- handleDelete(index) {
- this.fileList.splice(index, 1)
- this.$emit("input", this.listToString(this.fileList))
- },
- // 上传结束处理
- uploadedSuccessfully() {
- if (this.number > 0 && this.uploadList.length === this.number) {
- this.fileList = this.fileList.concat(this.uploadList)
- this.uploadList = []
- this.number = 0
- this.$emit("input", this.listToString(this.fileList))
- this.$modal.closeLoading()
- }
- },
- // 获取文件名称
- getFileName(name) {
- // 如果是url那么取最后的名字 如果不是直接返回
- if (name.lastIndexOf("/") > -1) {
- return name.slice(name.lastIndexOf("/") + 1)
- } else {
- return name
- }
- },
- // 对象转成指定字符串分隔
- listToString(list, separator) {
- let strs = ""
- separator = separator || ","
- for (let i in list) {
- strs += list[i].url + separator
- }
- return strs != '' ? strs.substr(0, strs.length - 1) : ''
- }
- }
-}
-</script>
-
-<style scoped lang="scss">
-.file-upload-darg {
- opacity: 0.5;
- background: #c8ebfb;
-}
-.upload-file-uploader {
- margin-bottom: 5px;
-}
-.upload-file-list .el-upload-list__item {
- border: 1px solid #e4e7ed;
- line-height: 2;
- margin-bottom: 10px;
- position: relative;
-}
-.upload-file-list .ele-upload-list__item-content {
- display: flex;
- justify-content: space-between;
- align-items: center;
- color: inherit;
-}
-.ele-upload-list__item-content-action .el-link {
- margin-right: 10px;
-}
-</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/Hamburger/index.vue b/ruoyi-ui/src/components/Hamburger/index.vue
deleted file mode 100644
index c6a4359..0000000
--- a/ruoyi-ui/src/components/Hamburger/index.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-<template>
- <div style="padding: 0 15px;" @click="toggleClick">
- <svg
- :class="{'is-active':isActive}"
- class="hamburger"
- viewBox="0 0 1024 1024"
- xmlns="http://www.w3.org/2000/svg"
- width="64"
- height="64"
- >
- <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
- </svg>
- </div>
-</template>
-
-<script>
-export default {
- name: 'Hamburger',
- props: {
- isActive: {
- type: Boolean,
- default: false
- }
- },
- methods: {
- toggleClick() {
- this.$emit('toggleClick')
- }
- }
-}
-</script>
-
-<style scoped>
-.hamburger {
- display: inline-block;
- vertical-align: middle;
- width: 20px;
- height: 20px;
-}
-
-.hamburger.is-active {
- transform: rotate(180deg);
-}
-</style>
diff --git a/ruoyi-ui/src/components/HeaderSearch/index.vue b/ruoyi-ui/src/components/HeaderSearch/index.vue
deleted file mode 100644
index 94aa95b..0000000
--- a/ruoyi-ui/src/components/HeaderSearch/index.vue
+++ /dev/null
@@ -1,397 +0,0 @@
-<template>
- <div class="header-search">
- <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
- <el-dialog
- :visible.sync="show"
- width="600px"
- @close="close"
- @opened="onDialogOpened"
- :show-close="false"
- append-to-body
- >
- <el-input
- v-model="search"
- ref="headerSearchSelectRef"
- size="large"
- @input="querySearch"
- prefix-icon="el-icon-search"
- placeholder="菜单搜索,支持标题、URL模糊查询"
- clearable
- @keyup.enter.native="selectActiveResult"
- @keydown.up.native="navigateResult('up')"
- @keydown.down.native="navigateResult('down')"
- >
- </el-input>
-
- <div class="result-count" v-if="search && options.length > 0">
- 找到 <strong>{{ options.length }}</strong> 个结果
- </div>
-
- <el-scrollbar wrap-class="right-scrollbar-wrapper">
- <div class="result-wrap">
- <template v-if="options.length > 0">
- <div
- class="search-item"
- v-for="(item, index) in options"
- :key="item.path"
- :class="{ 'is-active': index === activeIndex }"
- :style="activeStyle(index)"
- @mouseenter="activeIndex = index"
- @mouseleave="activeIndex = -1"
- >
- <div class="left">
- <svg-icon class="menu-icon" :icon-class="item.icon" />
- </div>
- <div class="search-info" @click="change(item)">
- <div class="menu-title" v-html="highlightText(item.title.join(' / '))"></div>
- <div class="menu-path" v-html="highlightText(item.path)"></div>
- </div>
- <svg-icon icon-class="enter" v-show="index === activeIndex" />
- </div>
- </template>
-
- <div class="empty-state" v-else-if="search && options.length === 0">
- <i class="el-icon-search empty-icon"></i>
- <p class="empty-text">未找到 "<strong>{{ search }}</strong>" 相关菜单</p>
- <p class="empty-tip">试试其他关键词或路径</p>
- </div>
-
- </div>
- </el-scrollbar>
-
- <div class="search-footer">
- <span class="shortcut-item">
- <kbd>↑</kbd><kbd>↓</kbd> 切换
- </span>
- <span class="shortcut-item">
- <kbd>↵</kbd> 选择
- </span>
- <span class="shortcut-item">
- <kbd>Esc</kbd> 关闭
- </span>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import Fuse from 'fuse.js/dist/fuse.min.js'
-import path from 'path'
-import { isHttp } from '@/utils/validate'
-
-export default {
- name: 'HeaderSearch',
- data() {
- return {
- search: '',
- options: [],
- searchPool: [],
- activeIndex: -1,
- show: false,
- fuse: undefined
- }
- },
- computed: {
- theme() {
- return this.$store.state.settings.theme
- },
- routes() {
- return this.$store.getters.defaultRoutes
- }
- },
- watch: {
- routes() {
- this.searchPool = this.generateRoutes(this.routes)
- },
- searchPool(list) {
- this.initFuse(list)
- }
- },
- mounted() {
- this.searchPool = this.generateRoutes(this.routes)
- },
- methods: {
- click() {
- this.show = !this.show
- if (this.show) {
- this.options = this.searchPool
- }
- },
- onDialogOpened() {
- this.$nextTick(() => {
- this.$refs.headerSearchSelectRef && this.$refs.headerSearchSelectRef.focus()
- })
- },
- close() {
- this.$refs.headerSearchSelectRef && this.$refs.headerSearchSelectRef.blur()
- this.search = ''
- this.options = this.searchPool
- this.show = false
- this.activeIndex = -1
- },
- change(val) {
- const p = val.path
- const query = val.query
- if (isHttp(val.path)) {
- // http(s):// 路径新窗口打开
- const pindex = p.indexOf('http')
- window.open(p.substr(pindex, p.length), '_blank')
- } else {
- if (query) {
- this.$router.push({ path: p, query: JSON.parse(query) })
- } else {
- this.$router.push(p)
- }
- }
- this.search = ''
- this.options = this.searchPool
- this.$nextTick(() => {
- this.show = false
- })
- },
- initFuse(list) {
- this.fuse = new Fuse(list, {
- shouldSort: true,
- threshold: 0.2,
- minMatchCharLength: 1,
- keys: [{
- name: 'title',
- weight: 0.7
- }, {
- name: 'path',
- weight: 0.3
- }]
- })
- },
- generateRoutes(routes, basePath = '/', prefixTitle = []) {
- let res = []
- for (const router of routes) {
- if (router.hidden) { continue }
- const data = {
- path: !isHttp(router.path) ? path.resolve(basePath, router.path) : router.path,
- title: [...prefixTitle],
- icon: ''
- }
- if (router.meta && router.meta.title) {
- data.title = [...data.title, router.meta.title]
- data.icon = router.meta.icon
- if (router.redirect !== 'noRedirect') {
- res.push(data)
- }
- }
- if (router.query) {
- data.query = router.query
- }
- if (router.children) {
- const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
- if (tempRoutes.length >= 1) {
- res = [...res, ...tempRoutes]
- }
- }
- }
- return res
- },
- querySearch(query) {
- this.activeIndex = -1
- if (query !== '') {
- const q = query.toLowerCase()
- const pathMatches = this.searchPool.filter(item =>
- item.path.toLowerCase().includes(q)
- )
- const fuseMatches = this.fuse.search(query).map(item => item.item)
- const merged = [...pathMatches]
- fuseMatches.forEach(item => {
- if (!merged.find(m => m.path === item.path)) {
- merged.push(item)
- }
- })
- this.options = merged
- } else {
- this.options = this.searchPool
- }
- },
- activeStyle(index) {
- if (index !== this.activeIndex) return {}
- return {
- 'background-color': this.theme,
- 'color': '#fff'
- }
- },
- navigateResult(direction) {
- if (direction === 'up') {
- this.activeIndex = this.activeIndex <= 0 ? this.options.length - 1 : this.activeIndex - 1
- } else if (direction === 'down') {
- this.activeIndex = this.activeIndex >= this.options.length - 1 ? 0 : this.activeIndex + 1
- }
- },
- selectActiveResult() {
- if (this.options.length > 0 && this.activeIndex >= 0) {
- this.change(this.options[this.activeIndex])
- }
- },
- highlightText(text) {
- if (!text) return ''
- if (!this.search) return text
- const keyword = this.escapeRegExp(this.search)
- const reg = new RegExp(`(${keyword})`, 'gi')
- return text.replace(reg, '<span class="highlight">$1</span>')
- },
- escapeRegExp(str) {
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- }
- }
-}
-</script>
-
-<style lang='scss' scoped>
-::v-deep {
- .el-dialog__header {
- padding: 6px !important;
- }
-
- .highlight {
- color: red;
- font-weight: 600;
- }
-
- .is-active .highlight {
- color: rgba(255, 255, 255, 0.9);
- font-weight: 600;
- }
-}
-
-.header-search {
- .search-icon {
- cursor: pointer;
- font-size: 18px;
- vertical-align: middle;
- }
-}
-
-.result-count {
- padding: 6px 16px 0;
- font-size: 12px;
- color: #aaa;
-
- strong {
- color: red;
- font-weight: 600;
- }
-}
-
-.result-wrap {
- height: 280px;
- margin: 4px 0;
-
- .search-item {
- display: flex;
- height: 48px;
- align-items: center;
- padding-right: 10px;
- border-radius: 4px;
- transition: background 0.15s;
-
- .left {
- width: 60px;
- text-align: center;
- flex-shrink: 0;
-
- .menu-icon {
- width: 18px;
- height: 18px;
- }
- }
-
- .search-info {
- padding-left: 5px;
- margin-top: 10px;
- width: 100%;
- display: flex;
- flex-direction: column;
- justify-content: flex-start;
- flex: 1;
- overflow: hidden;
-
- .menu-title,
- .menu-path {
- height: 20px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .menu-path {
- color: #ccc;
- font-size: 10px;
- }
- }
- }
-
- .search-item:hover {
- cursor: pointer;
- }
-
- .empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- height: 100%;
-
- .empty-icon {
- font-size: 42px;
- color: #e0e0e0;
- margin-bottom: 14px;
- }
-
- .empty-text {
- font-size: 14px;
- color: #999;
- margin: 0 0 6px;
-
- strong {
- color: #666;
- }
- }
-
- .empty-tip {
- font-size: 12px;
- color: #bbb;
- margin: 0;
- }
- }
-}
-
-.search-footer {
- display: flex;
- align-items: center;
- gap: 28px;
- padding: 10px 20px;
- border-top: 1px solid #f0f0f0;
- color: #999;
- font-size: 12px;
-
- .shortcut-item {
- display: flex;
- align-items: center;
- gap: 5px;
- }
-
- kbd {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-width: 20px;
- height: 20px;
- padding: 0 5px;
- border: 1px solid #ddd;
- border-radius: 4px;
- background: #f7f7f7;
- color: #555;
- font-size: 11px;
- font-family: inherit;
- line-height: 1;
- box-shadow: 0 1px 0 #ccc;
- }
-}
-</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/IconSelect/index.vue b/ruoyi-ui/src/components/IconSelect/index.vue
deleted file mode 100644
index 6087c6c..0000000
--- a/ruoyi-ui/src/components/IconSelect/index.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-<!-- @author zhengjie -->
-<template>
- <div class="icon-body">
- <el-input v-model="name" class="icon-search" clearable placeholder="请输入图标名称" @clear="filterIcons" @input="filterIcons">
- <i slot="suffix" class="el-icon-search el-input__icon" />
- </el-input>
- <div class="icon-list">
- <div class="list-container">
- <div v-for="(item, index) in iconList" class="icon-item-wrapper" :key="index" @click="selectedIcon(item)">
- <div :class="['icon-item', { active: activeIcon === item }]">
- <svg-icon :icon-class="item" class-name="icon" style="height: 25px;width: 16px;"/>
- <span>{{ item }}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
-</template>
-
-<script>
-import icons from './requireIcons'
-export default {
- name: 'IconSelect',
- props: {
- activeIcon: {
- type: String
- }
- },
- data() {
- return {
- name: '',
- iconList: icons
- }
- },
- methods: {
- filterIcons() {
- this.iconList = icons
- if (this.name) {
- this.iconList = this.iconList.filter(item => item.includes(this.name))
- }
- },
- selectedIcon(name) {
- this.$emit('selected', name)
- document.body.click()
- },
- reset() {
- this.name = ''
- this.iconList = icons
- }
- }
-}
-</script>
-
-<style rel="stylesheet/scss" lang="scss" scoped>
- .icon-body {
- width: 100%;
- padding: 10px;
- .icon-search {
- position: relative;
- margin-bottom: 5px;
- }
- .icon-list {
- height: 200px;
- overflow: auto;
- .list-container {
- display: flex;
- flex-wrap: wrap;
- .icon-item-wrapper {
- width: calc(100% / 3);
- height: 25px;
- line-height: 25px;
- cursor: pointer;
- display: flex;
- .icon-item {
- display: flex;
- max-width: 100%;
- height: 100%;
- padding: 0 5px;
- &:hover {
- background: #ececec;
- border-radius: 5px;
- }
- .icon {
- flex-shrink: 0;
- }
- span {
- display: inline-block;
- vertical-align: -0.15em;
- fill: currentColor;
- padding-left: 2px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- .icon-item.active {
- background: #ececec;
- border-radius: 5px;
- }
- }
- }
- }
- }
-</style>
diff --git a/ruoyi-ui/src/components/IconSelect/requireIcons.js b/ruoyi-ui/src/components/IconSelect/requireIcons.js
deleted file mode 100644
index 5d3005d..0000000
--- a/ruoyi-ui/src/components/IconSelect/requireIcons.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-const req = require.context('../../assets/icons/svg', false, /\.svg$/)
-const requireAll = requireContext => requireContext.keys()
-
-const re = /\.\/(.*)\.svg/
-
-const icons = requireAll(req).map(i => {
- return i.match(re)[1]
-})
-
-export default icons
diff --git a/ruoyi-ui/src/components/ImageUpload/index.vue b/ruoyi-ui/src/components/ImageUpload/index.vue
deleted file mode 100644
index 85dc28c..0000000
--- a/ruoyi-ui/src/components/ImageUpload/index.vue
+++ /dev/null
@@ -1,266 +0,0 @@
-<template>
- <div class="component-upload-image">
- <el-upload
- multiple
- :disabled="disabled"
- :action="uploadImgUrl"
- list-type="picture-card"
- :on-success="handleUploadSuccess"
- :before-upload="handleBeforeUpload"
- :data="data"
- :limit="limit"
- :on-error="handleUploadError"
- :on-exceed="handleExceed"
- ref="imageUpload"
- :on-remove="handleDelete"
- :show-file-list="true"
- :headers="headers"
- :file-list="fileList"
- :on-preview="handlePictureCardPreview"
- :class="{hide: this.fileList.length >= this.limit}"
- >
- <i class="el-icon-plus"></i>
- </el-upload>
-
- <!-- 上传提示 -->
- <div class="el-upload__tip" slot="tip" v-if="showTip && !disabled">
- 请上传
- <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
- <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
- 的文件
- </div>
-
- <el-dialog
- :visible.sync="dialogVisible"
- title="预览"
- width="800"
- append-to-body
- >
- <img
- :src="dialogImageUrl"
- style="display: block; max-width: 100%; margin: 0 auto"
- />
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { getToken } from "@/utils/auth"
-import Sortable from 'sortablejs'
-
-export default {
- props: {
- value: [String, Object, Array],
- // 上传接口地址
- action: {
- type: String,
- default: "/file/upload"
- },
- // 上传携带的参数
- data: {
- type: Object
- },
- // 图片数量限制
- limit: {
- type: Number,
- default: 5
- },
- // 大小限制(MB)
- fileSize: {
- type: Number,
- default: 5
- },
- // 文件类型, 例如['png', 'jpg', 'jpeg']
- fileType: {
- type: Array,
- default: () => ["png", "jpg", "jpeg"]
- },
- // 是否显示提示
- isShowTip: {
- type: Boolean,
- default: true
- },
- // 禁用组件(仅查看图片)
- disabled: {
- type: Boolean,
- default: false
- },
- // 拖动排序
- drag: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- number: 0,
- uploadList: [],
- dialogImageUrl: "",
- dialogVisible: false,
- hideUpload: false,
- uploadImgUrl: process.env.VUE_APP_BASE_API + this.action, // 上传的图片服务器地址
- headers: {
- Authorization: "Bearer " + getToken(),
- },
- fileList: []
- }
- },
- mounted() {
- if (this.drag && !this.disabled) {
- this.$nextTick(() => {
- const element = this.$refs.imageUpload?.$el?.querySelector('.el-upload-list')
- Sortable.create(element, {
- onEnd: (evt) => {
- const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
- this.fileList.splice(evt.newIndex, 0, movedItem)
- this.$emit("input", this.listToString(this.fileList))
- }
- })
- })
- }
- },
- watch: {
- value: {
- handler(val) {
- if (val) {
- // 首先将值转为数组
- const list = Array.isArray(val) ? val : this.value.split(',')
- // 然后将数组转为对象数组
- this.fileList = list.map(item => {
- if (typeof item === "string") {
- item = { name: item, url: item }
- }
- return item
- })
- } else {
- this.fileList = []
- return []
- }
- },
- deep: true,
- immediate: true
- }
- },
- computed: {
- // 是否显示提示
- showTip() {
- return this.isShowTip && (this.fileType || this.fileSize)
- },
- },
- methods: {
- // 上传前loading加载
- handleBeforeUpload(file) {
- let isImg = false
- if (this.fileType.length) {
- let fileExtension = ""
- if (file.name.lastIndexOf(".") > -1) {
- fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1)
- }
- isImg = this.fileType.some(type => {
- if (file.type.indexOf(type) > -1) return true
- if (fileExtension && fileExtension.indexOf(type) > -1) return true
- return false
- })
- } else {
- isImg = file.type.indexOf("image") > -1
- }
-
- if (!isImg) {
- this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}图片格式文件!`)
- return false
- }
- if (file.name.includes(',')) {
- this.$modal.msgError('文件名不正确,不能包含英文逗号!')
- return false
- }
- if (this.fileSize) {
- const isLt = file.size / 1024 / 1024 < this.fileSize
- if (!isLt) {
- this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`)
- return false
- }
- }
- this.$modal.loading("正在上传图片,请稍候...")
- this.number++
- },
- // 文件个数超出
- handleExceed() {
- this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
- },
- // 上传成功回调
- handleUploadSuccess(res, file) {
- if (res.code === 200) {
- this.uploadList.push({ name: res.data.url, url: res.data.url })
- this.uploadedSuccessfully()
- } else {
- this.number--
- this.$modal.closeLoading()
- this.$modal.msgError(res.msg)
- this.$refs.imageUpload.handleRemove(file)
- this.uploadedSuccessfully()
- }
- },
- // 删除图片
- handleDelete(file) {
- const findex = this.fileList.map(f => f.name).indexOf(file.name)
- if (findex > -1) {
- this.fileList.splice(findex, 1)
- this.$emit("input", this.listToString(this.fileList))
- }
- },
- // 上传失败
- handleUploadError() {
- this.$modal.msgError("上传图片失败,请重试")
- this.$modal.closeLoading()
- },
- // 上传结束处理
- uploadedSuccessfully() {
- if (this.number > 0 && this.uploadList.length === this.number) {
- this.fileList = this.fileList.concat(this.uploadList)
- this.uploadList = []
- this.number = 0
- this.$emit("input", this.listToString(this.fileList))
- this.$modal.closeLoading()
- }
- },
- // 预览
- handlePictureCardPreview(file) {
- this.dialogImageUrl = file.url
- this.dialogVisible = true
- },
- // 对象转成指定字符串分隔
- listToString(list, separator) {
- let strs = ""
- separator = separator || ","
- for (let i in list) {
- if (list[i].url) {
- strs += list[i].url.replace(this.baseUrl, "") + separator
- }
- }
- return strs != '' ? strs.substr(0, strs.length - 1) : ''
- }
- }
-}
-</script>
-<style scoped lang="scss">
-// .el-upload--picture-card 控制加号部分
-::v-deep.hide .el-upload--picture-card {
- display: none;
-}
-
-::v-deep .el-upload-list--picture-card.is-disabled + .el-upload--picture-card {
- display: none !important;
-}
-
-// 去掉动画效果
-::v-deep .el-list-enter-active,
-::v-deep .el-list-leave-active {
- transition: all 0s;
-}
-
-::v-deep .el-list-enter, .el-list-leave-active {
- opacity: 0;
- transform: translateY(0);
-}
-</style>
-
diff --git a/ruoyi-ui/src/components/Pagination/index.vue b/ruoyi-ui/src/components/Pagination/index.vue
deleted file mode 100644
index 53c72b4..0000000
--- a/ruoyi-ui/src/components/Pagination/index.vue
+++ /dev/null
@@ -1,113 +0,0 @@
-<template>
- <div :class="{'hidden':hidden}" class="pagination-container">
- <el-pagination
- :background="background"
- :current-page.sync="currentPage"
- :page-size.sync="pageSize"
- :layout="layout"
- :page-sizes="pageSizes"
- :pager-count="pagerCount"
- :total="total"
- v-bind="$attrs"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
-</template>
-
-<script>
-import { scrollTo } from '@/utils/scroll-to'
-
-export default {
- name: 'Pagination',
- props: {
- total: {
- required: true,
- type: Number
- },
- page: {
- type: Number,
- default: 1
- },
- limit: {
- type: Number,
- default: 20
- },
- pageSizes: {
- type: Array,
- default() {
- return [10, 20, 30, 50]
- }
- },
- // 移动端页码按钮的数量端默认值5
- pagerCount: {
- type: Number,
- default: document.body.clientWidth < 992 ? 5 : 7
- },
- layout: {
- type: String,
- default: 'total, sizes, prev, pager, next, jumper'
- },
- background: {
- type: Boolean,
- default: true
- },
- autoScroll: {
- type: Boolean,
- default: true
- },
- hidden: {
- type: Boolean,
- default: false
- }
- },
- data() {
- return {
- }
- },
- computed: {
- currentPage: {
- get() {
- return this.page
- },
- set(val) {
- this.$emit('update:page', val)
- }
- },
- pageSize: {
- get() {
- return this.limit
- },
- set(val) {
- this.$emit('update:limit', val)
- }
- }
- },
- methods: {
- handleSizeChange(val) {
- if (this.currentPage * val > this.total) {
- this.currentPage = 1
- }
- this.$emit('pagination', { page: this.currentPage, limit: val })
- if (this.autoScroll) {
- scrollTo(0, 800)
- }
- },
- handleCurrentChange(val) {
- this.$emit('pagination', { page: val, limit: this.pageSize })
- if (this.autoScroll) {
- scrollTo(0, 800)
- }
- }
- }
-}
-</script>
-
-<style scoped>
-.pagination-container {
- background: #fff;
-}
-.pagination-container.hidden {
- display: none;
-}
-</style>
diff --git a/ruoyi-ui/src/components/PanThumb/index.vue b/ruoyi-ui/src/components/PanThumb/index.vue
deleted file mode 100644
index 1fa64f7..0000000
--- a/ruoyi-ui/src/components/PanThumb/index.vue
+++ /dev/null
@@ -1,141 +0,0 @@
-<template>
- <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
- <div class="pan-info">
- <div class="pan-info-roles-container">
- <slot />
- </div>
- </div>
- <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
- </div>
-</template>
-
-<script>
-export default {
- name: 'PanThumb',
- props: {
- image: {
- type: String,
- required: true
- },
- zIndex: {
- type: Number,
- default: 1
- },
- width: {
- type: String,
- default: '150px'
- },
- height: {
- type: String,
- default: '150px'
- }
- }
-}
-</script>
-
-<style scoped>
-.pan-item {
- width: 200px;
- height: 200px;
- border-radius: 50%;
- display: inline-block;
- position: relative;
- cursor: default;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
-}
-
-.pan-info-roles-container {
- padding: 20px;
- text-align: center;
-}
-
-.pan-thumb {
- width: 100%;
- height: 100%;
- background-position: center center;
- background-size: cover;
- border-radius: 50%;
- overflow: hidden;
- position: absolute;
- transform-origin: 95% 40%;
- transition: all 0.3s ease-in-out;
-}
-
-/* .pan-thumb:after {
- content: '';
- width: 8px;
- height: 8px;
- position: absolute;
- border-radius: 50%;
- top: 40%;
- left: 95%;
- margin: -4px 0 0 -4px;
- background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
- box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
-} */
-
-.pan-info {
- position: absolute;
- width: inherit;
- height: inherit;
- border-radius: 50%;
- overflow: hidden;
- box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
-}
-
-.pan-info h3 {
- color: #fff;
- text-transform: uppercase;
- position: relative;
- letter-spacing: 2px;
- font-size: 18px;
- margin: 0 60px;
- padding: 22px 0 0 0;
- height: 85px;
- font-family: 'Open Sans', Arial, sans-serif;
- text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
-}
-
-.pan-info p {
- color: #fff;
- padding: 10px 5px;
- font-style: italic;
- margin: 0 30px;
- font-size: 12px;
- border-top: 1px solid rgba(255, 255, 255, 0.5);
-}
-
-.pan-info p a {
- display: block;
- color: #333;
- width: 80px;
- height: 80px;
- background: rgba(255, 255, 255, 0.3);
- border-radius: 50%;
- color: #fff;
- font-style: normal;
- font-weight: 700;
- text-transform: uppercase;
- font-size: 9px;
- letter-spacing: 1px;
- padding-top: 24px;
- margin: 7px auto 0;
- font-family: 'Open Sans', Arial, sans-serif;
- opacity: 0;
- transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
- transform: translateX(60px) rotate(90deg);
-}
-
-.pan-info p a:hover {
- background: rgba(255, 255, 255, 0.5);
-}
-
-.pan-item:hover .pan-thumb {
- transform: rotate(-110deg);
-}
-
-.pan-item:hover .pan-info p a {
- opacity: 1;
- transform: translateX(0px) rotate(0deg);
-}
-</style>
diff --git a/ruoyi-ui/src/components/Screenfull/index.vue b/ruoyi-ui/src/components/Screenfull/index.vue
deleted file mode 100644
index 85937c9..0000000
--- a/ruoyi-ui/src/components/Screenfull/index.vue
+++ /dev/null
@@ -1,57 +0,0 @@
-<template>
- <div>
- <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
- </div>
-</template>
-
-<script>
-import screenfull from 'screenfull'
-
-export default {
- name: 'Screenfull',
- data() {
- return {
- isFullscreen: false
- }
- },
- mounted() {
- this.init()
- },
- beforeDestroy() {
- this.destroy()
- },
- methods: {
- click() {
- if (!screenfull.isEnabled) {
- this.$message({ message: '你的浏览器不支持全屏', type: 'warning' })
- return false
- }
- screenfull.toggle()
- },
- change() {
- this.isFullscreen = screenfull.isFullscreen
- },
- init() {
- if (screenfull.isEnabled) {
- screenfull.on('change', this.change)
- }
- },
- destroy() {
- if (screenfull.isEnabled) {
- screenfull.off('change', this.change)
- }
- }
- }
-}
-</script>
-
-<style scoped>
-.screenfull-svg {
- display: inline-block;
- cursor: pointer;
- fill: #5a5e66;;
- width: 20px;
- height: 20px;
- vertical-align: 10px;
-}
-</style>
diff --git a/ruoyi-ui/src/components/SizeSelect/index.vue b/ruoyi-ui/src/components/SizeSelect/index.vue
deleted file mode 100644
index 3c75530..0000000
--- a/ruoyi-ui/src/components/SizeSelect/index.vue
+++ /dev/null
@@ -1,55 +0,0 @@
-<template>
- <el-dropdown trigger="click" @command="handleSetSize">
- <div>
- <svg-icon class-name="size-icon" icon-class="size" />
- </div>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
- {{ item.label }}
- </el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
-</template>
-
-<script>
-export default {
- data() {
- return {
- sizeOptions: [
- { label: 'Default', value: 'default' },
- { label: 'Medium', value: 'medium' },
- { label: 'Small', value: 'small' },
- { label: 'Mini', value: 'mini' }
- ]
- }
- },
- computed: {
- size() {
- return this.$store.getters.size
- }
- },
- methods: {
- handleSetSize(size) {
- this.$ELEMENT.size = size
- this.$store.dispatch('app/setSize', size)
- this.refreshView()
- this.$message({
- message: 'Switch Size Success',
- type: 'success'
- })
- },
- refreshView() {
- // In order to make the cached page re-rendered
- this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
-
- const { fullPath } = this.$route
-
- this.$nextTick(() => {
- this.$router.replace({
- path: '/redirect' + fullPath
- })
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/components/SvgIcon/index.vue b/ruoyi-ui/src/components/SvgIcon/index.vue
deleted file mode 100644
index 340ace4..0000000
--- a/ruoyi-ui/src/components/SvgIcon/index.vue
+++ /dev/null
@@ -1,61 +0,0 @@
-<template>
- <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
- <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
- <use :xlink:href="iconName" />
- </svg>
-</template>
-
-<script>
-import { isExternal } from '@/utils/validate'
-
-export default {
- name: 'SvgIcon',
- props: {
- iconClass: {
- type: String,
- required: true
- },
- className: {
- type: String,
- default: ''
- }
- },
- computed: {
- isExternal() {
- return isExternal(this.iconClass)
- },
- iconName() {
- return `#icon-${this.iconClass}`
- },
- svgClass() {
- if (this.className) {
- return 'svg-icon ' + this.className
- } else {
- return 'svg-icon'
- }
- },
- styleExternalIcon() {
- return {
- mask: `url(${this.iconClass}) no-repeat 50% 50%`,
- '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
- }
- }
- }
-}
-</script>
-
-<style scoped>
-.svg-icon {
- width: 1em;
- height: 1em;
- vertical-align: -0.15em;
- fill: currentColor;
- overflow: hidden;
-}
-
-.svg-external-icon {
- background-color: currentColor;
- mask-size: cover!important;
- display: inline-block;
-}
-</style>
diff --git a/ruoyi-ui/src/directive/dialog/dragHeight.js b/ruoyi-ui/src/directive/dialog/dragHeight.js
deleted file mode 100644
index 03e56d2..0000000
--- a/ruoyi-ui/src/directive/dialog/dragHeight.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * v-dialogDragWidth 可拖动弹窗高度(右下角)
- * Copyright (c) 2019 ruoyi
- */
-
-export default {
- bind(el) {
- const dragDom = el.querySelector('.el-dialog')
- const lineEl = document.createElement('div')
- lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;'
- lineEl.addEventListener('mousedown',
- function(e) {
- // 鼠标按下,计算当前元素距离可视区的距离
- const disX = e.clientX - el.offsetLeft
- const disY = e.clientY - el.offsetTop
- // 当前宽度 高度
- const curWidth = dragDom.offsetWidth
- const curHeight = dragDom.offsetHeight
- document.onmousemove = function(e) {
- e.preventDefault() // 移动时禁用默认事件
- // 通过事件委托,计算移动的距离
- const xl = e.clientX - disX
- const yl = e.clientY - disY
- dragDom.style.width = `${curWidth + xl}px`
- dragDom.style.height = `${curHeight + yl}px`
- }
- document.onmouseup = function(e) {
- document.onmousemove = null
- document.onmouseup = null
- }
- }, false)
- dragDom.appendChild(lineEl)
- }
-}
diff --git a/ruoyi-ui/src/directive/dialog/dragWidth.js b/ruoyi-ui/src/directive/dialog/dragWidth.js
deleted file mode 100644
index bcc0b4b..0000000
--- a/ruoyi-ui/src/directive/dialog/dragWidth.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * v-dialogDragWidth 可拖动弹窗宽度(右侧边)
- * Copyright (c) 2019 ruoyi
- */
-
-export default {
- bind(el) {
- const dragDom = el.querySelector('.el-dialog')
- const lineEl = document.createElement('div')
- lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;'
- lineEl.addEventListener('mousedown',
- function (e) {
- // 鼠标按下,计算当前元素距离可视区的距离
- const disX = e.clientX - el.offsetLeft
- // 当前宽度
- const curWidth = dragDom.offsetWidth
- document.onmousemove = function (e) {
- e.preventDefault() // 移动时禁用默认事件
- // 通过事件委托,计算移动的距离
- const l = e.clientX - disX
- dragDom.style.width = `${curWidth + l}px`
- }
- document.onmouseup = function (e) {
- document.onmousemove = null
- document.onmouseup = null
- }
- }, false)
- dragDom.appendChild(lineEl)
- }
-}
diff --git a/ruoyi-ui/src/directive/module/clipboard.js b/ruoyi-ui/src/directive/module/clipboard.js
deleted file mode 100644
index fd9d16b..0000000
--- a/ruoyi-ui/src/directive/module/clipboard.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
-* v-clipboard 文字复制剪贴
-* Copyright (c) 2021 ruoyi
-*/
-
-import Clipboard from 'clipboard'
-export default {
- bind(el, binding, vnode) {
- switch (binding.arg) {
- case 'success':
- el._vClipBoard_success = binding.value
- break
- case 'error':
- el._vClipBoard_error = binding.value
- break
- default: {
- const clipboard = new Clipboard(el, {
- text: () => binding.value,
- action: () => binding.arg === 'cut' ? 'cut' : 'copy'
- })
- clipboard.on('success', e => {
- const callback = el._vClipBoard_success
- callback && callback(e)
- })
- clipboard.on('error', e => {
- const callback = el._vClipBoard_error
- callback && callback(e)
- })
- el._vClipBoard = clipboard
- }
- }
- },
- update(el, binding) {
- if (binding.arg === 'success') {
- el._vClipBoard_success = binding.value
- } else if (binding.arg === 'error') {
- el._vClipBoard_error = binding.value
- } else {
- el._vClipBoard.text = function () { return binding.value }
- el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy'
- }
- },
- unbind(el, binding) {
- if (!el._vClipboard) return
- if (binding.arg === 'success') {
- delete el._vClipBoard_success
- } else if (binding.arg === 'error') {
- delete el._vClipBoard_error
- } else {
- el._vClipBoard.destroy()
- delete el._vClipBoard
- }
- }
-}
diff --git a/ruoyi-ui/src/directive/permission/hasPermi.js b/ruoyi-ui/src/directive/permission/hasPermi.js
deleted file mode 100644
index 6d5409e..0000000
--- a/ruoyi-ui/src/directive/permission/hasPermi.js
+++ /dev/null
@@ -1,28 +0,0 @@
- /**
- * v-hasPermi 操作权限处理
- * Copyright (c) 2019 ruoyi
- */
-
-import store from '@/store'
-
-export default {
- inserted(el, binding, vnode) {
- const { value } = binding
- const all_permission = "*:*:*"
- const permissions = store.getters && store.getters.permissions
-
- if (value && value instanceof Array && value.length > 0) {
- const permissionFlag = value
-
- const hasPermissions = permissions.some(permission => {
- return all_permission === permission || permissionFlag.includes(permission)
- })
-
- if (!hasPermissions) {
- el.parentNode && el.parentNode.removeChild(el)
- }
- } else {
- throw new Error(`请设置操作权限标签值`)
- }
- }
-}
diff --git a/ruoyi-ui/src/directive/permission/hasRole.js b/ruoyi-ui/src/directive/permission/hasRole.js
deleted file mode 100644
index 276dfbe..0000000
--- a/ruoyi-ui/src/directive/permission/hasRole.js
+++ /dev/null
@@ -1,28 +0,0 @@
- /**
- * v-hasRole 角色权限处理
- * Copyright (c) 2019 ruoyi
- */
-
-import store from '@/store'
-
-export default {
- inserted(el, binding, vnode) {
- const { value } = binding
- const super_admin = "admin"
- const roles = store.getters && store.getters.roles
-
- if (value && value instanceof Array && value.length > 0) {
- const roleFlag = value
-
- const hasRole = roles.some(role => {
- return super_admin === role || roleFlag.includes(role)
- })
-
- if (!hasRole) {
- el.parentNode && el.parentNode.removeChild(el)
- }
- } else {
- throw new Error(`请设置角色权限标签值"`)
- }
- }
-}
diff --git a/ruoyi-ui/src/layout/components/AppMain.vue b/ruoyi-ui/src/layout/components/AppMain.vue
deleted file mode 100644
index e8dfc93..0000000
--- a/ruoyi-ui/src/layout/components/AppMain.vue
+++ /dev/null
@@ -1,140 +0,0 @@
-<template>
- <section class="app-main">
- <transition name="fade-transform" mode="out-in">
- <keep-alive :include="cachedViews">
- <router-view v-if="!$route.meta.link" :key="key" />
- </keep-alive>
- </transition>
- <iframe-toggle />
- <copyright />
- </section>
-</template>
-
-<script>
-import copyright from "./Copyright/index"
-import iframeToggle from "./IframeToggle/index"
-
-export default {
- name: 'AppMain',
- components: { iframeToggle, copyright },
- computed: {
- cachedViews() {
- return this.$store.state.tagsView.cachedViews
- },
- key() {
- return this.$route.path
- }
- },
- watch: {
- $route() {
- this.addIframe()
- }
- },
- mounted() {
- this.addIframe()
- },
- methods: {
- addIframe() {
- const { name } = this.$route
- if (name && this.$route.meta.link) {
- this.$store.dispatch('tagsView/addIframeView', this.$route)
- }
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.app-main {
- /* 50= navbar 50 */
- min-height: calc(100vh - 50px);
- width: 100%;
- position: relative;
- overflow: hidden;
-
- &:fullscreen,
- &:-webkit-full-screen,
- &:-moz-full-screen,
- &:-ms-fullscreen {
- background: #fff;
- overflow-y: auto;
- }
-}
-
-.fixed-header + .app-main {
- overflow-y: auto;
- scrollbar-gutter: auto;
- height: calc(100vh - 50px);
- min-height: 0px;
-}
-
-.app-main:has(.copyright) {
- padding-bottom: 36px;
-}
-
-.fixed-header + .app-main {
- margin-top: 50px;
-}
-
-.hasTagsView {
- .app-main {
- /* 84 = navbar + tags-view = 50 + 34 */
- min-height: calc(100vh - 84px);
- }
-
- .fixed-header + .app-main {
- margin-top: 84px;
- height: calc(100vh - 84px);
- min-height: 0px;
- }
-}
-
-/* 移动端fixed-header优化 */
-@media screen and (max-width: 991px) {
- .fixed-header + .app-main {
- padding-bottom: max(60px, calc(constant(safe-area-inset-bottom) + 40px));
- padding-bottom: max(60px, calc(env(safe-area-inset-bottom) + 40px));
- overscroll-behavior-y: none;
- }
-
- .hasTagsView .fixed-header + .app-main {
- padding-bottom: max(60px, calc(constant(safe-area-inset-bottom) + 40px));
- padding-bottom: max(60px, calc(env(safe-area-inset-bottom) + 40px));
- overscroll-behavior-y: none;
- }
-}
-
-@supports (-webkit-touch-callout: none) {
- @media screen and (max-width: 991px) {
- .fixed-header + .app-main {
- padding-bottom: max(17px, calc(constant(safe-area-inset-bottom) + 10px));
- padding-bottom: max(17px, calc(env(safe-area-inset-bottom) + 10px));
- height: calc(100svh - 50px);
- height: calc(100dvh - 50px);
- }
-
- .hasTagsView .fixed-header + .app-main {
- padding-bottom: max(17px, calc(constant(safe-area-inset-bottom) + 10px));
- padding-bottom: max(17px, calc(env(safe-area-inset-bottom) + 10px));
- height: calc(100svh - 84px);
- height: calc(100dvh - 84px);
- }
- }
-}
-</style>
-
-<style lang="scss">
-::-webkit-scrollbar {
- width: 6px;
- height: 6px;
-}
-
-::-webkit-scrollbar-track {
- background-color: #f1f1f1;
-}
-
-::-webkit-scrollbar-thumb {
- background-color: #c0c0c0;
- border-radius: 3px;
-}
-</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/layout/components/IframeToggle/index.vue b/ruoyi-ui/src/layout/components/IframeToggle/index.vue
deleted file mode 100644
index 02ba4c3..0000000
--- a/ruoyi-ui/src/layout/components/IframeToggle/index.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-<template>
- <transition-group name="fade-transform" mode="out-in">
- <inner-link
- v-for="(item, index) in iframeViews"
- :key="item.path"
- :iframeId="'iframe' + index"
- v-show="$route.path === item.path"
- :src="iframeUrl(item.meta.link, item.query)"
- ></inner-link>
- </transition-group>
-</template>
-
-<script>
-import InnerLink from "../InnerLink/index"
-
-export default {
- components: { InnerLink },
- computed: {
- iframeViews() {
- return this.$store.state.tagsView.iframeViews
- }
- },
- methods: {
- iframeUrl(url, query) {
- if (Object.keys(query).length > 0) {
- let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&")
- return url + "?" + params
- }
- return url
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/InnerLink/index.vue b/ruoyi-ui/src/layout/components/InnerLink/index.vue
deleted file mode 100644
index afe66b5..0000000
--- a/ruoyi-ui/src/layout/components/InnerLink/index.vue
+++ /dev/null
@@ -1,47 +0,0 @@
-<template>
- <div :style="'height:' + height" v-loading="loading" element-loading-text="正在加载页面,请稍候!">
- <iframe
- :id="iframeId"
- style="width: 100%; height: 100%"
- :src="src"
- frameborder="no"
- ></iframe>
- </div>
-</template>
-
-<script>
-export default {
- props: {
- src: {
- type: String,
- default: "/"
- },
- iframeId: {
- type: String
- }
- },
- data() {
- return {
- loading: false,
- height: document.documentElement.clientHeight - 94.5 + "px;"
- }
- },
- mounted() {
- var _this = this
- const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/")
- const iframe = document.querySelector(iframeId)
- // iframe页面loading控制
- if (iframe.attachEvent) {
- this.loading = true
- iframe.attachEvent("onload", function () {
- _this.loading = false
- })
- } else {
- this.loading = true
- iframe.onload = function () {
- _this.loading = false
- }
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
deleted file mode 100644
index ac2959d..0000000
--- a/ruoyi-ui/src/layout/components/Navbar.vue
+++ /dev/null
@@ -1,254 +0,0 @@
-<template>
- <div class="navbar" :class="'nav' + navType">
- <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
-
- <breadcrumb v-if="navType == 1" id="breadcrumb-container" class="breadcrumb-container" />
- <top-nav v-if="navType == 2" id="topmenu-container" class="topmenu-container" />
- <template v-if="navType == 3">
- <logo v-show="showLogo" :collapse="false"></logo>
- <top-bar id="topbar-container" class="topbar-container" />
- </template>
- <div class="right-menu">
- <template v-if="device!=='mobile'">
- <search id="header-search" class="right-menu-item" />
-
- <el-tooltip content="源码地址" effect="dark" placement="bottom">
- <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
- </el-tooltip>
-
- <el-tooltip content="文档地址" effect="dark" placement="bottom">
- <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
- </el-tooltip>
-
- <screenfull id="screenfull" class="right-menu-item hover-effect" />
-
- <el-tooltip content="布局大小" effect="dark" placement="bottom">
- <size-select id="size-select" class="right-menu-item hover-effect" />
- </el-tooltip>
-
- <el-tooltip content="消息通知" effect="dark" placement="bottom">
- <header-notice id="header-notice" class="right-menu-item hover-effect" />
- </el-tooltip>
-
- </template>
-
- <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
- <div class="avatar-wrapper">
- <img :src="avatar" class="user-avatar">
- <span class="user-nickname"> {{ nickName }} </span>
- </div>
- <el-dropdown-menu slot="dropdown">
- <router-link to="/user/profile">
- <el-dropdown-item>个人中心</el-dropdown-item>
- </router-link>
- <el-dropdown-item @click.native="setLayout" v-if="setting">
- <span>布局设置</span>
- </el-dropdown-item>
- <el-dropdown-item @click.native="lockScreen">
- <span>锁定屏幕</span>
- </el-dropdown-item>
- <el-dropdown-item divided @click.native="logout">
- <span>退出登录</span>
- </el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </div>
- </div>
-</template>
-
-<script>
-import { mapGetters } from 'vuex'
-import Breadcrumb from '@/components/Breadcrumb'
-import TopNav from './TopNav'
-import TopBar from './TopBar'
-import Logo from './Sidebar/Logo'
-import Hamburger from '@/components/Hamburger'
-import Screenfull from '@/components/Screenfull'
-import SizeSelect from '@/components/SizeSelect'
-import Search from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
-import HeaderNotice from './HeaderNotice'
-
-export default {
- components: {
- Breadcrumb,
- Logo,
- TopNav,
- TopBar,
- Hamburger,
- Screenfull,
- SizeSelect,
- Search,
- RuoYiGit,
- RuoYiDoc,
- HeaderNotice
- },
- computed: {
- ...mapGetters([
- 'sidebar',
- 'avatar',
- 'device',
- 'nickName'
- ]),
- setting: {
- get() {
- return this.$store.state.settings.showSettings
- }
- },
- navType: {
- get() {
- return this.$store.state.settings.navType
- }
- },
- showLogo: {
- get() {
- return this.$store.state.settings.sidebarLogo
- }
- }
- },
- methods: {
- toggleSideBar() {
- this.$store.dispatch('app/toggleSideBar')
- },
- setLayout(event) {
- this.$emit('setLayout')
- },
- lockScreen() {
- const currentPath = this.$route.fullPath
- this.$store.dispatch('lock/lockScreen', currentPath).then(() => {
- this.$router.push('/lock')
- })
- },
- logout() {
- this.$confirm('确定注销并退出系统吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(() => {
- this.$store.dispatch('LogOut').then(() => {
- location.href = '/index'
- })
- }).catch(() => {})
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.navbar.nav3 {
- .hamburger-container {
- display: none !important;
- }
-}
-
-.navbar {
- height: 50px;
- overflow: hidden;
- position: relative;
- background: #fff;
- box-shadow: 0 1px 4px rgba(0,21,41,.08);
- display: flex;
- align-items: center;
- // padding: 0 8px;
- box-sizing: border-box;
-
- .hamburger-container {
- line-height: 46px;
- height: 100%;
- cursor: pointer;
- transition: background .3s;
- -webkit-tap-highlight-color:transparent;
- display: flex;
- align-items: center;
- flex-shrink: 0;
- margin-right: 8px;
-
- &:hover {
- background: rgba(0, 0, 0, .025)
- }
- }
-
- .breadcrumb-container {
- flex-shrink: 0;
- }
-
- .topmenu-container {
- position: absolute;
- left: 50px;
- }
-
- .topbar-container {
- flex: 1;
- min-width: 0;
- display: flex;
- align-items: center;
- overflow: hidden;
- margin-left: 8px;
- }
-
- .right-menu {
- height: 100%;
- line-height: 50px;
- display: flex;
- align-items: center;
- margin-left: auto;
-
- &:focus {
- outline: none;
- }
-
- .right-menu-item {
- display: inline-block;
- padding: 0 8px;
- height: 100%;
- font-size: 18px;
- color: #5a5e66;
- vertical-align: text-bottom;
-
- &.hover-effect {
- cursor: pointer;
- transition: background .3s;
-
- &:hover {
- background: rgba(0, 0, 0, .025)
- }
- }
- }
-
- .avatar-container {
- margin-right: 0px;
- padding-right: 0px;
-
- .avatar-wrapper {
- margin-top: 10px;
- right: 8px;
- position: relative;
-
- .user-avatar {
- cursor: pointer;
- width: 30px;
- height: 30px;
- border-radius: 50%;
- }
-
- .user-nickname{
- position: relative;
- bottom: 10px;
- left: 2px;
- font-size: 14px;
- font-weight: bold;
- }
-
- .el-icon-caret-bottom {
- cursor: pointer;
- position: absolute;
- right: -20px;
- top: 25px;
- font-size: 12px;
- }
- }
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue
deleted file mode 100644
index 779ab64..0000000
--- a/ruoyi-ui/src/layout/components/Settings/index.vue
+++ /dev/null
@@ -1,430 +0,0 @@
-<template>
- <el-drawer size="280px" :visible="showSettings" :with-header="false" :append-to-body="true" :before-close="closeSetting" :lock-scroll="false">
- <div class="drawer-container">
- <div>
- <div class="setting-drawer-content">
- <div class="setting-drawer-title">
- <h3 class="drawer-title">菜单导航设置</h3>
- </div>
- <div class="nav-wrap">
- <el-tooltip content="左侧菜单" placement="bottom">
- <div class="item left" @click="handleNavType(1)" :style="{'--theme': theme}" :class="{ activeItem: navType == 1 }">
- <b></b><b></b>
- </div>
- </el-tooltip>
-
- <el-tooltip content="混合菜单" placement="bottom">
- <div class="item mix" @click="handleNavType(2)" :style="{'--theme': theme}" :class="{ activeItem: navType == 2 }">
- <b></b><b></b>
- </div>
- </el-tooltip>
- <el-tooltip content="顶部菜单" placement="bottom">
- <div class="item top" @click="handleNavType(3)" :style="{'--theme': theme}" :class="{ activeItem: navType == 3 }">
- <b></b><b></b>
- </div>
- </el-tooltip>
- </div>
- <div class="setting-drawer-title">
- <h3 class="drawer-title">主题风格设置</h3>
- </div>
- <div class="setting-drawer-block-checbox">
- <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
- <img src="@/assets/images/dark.svg" alt="dark">
- <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
- <i aria-label="图标: check" class="anticon anticon-check">
- <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
- <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
- </svg>
- </i>
- </div>
- </div>
- <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
- <img src="@/assets/images/light.svg" alt="light">
- <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
- <i aria-label="图标: check" class="anticon anticon-check">
- <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
- <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
- </svg>
- </i>
- </div>
- </div>
- </div>
-
- <div class="drawer-item">
- <span>主题颜色</span>
- <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
- </div>
- </div>
-
- <el-divider/>
-
- <h3 class="drawer-title">系统布局配置</h3>
-
- <div class="drawer-item">
- <span>开启页签</span>
- <el-switch v-model="tagsView" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>持久化标签页</span>
- <el-switch v-model="tagsViewPersist" :disabled="!tagsView" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>显示页签图标</span>
- <el-switch v-model="tagsIcon" :disabled="!tagsView" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>标签页样式</span>
- <el-radio-group v-model="tagsViewStyle" :disabled="!tagsView" size="mini" class="drawer-switch">
- <el-radio-button label="card">卡片</el-radio-button>
- <el-radio-button label="chrome">谷歌</el-radio-button>
- </el-radio-group>
- </div>
-
- <div class="drawer-item">
- <span>固定 Header</span>
- <el-switch v-model="fixedHeader" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>显示 Logo</span>
- <el-switch v-model="sidebarLogo" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>动态标题</span>
- <el-switch v-model="dynamicTitle" class="drawer-switch" />
- </div>
-
- <div class="drawer-item">
- <span>底部版权</span>
- <el-switch v-model="footerVisible" class="drawer-switch" />
- </div>
-
- <el-divider/>
-
- <el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
- <el-button size="small" plain icon="el-icon-refresh" @click="resetSetting">重置配置</el-button>
- </div>
- </div>
- </el-drawer>
-</template>
-
-<script>
-import ThemePicker from '@/components/ThemePicker'
-
-export default {
- components: { ThemePicker },
- expose: ['openSetting'],
- data() {
- return {
- theme: this.$store.state.settings.theme,
- sideTheme: this.$store.state.settings.sideTheme,
- navType: this.$store.state.settings.navType,
- showSettings: false
- }
- },
- computed: {
- fixedHeader: {
- get() {
- return this.$store.state.settings.fixedHeader
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'fixedHeader',
- value: val
- })
- }
- },
- tagsViewPersist: {
- get() {
- return this.$store.state.settings.tagsViewPersist
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'tagsViewPersist',
- value: val
- })
- }
- },
- tagsView: {
- get() {
- return this.$store.state.settings.tagsView
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'tagsView',
- value: val
- })
- }
- },
- tagsIcon: {
- get() {
- return this.$store.state.settings.tagsIcon
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'tagsIcon',
- value: val
- })
- }
- },
- tagsViewStyle: {
- get() {
- return this.$store.state.settings.tagsViewStyle
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'tagsViewStyle',
- value: val
- })
- }
- },
- sidebarLogo: {
- get() {
- return this.$store.state.settings.sidebarLogo
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'sidebarLogo',
- value: val
- })
- }
- },
- dynamicTitle: {
- get() {
- return this.$store.state.settings.dynamicTitle
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'dynamicTitle',
- value: val
- })
- this.$store.dispatch('settings/setTitle', this.$store.state.settings.title)
- }
- },
- footerVisible: {
- get() {
- return this.$store.state.settings.footerVisible
- },
- set(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'footerVisible',
- value: val
- })
- }
- }
- },
- watch: {
- navType: {
- handler(val) {
- if (val == 1) {
- this.$store.dispatch("app/toggleSideBarHide", false)
- }
- if (val == 2) {
- }
- if (val == 3) {
- this.$store.dispatch("app/toggleSideBarHide", true)
- }
- if ([1, 3].includes(val)) {
- this.$store.commit("SET_SIDEBAR_ROUTERS",this.$store.state.permission.defaultRoutes)
- }
- },
- immediate: true,
- deep: true
- }
- },
- methods: {
- themeChange(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'theme',
- value: val
- })
- this.theme = val
- },
- handleTheme(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'sideTheme',
- value: val
- })
- this.sideTheme = val
- },
- handleNavType(val) {
- this.$store.dispatch('settings/changeSetting', {
- key: 'navType',
- value: val
- })
- this.navType = val
- },
- openSetting() {
- this.showSettings = true
- },
- closeSetting(){
- this.showSettings = false
- },
- saveSetting() {
- this.$modal.loading("正在保存到本地,请稍候...")
- if (!this.tagsViewPersist) {
- this.$cache.local.remove('tags-view-visited')
- }
- this.$cache.local.set(
- "layout-setting",
- `{
- "navType":${this.navType},
- "tagsView":${this.tagsView},
- "tagsIcon":${this.tagsIcon},
- "tagsViewStyle":"${this.tagsViewStyle}",
- "tagsViewPersist":${this.tagsViewPersist},
- "fixedHeader":${this.fixedHeader},
- "sidebarLogo":${this.sidebarLogo},
- "dynamicTitle":${this.dynamicTitle},
- "footerVisible":${this.footerVisible},
- "sideTheme":"${this.sideTheme}",
- "theme":"${this.theme}"
- }`
- )
- setTimeout(this.$modal.closeLoading(), 1000)
- },
- resetSetting() {
- this.$modal.loading("正在清除设置缓存并刷新,请稍候...")
- this.$cache.local.remove('tags-view-visited')
- this.$cache.local.remove("layout-setting")
- setTimeout("window.location.reload()", 1000)
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.setting-drawer-content {
- .setting-drawer-title {
- margin-bottom: 12px;
- color: rgba(0, 0, 0, .85);
- font-size: 14px;
- line-height: 22px;
- font-weight: bold;
- }
-
- .setting-drawer-block-checbox {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 10px;
- margin-bottom: 20px;
-
- .setting-drawer-block-checbox-item {
- position: relative;
- margin-right: 16px;
- border-radius: 2px;
- cursor: pointer;
-
- img {
- width: 48px;
- height: 48px;
- }
-
- .setting-drawer-block-checbox-selectIcon {
- position: absolute;
- top: 0;
- right: 0;
- width: 100%;
- height: 100%;
- padding-top: 15px;
- padding-left: 24px;
- color: #1890ff;
- font-weight: 700;
- font-size: 14px;
- }
- }
- }
-}
-
-.drawer-container {
- padding: 20px;
- font-size: 14px;
- line-height: 1.5;
- word-wrap: break-word;
-
- .drawer-title {
- margin-bottom: 12px;
- color: rgba(0, 0, 0, .85);
- font-size: 14px;
- line-height: 22px;
- }
-
- .drawer-item {
- color: rgba(0, 0, 0, .65);
- font-size: 14px;
- padding: 12px 0;
- }
-
- .drawer-switch {
- float: right
- }
-}
-
-// 导航模式
-.nav-wrap {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 10px;
- margin-bottom: 20px;
-
- .activeItem {
- border: 2px solid #{'var(--theme)'} !important;
- }
-
- .item {
- position: relative;
- margin-right: 16px;
- cursor: pointer;
- width: 56px;
- height: 48px;
- border-radius: 4px;
- background: #f0f2f5;
- border: 2px solid transparent;
- }
-
- .left {
- b:first-child {
- display: block;
- height: 30%;
- background: #fff;
- }
- b:last-child {
- width: 30%;
- background: #1b2a47;
- position: absolute;
- height: 100%;
- top: 0;
- border-radius: 4px 0 0 4px;
- }
- }
- .mix {
- b:first-child {
- border-radius: 4px 4px 0 0;
- display: block;
- height: 30%;
- background: #1b2a47;
- }
- b:last-child {
- width: 30%;
- background: #1b2a47;
- position: absolute;
- height: 70%;
- border-radius: 0 0 0 4px;
- }
- }
- .top {
- b:first-child {
- display: block;
- height: 30%;
- background: #1b2a47;
- border-radius: 4px 4px 0 0;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js b/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
deleted file mode 100644
index 3d8cc21..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
+++ /dev/null
@@ -1,25 +0,0 @@
-export default {
- computed: {
- device() {
- return this.$store.state.app.device
- }
- },
- mounted() {
- // In order to fix the click on menu on the ios device will trigger the mouseleave bug
- this.fixBugIniOS()
- },
- methods: {
- fixBugIniOS() {
- const $subMenu = this.$refs.subMenu
- if ($subMenu) {
- const handleMouseleave = $subMenu.handleMouseleave
- $subMenu.handleMouseleave = (e) => {
- if (this.device === 'mobile') {
- return
- }
- handleMouseleave(e)
- }
- }
- }
- }
-}
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Item.vue b/ruoyi-ui/src/layout/components/Sidebar/Item.vue
deleted file mode 100644
index 37214aa..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/Item.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-<script>
-export default {
- name: 'MenuItem',
- functional: true,
- props: {
- icon: {
- type: String,
- default: ''
- },
- title: {
- type: String,
- default: ''
- }
- },
- render(h, context) {
- const { icon, title } = context.props
- const vnodes = []
-
- if (icon) {
- vnodes.push(<svg-icon icon-class={icon}/>)
- }
-
- if (title) {
- if (title.length > 5) {
- vnodes.push(<span slot='title' title={(title)}>{(title)}</span>)
- } else {
- vnodes.push(<span slot='title'>{(title)}</span>)
- }
- }
- return vnodes
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Link.vue b/ruoyi-ui/src/layout/components/Sidebar/Link.vue
deleted file mode 100644
index cc62468..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/Link.vue
+++ /dev/null
@@ -1,43 +0,0 @@
-<template>
- <component :is="type" v-bind="linkProps(to)">
- <slot />
- </component>
-</template>
-
-<script>
-import { isExternal } from '@/utils/validate'
-
-export default {
- props: {
- to: {
- type: [String, Object],
- required: true
- }
- },
- computed: {
- isExternal() {
- return isExternal(this.to)
- },
- type() {
- if (this.isExternal) {
- return 'a'
- }
- return 'router-link'
- }
- },
- methods: {
- linkProps(to) {
- if (this.isExternal) {
- return {
- href: to,
- target: '_blank',
- rel: 'noopener'
- }
- }
- return {
- to: to
- }
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
deleted file mode 100644
index feaefaf..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-<template>
- <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' && navType !== 3 ? variables.menuBackground : variables.menuLightBackground }">
- <transition name="sidebarLogoFade">
- <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
- <img v-if="logo" :src="logo" class="sidebar-logo" />
- <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' && navType !== 3 ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
- </router-link>
- <router-link v-else key="expand" class="sidebar-logo-link" to="/">
- <img v-if="logo" :src="logo" class="sidebar-logo" />
- <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' && navType !== 3 ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
- </router-link>
- </transition>
- </div>
-</template>
-
-<script>
-import logoImg from '@/assets/logo/logo.png'
-import variables from '@/assets/styles/variables.scss'
-
-export default {
- name: 'SidebarLogo',
- props: {
- collapse: {
- type: Boolean,
- required: true
- }
- },
- computed: {
- variables() {
- return variables
- },
- sideTheme() {
- return this.$store.state.settings.sideTheme
- },
- navType() {
- return this.$store.state.settings.navType
- }
- },
- data() {
- return {
- title: process.env.VUE_APP_TITLE,
- logo: logoImg
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.sidebarLogoFade-enter-active {
- transition: opacity 1.5s;
-}
-
-.sidebarLogoFade-enter,
-.sidebarLogoFade-leave-to {
- opacity: 0;
-}
-
-.sidebar-logo-container {
- position: relative;
- height: 50px;
- line-height: 50px;
- background: #2b2f3a;
- text-align: center;
- overflow: hidden;
-
- & .sidebar-logo-link {
- height: 100%;
- width: 100%;
-
- & .sidebar-logo {
- width: 32px;
- height: 32px;
- vertical-align: middle;
- margin-right: 12px;
- }
-
- & .sidebar-title {
- display: inline-block;
- margin: 0;
- color: #fff;
- font-weight: 600;
- line-height: 50px;
- font-size: 14px;
- font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
- vertical-align: middle;
- }
- }
-
- &.collapse {
- .sidebar-logo {
- margin-right: 0px;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue b/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
deleted file mode 100644
index 53cc7b0..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
+++ /dev/null
@@ -1,99 +0,0 @@
-<template>
- <div v-if="!item.hidden">
- <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
- <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
- <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
- <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
- </el-menu-item>
- </app-link>
- </template>
-
- <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
- <template slot="title">
- <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
- </template>
- <sidebar-item
- v-for="(child, index) in item.children"
- :key="child.path + index"
- :is-nest="true"
- :item="child"
- :base-path="resolvePath(child.path)"
- class="nest-menu"
- />
- </el-submenu>
- </div>
-</template>
-
-<script>
-import path from 'path'
-import { isExternal } from '@/utils/validate'
-import Item from './Item'
-import AppLink from './Link'
-import FixiOSBug from './FixiOSBug'
-
-export default {
- name: 'SidebarItem',
- components: { Item, AppLink },
- mixins: [FixiOSBug],
- props: {
- // route object
- item: {
- type: Object,
- required: true
- },
- isNest: {
- type: Boolean,
- default: false
- },
- basePath: {
- type: String,
- default: ''
- }
- },
- data() {
- this.onlyOneChild = null
- return {}
- },
- methods: {
- hasOneShowingChild(children = [], parent) {
- if (!children) {
- children = []
- }
- const showingChildren = children.filter(item => {
- if (item.hidden) {
- return false
- }
- // Temp set(will be used if only has one showing child)
- this.onlyOneChild = item
- return true
- })
-
- // When there is only one child router, the child router is displayed by default
- if (showingChildren.length === 1) {
- return true
- }
-
- // Show parent if there are no child router to display
- if (showingChildren.length === 0) {
- this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
- return true
- }
-
- return false
- },
- resolvePath(routePath, routeQuery) {
- if (isExternal(routePath)) {
- return routePath
- }
- if (isExternal(this.basePath)) {
- return this.basePath
- }
- if (routeQuery) {
- let query = JSON.parse(routeQuery)
- return { path: path.resolve(this.basePath, routePath), query: query }
- }
- return path.resolve(this.basePath, routePath)
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/index.vue b/ruoyi-ui/src/layout/components/Sidebar/index.vue
deleted file mode 100644
index f954bf3..0000000
--- a/ruoyi-ui/src/layout/components/Sidebar/index.vue
+++ /dev/null
@@ -1,57 +0,0 @@
-<template>
- <div :class="['sidebar-theme-wrapper', {'has-logo':showLogo}, settings.sideTheme]" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
- <logo v-if="showLogo" :collapse="isCollapse" />
- <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
- <el-menu
- :default-active="activeMenu"
- :collapse="isCollapse"
- :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
- :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
- :unique-opened="true"
- :active-text-color="settings.theme"
- :collapse-transition="false"
- mode="vertical"
- >
- <sidebar-item
- v-for="(route, index) in sidebarRouters"
- :key="route.path + index"
- :item="route"
- :base-path="route.path"
- />
- </el-menu>
- </el-scrollbar>
- </div>
-</template>
-
-<script>
-import { mapGetters, mapState } from "vuex"
-import Logo from "./Logo"
-import SidebarItem from "./SidebarItem"
-import variables from "@/assets/styles/variables.scss"
-
-export default {
- components: { SidebarItem, Logo },
- computed: {
- ...mapState(["settings"]),
- ...mapGetters(["sidebarRouters", "sidebar"]),
- activeMenu() {
- const route = this.$route
- const { meta, path } = route
- // if set path, the sidebar will highlight the path you set
- if (meta.activeMenu) {
- return meta.activeMenu
- }
- return path
- },
- showLogo() {
- return this.$store.state.settings.sidebarLogo
- },
- variables() {
- return variables
- },
- isCollapse() {
- return !this.sidebar.opened
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
deleted file mode 100644
index 3dbd9ae..0000000
--- a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
+++ /dev/null
@@ -1,149 +0,0 @@
-<template>
- <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
- <slot />
- </el-scrollbar>
-</template>
-
-<script>
-const tagAndTagSpacing = 4
-
-export default {
- name: 'ScrollPane',
- data() {
- return {
- left: 0
- }
- },
- computed: {
- scrollWrapper() {
- return this.$refs.scrollContainer.$refs.wrap
- }
- },
- mounted() {
- this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
- },
- beforeDestroy() {
- this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
- },
- methods: {
- smoothScrollTo(target) {
- const $scrollWrapper = this.scrollWrapper
- const start = $scrollWrapper.scrollLeft
- const distance = target - start
- const duration = 300
- let startTime = null
-
- function ease(t, b, c, d) {
- t /= d / 2
- if (t < 1) return c / 2 * t * t + b
- t--
- return -c / 2 * (t * (t - 2) - 1) + b
- }
-
- const emit = this.$emit.bind(this)
- function step(timestamp) {
- if (!startTime) startTime = timestamp
- const elapsed = timestamp - startTime
- $scrollWrapper.scrollLeft = ease(elapsed, start, distance, duration)
- if (elapsed < duration) {
- requestAnimationFrame(step)
- } else {
- $scrollWrapper.scrollLeft = target
- emit('updateArrows')
- }
- }
-
- requestAnimationFrame(step)
- },
- handleScroll(e) {
- const eventDelta = e.wheelDelta || -e.deltaY * 40
- const $scrollWrapper = this.scrollWrapper
- $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
- this.$emit('updateArrows')
- },
- emitScroll() {
- this.$emit('scroll')
- this.$emit('updateArrows')
- },
- moveToTarget(currentTag) {
- const $container = this.$refs.scrollContainer.$el
- const $containerWidth = $container.offsetWidth
- const $scrollWrapper = this.scrollWrapper
- const tagList = this.$parent.$refs.tag
-
- let firstTag = null
- let lastTag = null
-
- if (tagList.length > 0) {
- firstTag = tagList[0]
- lastTag = tagList[tagList.length - 1]
- }
-
- if (firstTag === currentTag) {
- this.smoothScrollTo(0)
- } else if (lastTag === currentTag) {
- this.smoothScrollTo($scrollWrapper.scrollWidth - $containerWidth)
- } else {
- const currentIndex = tagList.findIndex(item => item === currentTag)
- const prevTag = tagList[currentIndex - 1]
- const nextTag = tagList[currentIndex + 1]
- const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
- const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
-
- if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
- this.smoothScrollTo(afterNextTagOffsetLeft - $containerWidth)
- } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
- this.smoothScrollTo(beforePrevTagOffsetLeft)
- }
- }
- },
- // 向左滚动固定距离
- scrollLeft() {
- const $scrollWrapper = this.scrollWrapper
- this.smoothScrollTo(Math.max(0, $scrollWrapper.scrollLeft - 200))
- },
- // 向右滚动固定距离
- scrollRight() {
- const $scrollWrapper = this.scrollWrapper
- const maxScroll = $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth
- this.smoothScrollTo(Math.min(maxScroll, $scrollWrapper.scrollLeft + 200))
- },
- // 直接平滑滚动到最左端
- scrollToStart() {
- this.smoothScrollTo(0)
- },
- // 直接平滑滚动到最右端
- scrollToEnd() {
- const $scrollWrapper = this.scrollWrapper
- this.smoothScrollTo($scrollWrapper.scrollWidth - $scrollWrapper.clientWidth)
- },
- // 获取是否可以继续向左/右滚动
- getScrollState() {
- const $scrollWrapper = this.scrollWrapper
- return {
- canLeft: $scrollWrapper.scrollLeft > 0,
- canRight: $scrollWrapper.scrollLeft < $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth - 1
- }
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.scroll-container {
- white-space: nowrap;
- position: relative;
- overflow: hidden;
- width: 100%;
- ::v-deep {
- .el-scrollbar__bar {
- bottom: 0px;
- }
- .el-scrollbar__wrap {
- height: 34px;
- display: flex;
- align-items: center;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue
deleted file mode 100644
index 5e2e3c6..0000000
--- a/ruoyi-ui/src/layout/components/TagsView/index.vue
+++ /dev/null
@@ -1,760 +0,0 @@
-<template>
- <div id="tags-view-container" class="tags-view-container" :class="{ 'tags-view-container--chrome': tagsViewStyle === 'chrome' }" :style="chromeVars">
- <!-- 左切换箭头 -->
- <span class="tags-nav-btn tags-nav-btn--left" :class="{ disabled: !canScrollLeft }" @click="scrollLeft">
- <i class="el-icon-arrow-left" />
- </span>
-
- <!-- 标签滚动区 -->
- <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll" @updateArrows="updateArrowState">
- <router-link
- v-for="tag in visitedViews"
- ref="tag"
- :key="tag.path"
- :class="{ 'active': isActive(tag), 'has-icon': tagsIcon }"
- :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
- tag="span"
- class="tags-view-item"
- :style="tagActiveStyle(tag)"
- @click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
- @contextmenu.prevent.native="openMenu(tag, $event)"
- >
- <svg-icon v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'" :icon-class="tag.meta.icon" style="margin-right: 3px;" />
- {{ tag.title }}
- <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
- </router-link>
- </scroll-pane>
-
- <!-- 右切换箭头 -->
- <span class="tags-nav-btn tags-nav-btn--right" :class="{ disabled: !canScrollRight }" @click="scrollRight">
- <i class="el-icon-arrow-right" />
- </span>
-
- <!-- 下拉操作菜单 -->
- <el-dropdown class="tags-action-dropdown" trigger="click" placement="bottom-end" @command="handleDropdownCommand">
- <span class="tags-action-btn">
- <i class="el-icon-arrow-down" />
- </span>
- <el-dropdown-menu slot="dropdown" class="tags-dropdown-menu">
- <el-dropdown-item v-if="!isAffix(selectedDropdownTag)" command="close" icon="el-icon-close">关闭当前</el-dropdown-item>
- <el-dropdown-item command="closeOthers" icon="el-icon-circle-close">关闭其他</el-dropdown-item>
- <el-dropdown-item command="closeLeft" :disabled="isFirstView()" icon="el-icon-back">关闭左侧</el-dropdown-item>
- <el-dropdown-item command="closeRight" :disabled="isLastView()" icon="el-icon-right">关闭右侧</el-dropdown-item>
- <el-dropdown-item command="closeAll" icon="el-icon-circle-close">全部关闭</el-dropdown-item>
- <el-dropdown-item command="fullscreen" divided>
- <template v-if="!isFullscreen"><i class="el-icon-full-screen"></i>全屏显示</template>
- <template v-else><i class="el-icon-close"></i>退出全屏</template>
- </el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
-
- <!-- 刷新按钮 -->
- <span class="tags-action-btn tags-refresh-btn" title="刷新页面" @click="refreshSelectedTag(selectedDropdownTag)">
- <i class="el-icon-refresh-right" /> 刷新
- </span>
-
- <!-- 右键上下文菜单 -->
- <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
- <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>
- <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>
- <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li>
- <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li>
- <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li>
- <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li>
- </ul>
- </div>
-</template>
-
-<script>
-import ScrollPane from './ScrollPane'
-import path from 'path'
-
-export default {
- components: { ScrollPane },
- data() {
- return {
- visible: false,
- top: 0,
- left: 0,
- selectedTag: {},
- affixTags: [],
- canScrollLeft: false,
- canScrollRight: false,
- isFullscreen: false,
- hiddenElements: []
- }
- },
- computed: {
- visitedViews() {
- return this.$store.state.tagsView.visitedViews
- },
- routes() {
- return this.$store.state.permission.routes
- },
- theme() {
- return this.$store.state.settings.theme
- },
- tagsIcon() {
- return this.$store.state.settings.tagsIcon
- },
- tagsViewStyle() {
- return this.$store.state.settings.tagsViewStyle
- },
- selectedDropdownTag() {
- return this.visitedViews.find(v => this.isActive(v)) || {}
- },
- chromeVars() {
- if (this.tagsViewStyle !== 'chrome') return {}
- const primary = this.theme || '#409EFF'
- return {
- '--chrome-tab-active-bg': this.mixHexWithWhite(primary, 0.15),
- '--chrome-tab-text-active': primary,
- '--chrome-wing-r': '14px'
- }
- }
- },
- watch: {
- $route() {
- this.addTags()
- this.moveToCurrentTag()
- },
- visible(value) {
- if (value) {
- document.body.addEventListener('click', this.closeMenu)
- } else {
- document.body.removeEventListener('click', this.closeMenu)
- }
- },
- visitedViews() {
- this.$nextTick(() => {
- this.updateArrowState()
- })
- }
- },
- mounted() {
- this.initTags()
- this.addTags()
- window.addEventListener('resize', this.updateArrowState)
- window.addEventListener('keydown', this.handleKeyDown)
- },
- beforeDestroy() {
- window.removeEventListener('resize', this.updateArrowState)
- window.removeEventListener('keydown', this.handleKeyDown)
- },
- methods: {
- handleKeyDown(event) {
- // 当按下Esc键且处于全屏状态时,退出全屏
- if (event.key === 'Escape' && this.isFullscreen) {
- this.toggleFullscreen()
- }
- },
- mixHexWithWhite(hex, ratio) {
- const clean = hex.replace('#', '')
- const r = parseInt(clean.substring(0, 2), 16)
- const g = parseInt(clean.substring(2, 4), 16)
- const b = parseInt(clean.substring(4, 6), 16)
- const mr = Math.round(r * ratio + 255 * (1 - ratio))
- const mg = Math.round(g * ratio + 255 * (1 - ratio))
- const mb = Math.round(b * ratio + 255 * (1 - ratio))
- return `rgb(${mr}, ${mg}, ${mb})`
- },
- isActive(route) {
- return route.path === this.$route.path
- },
- tagActiveStyle(tag) {
- if (!this.isActive(tag) || this.tagsViewStyle !== 'card') return {}
- return {
- "background-color": this.theme,
- "border-color": this.theme
- }
- },
- isAffix(tag) {
- return tag && tag.meta && tag.meta.affix
- },
- isFirstView() {
- try {
- const tag = this.selectedTag && this.selectedTag.fullPath ? this.selectedTag : this.selectedDropdownTag
- return tag.fullPath === '/index' || tag.fullPath === this.visitedViews[1].fullPath
- } catch (err) {
- return false
- }
- },
- isLastView() {
- try {
- const tag = this.selectedTag && this.selectedTag.fullPath ? this.selectedTag : this.selectedDropdownTag
- return tag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
- } catch (err) {
- return false
- }
- },
- filterAffixTags(routes, basePath = '/') {
- let tags = []
- routes.forEach(route => {
- if (route.meta && route.meta.affix) {
- const tagPath = path.resolve(basePath, route.path)
- tags.push({
- fullPath: tagPath,
- path: tagPath,
- name: route.name,
- meta: { ...route.meta }
- })
- }
- if (route.children) {
- const tempTags = this.filterAffixTags(route.children, route.path)
- if (tempTags.length >= 1) {
- tags = [...tags, ...tempTags]
- }
- }
- })
- return tags
- },
- initTags() {
- if (this.$store.state.settings.tagsViewPersist) {
- this.$store.dispatch('tagsView/loadPersistedViews')
- }
- const affixTags = this.affixTags = this.filterAffixTags(this.routes)
- for (const tag of affixTags) {
- if (tag.name) {
- this.$store.dispatch('tagsView/addAffixView', tag)
- }
- }
- },
- addTags() {
- const { name } = this.$route
- if (name) {
- this.$store.dispatch('tagsView/addView', this.$route)
- }
- },
- moveToCurrentTag() {
- const tags = this.$refs.tag
- this.$nextTick(() => {
- for (const tag of tags) {
- if (tag.to.path === this.$route.path) {
- this.$refs.scrollPane.moveToTarget(tag)
- if (tag.to.fullPath !== this.$route.fullPath) {
- this.$store.dispatch('tagsView/updateVisitedView', this.$route)
- }
- break
- }
- }
- })
- },
- scrollLeft() {
- if (!this.canScrollLeft) return
- this.$refs.scrollPane.scrollToStart()
- },
- scrollRight() {
- if (!this.canScrollRight) return
- this.$refs.scrollPane.scrollToEnd()
- },
- updateArrowState() {
- this.$nextTick(() => {
- if (this.$refs.scrollPane) {
- const state = this.$refs.scrollPane.getScrollState()
- this.canScrollLeft = state.canLeft
- this.canScrollRight = state.canRight
- }
- })
- },
- toggleFullscreen() {
- const mainContainer = document.querySelector('.main-container')
- const navbar = document.querySelector('.navbar')
- const sidebar = document.querySelector('.sidebar-container')
- if (!mainContainer) return
-
- if (!this.isFullscreen) {
- mainContainer.classList.add('fullscreen-mode')
- document.body.style.overflow = 'hidden'
- const elementsToHide = [
- { el: navbar, originalDisplay: (navbar && navbar.style.display) || '' },
- { el: sidebar, originalDisplay: (sidebar && sidebar.style.display) || '' }
- ]
- elementsToHide.forEach(item => {
- if (item.el && item.el.style.display !== 'none') {
- item.originalDisplay = item.el.style.display
- item.el.style.display = 'none'
- this.hiddenElements.push(item)
- }
- })
- this.isFullscreen = true
- } else {
- mainContainer.classList.remove('fullscreen-mode')
- document.body.style.overflow = ''
- this.hiddenElements.forEach(item => {
- if (item.el) {
- item.el.style.display = item.originalDisplay
- }
- })
- this.hiddenElements = []
- const btn = document.querySelector('.tags-action-btn')
- if (btn) btn.blur()
- this.isFullscreen = false
- }
- },
- handleDropdownCommand(command) {
- const tag = this.selectedDropdownTag
- this.selectedTag = tag
- switch (command) {
- case 'refresh':
- this.refreshSelectedTag(tag)
- break
- case 'fullscreen':
- this.toggleFullscreen()
- break
- case 'close':
- this.closeSelectedTag(tag)
- break
- case 'closeOthers':
- this.closeOthersTags()
- break
- case 'closeLeft':
- this.closeLeftTags()
- break
- case 'closeRight':
- this.closeRightTags()
- break
- case 'closeAll':
- this.closeAllTags(tag)
- break
- }
- },
- refreshSelectedTag(view) {
- this.$tab.refreshPage(view)
- if (this.$route.meta.link) {
- this.$store.dispatch('tagsView/delIframeView', this.$route)
- }
- },
- closeSelectedTag(view) {
- this.$tab.closePage(view).then(({ visitedViews }) => {
- if (this.isActive(view)) {
- this.toLastView(visitedViews, view)
- }
- })
- },
- closeRightTags() {
- this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
- if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
- this.toLastView(visitedViews)
- }
- })
- },
- closeLeftTags() {
- this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
- if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
- this.toLastView(visitedViews)
- }
- })
- },
- closeOthersTags() {
- this.$router.push(this.selectedTag.fullPath).catch(() => {})
- this.$tab.closeOtherPage(this.selectedTag).then(() => {
- this.moveToCurrentTag()
- })
- },
- closeAllTags(view) {
- this.$tab.closeAllPage().then(({ visitedViews }) => {
- if (this.affixTags.some(tag => tag.path === this.$route.path)) {
- return
- }
- this.toLastView(visitedViews, view)
- })
- },
- toLastView(visitedViews, view) {
- const latestView = visitedViews.slice(-1)[0]
- if (latestView) {
- this.$router.push(latestView.fullPath)
- } else {
- if (view && view.name === 'Dashboard') {
- this.$router.replace({ path: '/redirect' + view.fullPath })
- } else {
- this.$router.push('/')
- }
- }
- },
- openMenu(tag, e) {
- this.left = e.clientX
- this.top = e.clientY
- this.visible = true
- this.selectedTag = tag
- },
- closeMenu() {
- this.visible = false
- },
- handleScroll() {
- this.closeMenu()
- this.updateArrowState()
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-$tags-bar-height: 34px;
-
-.tags-view-container {
- height: $tags-bar-height;
- width: 100%;
- background: #fff;
- border-bottom: 1px solid #d8dce5;
- display: flex;
- align-items: center;
- overflow: hidden;
-
- $btn-width: 28px;
- $btn-color: #71717a;
- $btn-hover-bg: #f0f2f5;
- $btn-hover-color: #303133;
- $btn-disabled-color: #c0c4cc;
- $divider: 1px solid #d8dce5;
-
- .tags-nav-btn {
- flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- width: $btn-width;
- height: $tags-bar-height;
- cursor: pointer;
- color: $btn-color;
- font-size: 13px;
- user-select: none;
- transition: background 0.15s, color 0.15s;
-
- &:hover:not(.disabled) {
- background: $btn-hover-bg;
- color: $btn-hover-color;
- }
-
- &.disabled {
- color: $btn-disabled-color;
- cursor: not-allowed;
- }
-
- &--left { border-right: $divider; }
- &--right { border-left: $divider; }
- }
-
- .tags-view-wrapper {
- flex: 1;
- min-width: 0;
- height: 100%;
-
- .tags-view-item {
- display: inline-block;
- position: relative;
- cursor: pointer;
- height: 26px;
- line-height: 26px;
- border: 1px solid #d8dce5;
- color: #495060;
- background: #fff;
- padding: 0 8px;
- font-size: 12px;
- margin-left: 5px;
- border-radius: 3px;
-
- &:first-of-type { margin-left: 6px; }
- &:last-of-type { margin-right: 15px; }
- }
- }
- &:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active {
- background-color: #42b983;
- color: #fff;
- border-color: #42b983;
- &::before {
- content: '';
- background: #fff;
- display: inline-block;
- width: 8px;
- height: 8px;
- border-radius: 50%;
- position: relative;
- margin-right: 2px;
- }
- }
-
- &:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active.has-icon::before {
- content: none !important;
- }
-
- .tags-action-dropdown {
- flex-shrink: 0;
- display: flex;
- align-items: center;
- }
-
- .tags-action-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- width: $btn-width;
- height: $tags-bar-height;
- cursor: pointer;
- color: $btn-color;
- font-size: 13px;
- border-left: $divider;
- user-select: none;
- transition: background 0.15s, color 0.15s;
-
- &:hover {
- background: $btn-hover-bg;
- color: $btn-hover-color;
- }
- }
-
- .tags-refresh-btn {
- width: 60px;
- }
-
- .contextmenu {
- margin: 0;
- background: #fff;
- z-index: 3000;
- position: fixed;
- list-style-type: none;
- padding: 5px 0;
- border-radius: 4px;
- font-size: 12px;
- font-weight: 400;
- color: #333;
- box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
-
- li {
- margin: 0;
- padding: 7px 16px;
- cursor: pointer;
- &:hover {
- background: #eee;
- }
- }
- }
- &.tags-view-container--chrome {
- --chrome-strip-bg: #ffffff;
- --chrome-strip-border: #e4e7ed;
- --chrome-tab-text: #606266;
-
- overflow: visible;
- background: var(--chrome-strip-bg);
- border-bottom: 1px solid var(--chrome-strip-border);
- align-items: flex-end;
-
- .tags-nav-btn {
- align-self: stretch;
- height: auto;
- min-height: $tags-bar-height;
- border-color: var(--chrome-strip-border);
- }
-
- .tags-action-btn {
- border-color: var(--chrome-strip-border);
- }
-
- .tags-view-wrapper {
- .tags-view-item {
- display: inline-flex !important;
- align-items: center;
- justify-content: center;
- position: relative;
- z-index: 1;
- height: 30px;
- min-height: 30px;
- margin: 0 0 -1px;
- padding: 0 12px;
- font-size: 13px;
- font-weight: 400;
- line-height: 1.2;
- border: none !important;
- border-radius: 0;
- background: transparent !important;
- color: var(--chrome-tab-text) !important;
- padding-top: 0 !important;
- box-shadow: none !important;
- transition: background 0.12s ease, color 0.12s ease, border-radius 0.12s ease;
-
- &::before,
- &::after {
- content: '' !important;
- display: block !important;
- position: absolute;
- bottom: 0;
- width: var(--chrome-wing-r);
- height: var(--chrome-wing-r);
- margin: 0 !important;
- pointer-events: none;
- background: transparent !important;
- border-radius: 0 !important;
- transition: box-shadow 0.12s ease;
- }
-
- &::before {
- left: calc(-1 * var(--chrome-wing-r));
- border-bottom-right-radius: var(--chrome-wing-r) !important;
- box-shadow: none;
- }
-
- &::after {
- right: calc(-1 * var(--chrome-wing-r));
- border-bottom-left-radius: var(--chrome-wing-r) !important;
- box-shadow: none;
- }
-
- &:first-of-type { margin-left: 6px; }
- &:last-of-type { margin-right: 10px; }
-
- &:not(.active) + .tags-view-item:not(.active) {
- border-left: 1px solid #e4e7ed;
- padding-left: 11px;
- }
-
- &:hover:not(.active) {
- background: #f5f7fa !important;
- border-radius: 6px 6px 0 0;
- color: #303133 !important;
- }
-
- &.active {
- height: 31px;
- min-height: 31px;
- padding: 0 14px;
- color: var(--chrome-tab-text-active) !important;
- font-weight: 500;
- background: var(--chrome-tab-active-bg) !important;
- border: none !important;
- border-radius: var(--chrome-wing-r) var(--chrome-wing-r) 0 0;
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
-
- &::before {
- box-shadow: calc(var(--chrome-wing-r) * 0.5) calc(var(--chrome-wing-r) * 0.5) 0 calc(var(--chrome-wing-r) * 0.5) var(--chrome-tab-active-bg);
- }
-
- &::after {
- box-shadow: calc(var(--chrome-wing-r) * -0.5) calc(var(--chrome-wing-r) * 0.5) 0 calc(var(--chrome-wing-r) * 0.5) var(--chrome-tab-active-bg);
- }
- }
- .el-icon-close {
- margin-left: 3px;
- &:before {
- vertical-align: -2px;
- }
- }
- }
- }
- }
-}
-</style>
-
-<style lang="scss">
-.tags-view-wrapper {
- .el-scrollbar {
- height: 100%;
- overflow: hidden;
- }
-
- .el-scrollbar__wrap {
- height: 34px !important;
- display: flex;
- align-items: center;
- overflow-x: auto;
- overflow-y: hidden;
-
- &::-webkit-scrollbar {
- width: 0;
- height: 0;
- }
-
- .tags-view-container:hover & {
- &::-webkit-scrollbar {
- width: 6px;
- height: 6px;
- }
-
- &::-webkit-scrollbar-track {
- background: transparent;
- }
-
- &::-webkit-scrollbar-thumb {
- background-color: rgba(0, 0, 0, 0.2);
- border-radius: 3px;
- transition: background-color 0.2s;
-
- &:hover {
- background-color: rgba(0, 0, 0, 0.4);
- }
- }
- }
-
- scrollbar-width: none;
- -ms-overflow-style: none;
- }
-
- .el-scrollbar__bar {
- opacity: 0;
- transition: opacity 0.3s;
-
- .tags-view-container:hover & {
- opacity: 1;
- }
- }
-
- .tags-view-item {
- .el-icon-close {
- width: 16px;
- height: 16px;
- vertical-align: 2px;
- border-radius: 50%;
- text-align: center;
- transition: all .3s cubic-bezier(.645, .045, .355, 1);
- transform-origin: 100% 50%;
- &:before {
- transform: scale(.6);
- display: inline-block;
- vertical-align: -3px;
- }
- &:hover {
- background-color: #b4bccc;
- color: #fff;
- }
- }
- }
-}
-
-/* 页签全屏模式样式 */
-.main-container.fullscreen-mode {
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- overflow: hidden;
- margin-left: 0 !important;
- transition: none !important;
-}
-
-.main-container.fullscreen-mode .fixed-header {
- display: block !important;
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- width: 100% !important;
- z-index: 1000;
- transition: none !important;
-}
-
-.main-container.fullscreen-mode .fixed-header .navbar {
- display: none !important;
-}
-
-.main-container.fullscreen-mode .app-main {
- position: fixed;
- top: 34px;
- left: 0;
- right: 0;
- bottom: 0;
- margin: 0 !important;
- padding: 0 !important;
- height: calc(100vh - 34px) !important;
- min-height: calc(100vh - 34px) !important;
- overflow: auto;
-}
-</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/layout/components/index.js b/ruoyi-ui/src/layout/components/index.js
deleted file mode 100644
index 7f83004..0000000
--- a/ruoyi-ui/src/layout/components/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export { default as AppMain } from './AppMain'
-export { default as Navbar } from './Navbar'
-export { default as Settings } from './Settings'
-export { default as Sidebar } from './Sidebar/index.vue'
-export { default as TagsView } from './TagsView/index.vue'
diff --git a/ruoyi-ui/src/layout/index.vue b/ruoyi-ui/src/layout/index.vue
deleted file mode 100644
index 64f44c4..0000000
--- a/ruoyi-ui/src/layout/index.vue
+++ /dev/null
@@ -1,115 +0,0 @@
-<template>
- <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33'}">
- <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
- <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
- <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
- <div :class="{'fixed-header':fixedHeader}">
- <navbar @setLayout="setLayout"/>
- <tags-view v-if="needTagsView"/>
- </div>
- <app-main/>
- <settings ref="settingRef"/>
- </div>
- </div>
-</template>
-
-<script>
-import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
-import ResizeMixin from './mixin/ResizeHandler'
-import { mapState } from 'vuex'
-import variables from '@/assets/styles/variables.scss'
-
-export default {
- name: 'Layout',
- components: {
- AppMain,
- Navbar,
- Settings,
- Sidebar,
- TagsView
- },
- mixins: [ResizeMixin],
- computed: {
- ...mapState({
- theme: state => state.settings.theme,
- sideTheme: state => state.settings.sideTheme,
- sidebar: state => state.app.sidebar,
- device: state => state.app.device,
- needTagsView: state => state.settings.tagsView,
- fixedHeader: state => state.settings.fixedHeader
- }),
- classObj() {
- return {
- hideSidebar: !this.sidebar.opened,
- openSidebar: this.sidebar.opened,
- withoutAnimation: this.sidebar.withoutAnimation,
- mobile: this.device === 'mobile'
- }
- },
- variables() {
- return variables
- }
- },
- methods: {
- handleClickOutside() {
- this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
- },
- setLayout() {
- this.$refs.settingRef.openSetting()
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
- @import "~@/assets/styles/mixin.scss";
- @import "~@/assets/styles/variables.scss";
-
- .app-wrapper {
- @include clearfix;
- position: relative;
- height: 100%;
- width: 100%;
-
- &.mobile.openSidebar {
- position: fixed;
- top: 0;
- }
- }
-
- .main-container:has(.fixed-header) {
- height: 100vh;
- overflow: hidden;
- }
-
- .drawer-bg {
- background: #000;
- opacity: 0.3;
- width: 100%;
- top: 0;
- height: 100%;
- position: absolute;
- z-index: 999;
- }
-
- .fixed-header {
- position: fixed;
- top: 0;
- right: 0;
- z-index: 9;
- width: calc(100% - #{$base-sidebar-width});
- transition: width 0.28s;
- }
-
- .hideSidebar .fixed-header {
- width: calc(100% - 54px);
- }
-
- .sidebarHide .fixed-header {
- width: 100%;
- }
-
- .mobile .fixed-header {
- width: 100%;
- }
-</style>
diff --git a/ruoyi-ui/src/layout/mixin/ResizeHandler.js b/ruoyi-ui/src/layout/mixin/ResizeHandler.js
deleted file mode 100644
index b3fc8b2..0000000
--- a/ruoyi-ui/src/layout/mixin/ResizeHandler.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import store from '@/store'
-
-const { body } = document
-const WIDTH = 992 // refer to Bootstrap's responsive design
-
-export default {
- watch: {
- $route(route) {
- if (this.device === 'mobile' && this.sidebar.opened) {
- store.dispatch('app/closeSideBar', { withoutAnimation: false })
- }
- }
- },
- beforeMount() {
- window.addEventListener('resize', this.$_resizeHandler)
- },
- beforeDestroy() {
- window.removeEventListener('resize', this.$_resizeHandler)
- },
- mounted() {
- const isMobile = this.$_isMobile()
- if (isMobile) {
- store.dispatch('app/toggleDevice', 'mobile')
- store.dispatch('app/closeSideBar', { withoutAnimation: true })
- }
- },
- methods: {
- // use $_ for mixins properties
- // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
- $_isMobile() {
- const rect = body.getBoundingClientRect()
- return rect.width - 1 < WIDTH
- },
- $_resizeHandler() {
- if (!document.hidden) {
- const isMobile = this.$_isMobile()
- store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
-
- if (isMobile) {
- store.dispatch('app/closeSideBar', { withoutAnimation: true })
- }
- }
- }
- }
-}
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
deleted file mode 100644
index fab45df..0000000
--- a/ruoyi-ui/src/main.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import Vue from 'vue'
-
-import Cookies from 'js-cookie'
-
-import Element from 'element-ui'
-import './assets/styles/element-variables.scss'
-
-import '@/assets/styles/index.scss' // global css
-import '@/assets/styles/ruoyi.scss' // ruoyi css
-import App from './App'
-import store from './store'
-import router from './router'
-import directive from './directive' // directive
-import plugins from './plugins' // plugins
-import { download } from '@/utils/request'
-
-import './assets/icons' // icon
-import './permission' // permission control
-import { getDicts } from "@/api/system/dict/data"
-import { getConfigKey } from "@/api/system/config"
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"
-// 分页组件
-import Pagination from "@/components/Pagination"
-// 自定义表格工具组件
-import RightToolbar from "@/components/RightToolbar"
-// 富文本组件
-import Editor from "@/components/Editor"
-// 文件上传组件
-import FileUpload from "@/components/FileUpload"
-// 图片上传组件
-import ImageUpload from "@/components/ImageUpload"
-// 图片预览组件
-import ImagePreview from "@/components/ImagePreview"
-// 字典标签组件
-import DictTag from '@/components/DictTag'
-// 字典数据组件
-import DictData from '@/components/DictData'
-
-// 全局方法挂载
-Vue.prototype.getDicts = getDicts
-Vue.prototype.getConfigKey = getConfigKey
-Vue.prototype.parseTime = parseTime
-Vue.prototype.resetForm = resetForm
-Vue.prototype.addDateRange = addDateRange
-Vue.prototype.selectDictLabel = selectDictLabel
-Vue.prototype.selectDictLabels = selectDictLabels
-Vue.prototype.download = download
-Vue.prototype.handleTree = handleTree
-
-// 全局组件挂载
-Vue.component('DictTag', DictTag)
-Vue.component('Pagination', Pagination)
-Vue.component('RightToolbar', RightToolbar)
-Vue.component('Editor', Editor)
-Vue.component('FileUpload', FileUpload)
-Vue.component('ImageUpload', ImageUpload)
-Vue.component('ImagePreview', ImagePreview)
-
-Vue.use(directive)
-Vue.use(plugins)
-DictData.install()
-
-/**
- * If you don't want to use mock-server
- * you want to use MockJs for mock api
- * you can execute: mockXHR()
- *
- * Currently MockJs will be used in the production environment,
- * please remove it before going online! ! !
- */
-
-Vue.use(Element, {
- size: Cookies.get('size') || 'medium' // set element-ui default size
-})
-
-Vue.config.productionTip = false
-
-new Vue({
- el: '#app',
- router,
- store,
- render: h => h(App)
-})
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
deleted file mode 100644
index 1dac250..0000000
--- a/ruoyi-ui/src/permission.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import router from './router'
-import store from './store'
-import { Message } from 'element-ui'
-import NProgress from 'nprogress'
-import 'nprogress/nprogress.css'
-import { getToken } from '@/utils/auth'
-import { isPathMatch } from '@/utils/validate'
-import { isRelogin } from '@/utils/request'
-
-NProgress.configure({ showSpinner: false })
-
-const whiteList = ['/login', '/register']
-
-const isWhiteList = (path) => {
- return whiteList.some(pattern => isPathMatch(pattern, path))
-}
-
-router.beforeEach((to, from, next) => {
- NProgress.start()
- if (getToken()) {
- to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
- const isLock = store.getters.isLock
- /* has token*/
- if (to.path === '/login') {
- next({ path: '/' })
- NProgress.done()
- } else if (isWhiteList(to.path)) {
- next()
- } else if (isLock && to.path !== '/lock') {
- next({ path: '/lock' })
- NProgress.done()
- } else if (!isLock && to.path === '/lock') {
- next({ path: '/' })
- NProgress.done()
- } else {
- if (store.getters.roles.length === 0) {
- isRelogin.show = true
- // 判断当前用户是否已拉取完user_info信息
- store.dispatch('GetInfo').then(() => {
- isRelogin.show = false
- store.dispatch('GenerateRoutes').then(accessRoutes => {
- // 根据roles权限生成可访问的路由表
- router.addRoutes(accessRoutes) // 动态添加可访问路由表
- next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
- })
- }).catch(err => {
- store.dispatch('LogOut').then(() => {
- Message.error(err)
- next({ path: '/' })
- })
- })
- } else {
- next()
- }
- }
- } else {
- // 没有token
- if (isWhiteList(to.path)) {
- // 在免登录白名单,直接进入
- next()
- } else {
- next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页
- NProgress.done()
- }
- }
-})
-
-router.afterEach(() => {
- NProgress.done()
-})
diff --git a/ruoyi-ui/src/plugins/auth.js b/ruoyi-ui/src/plugins/auth.js
deleted file mode 100644
index 6bcce3f..0000000
--- a/ruoyi-ui/src/plugins/auth.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import store from '@/store'
-
-function authPermission(permission) {
- const all_permission = "*:*:*"
- const permissions = store.getters && store.getters.permissions
- if (permission && permission.length > 0) {
- return permissions.some(v => {
- return all_permission === v || v === permission
- })
- } else {
- return false
- }
-}
-
-function authRole(role) {
- const super_admin = "admin"
- const roles = store.getters && store.getters.roles
- if (role && role.length > 0) {
- return roles.some(v => {
- return super_admin === v || v === role
- })
- } else {
- return false
- }
-}
-
-export default {
- // 验证用户是否具备某权限
- hasPermi(permission) {
- return authPermission(permission)
- },
- // 验证用户是否含有指定权限,只需包含其中一个
- hasPermiOr(permissions) {
- return permissions.some(item => {
- return authPermission(item)
- })
- },
- // 验证用户是否含有指定权限,必须全部拥有
- hasPermiAnd(permissions) {
- return permissions.every(item => {
- return authPermission(item)
- })
- },
- // 验证用户是否具备某角色
- hasRole(role) {
- return authRole(role)
- },
- // 验证用户是否含有指定角色,只需包含其中一个
- hasRoleOr(roles) {
- return roles.some(item => {
- return authRole(item)
- })
- },
- // 验证用户是否含有指定角色,必须全部拥有
- hasRoleAnd(roles) {
- return roles.every(item => {
- return authRole(item)
- })
- }
-}
diff --git a/ruoyi-ui/src/plugins/cache.js b/ruoyi-ui/src/plugins/cache.js
deleted file mode 100644
index 4d29dfe..0000000
--- a/ruoyi-ui/src/plugins/cache.js
+++ /dev/null
@@ -1,79 +0,0 @@
-const sessionCache = {
- set (key, value) {
- if (!sessionStorage) {
- return
- }
- if (key != null && value != null) {
- sessionStorage.setItem(key, value)
- }
- },
- get (key) {
- if (!sessionStorage) {
- return null
- }
- if (key == null) {
- return null
- }
- return sessionStorage.getItem(key)
- },
- setJSON (key, jsonValue) {
- if (jsonValue != null) {
- this.set(key, JSON.stringify(jsonValue))
- }
- },
- getJSON (key) {
- const value = this.get(key)
- if (value != null) {
- return JSON.parse(value)
- }
- return null
- },
- remove (key) {
- sessionStorage.removeItem(key)
- }
-}
-const localCache = {
- set (key, value) {
- if (!localStorage) {
- return
- }
- if (key != null && value != null) {
- localStorage.setItem(key, value)
- }
- },
- get (key) {
- if (!localStorage) {
- return null
- }
- if (key == null) {
- return null
- }
- return localStorage.getItem(key)
- },
- setJSON (key, jsonValue) {
- if (jsonValue != null) {
- this.set(key, JSON.stringify(jsonValue))
- }
- },
- getJSON (key) {
- const value = this.get(key)
- if (value != null) {
- return JSON.parse(value)
- }
- return null
- },
- remove (key) {
- localStorage.removeItem(key)
- }
-}
-
-export default {
- /**
- * 会话级缓存
- */
- session: sessionCache,
- /**
- * 本地缓存
- */
- local: localCache
-}
diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
deleted file mode 100644
index f17069e..0000000
--- a/ruoyi-ui/src/plugins/download.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import axios from 'axios'
-import {Loading, Message} from 'element-ui'
-import { saveAs } from 'file-saver'
-import { getToken } from '@/utils/auth'
-import errorCode from '@/utils/errorCode'
-import { blobValidate } from "@/utils/ruoyi"
-
-const baseURL = process.env.VUE_APP_BASE_API
-let downloadLoadingInstance
-
-export default {
- zip(url, name) {
- var url = baseURL + url
- downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
- axios({
- method: 'get',
- url: url,
- responseType: 'blob',
- headers: { 'Authorization': 'Bearer ' + getToken() }
- }).then((res) => {
- const isBlob = blobValidate(res.data)
- if (isBlob) {
- const blob = new Blob([res.data], { type: 'application/zip' })
- this.saveAs(blob, name)
- } else {
- this.printErrMsg(res.data)
- }
- downloadLoadingInstance.close()
- }).catch((r) => {
- console.error(r)
- Message.error('下载文件出现错误,请联系管理员!')
- downloadLoadingInstance.close()
- })
- },
- saveAs(text, name, opts) {
- saveAs(text, name, opts)
- },
- async printErrMsg(data) {
- const resText = await data.text()
- const rspObj = JSON.parse(resText)
- const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
- Message.error(errMsg)
- }
-}
-
diff --git a/ruoyi-ui/src/plugins/index.js b/ruoyi-ui/src/plugins/index.js
deleted file mode 100644
index 9bc6eac..0000000
--- a/ruoyi-ui/src/plugins/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import tab from './tab'
-import auth from './auth'
-import cache from './cache'
-import modal from './modal'
-import download from './download'
-
-export default {
- install(Vue) {
- // 页签操作
- Vue.prototype.$tab = tab
- // 认证对象
- Vue.prototype.$auth = auth
- // 缓存对象
- Vue.prototype.$cache = cache
- // 模态框对象
- Vue.prototype.$modal = modal
- // 下载文件
- Vue.prototype.$download = download
- }
-}
diff --git a/ruoyi-ui/src/plugins/modal.js b/ruoyi-ui/src/plugins/modal.js
deleted file mode 100644
index 99cea2e..0000000
--- a/ruoyi-ui/src/plugins/modal.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Message, MessageBox, Notification, Loading } from 'element-ui'
-
-let loadingInstance
-
-export default {
- // 消息提示
- msg(content) {
- Message.info(content)
- },
- // 错误消息
- msgError(content) {
- Message.error(content)
- },
- // 成功消息
- msgSuccess(content) {
- Message.success(content)
- },
- // 警告消息
- msgWarning(content) {
- Message.warning(content)
- },
- // 弹出提示
- alert(content) {
- MessageBox.alert(content, "系统提示")
- },
- // 错误提示
- alertError(content) {
- MessageBox.alert(content, "系统提示", { type: 'error' })
- },
- // 成功提示
- alertSuccess(content) {
- MessageBox.alert(content, "系统提示", { type: 'success' })
- },
- // 警告提示
- alertWarning(content) {
- MessageBox.alert(content, "系统提示", { type: 'warning' })
- },
- // 通知提示
- notify(content) {
- Notification.info(content)
- },
- // 错误通知
- notifyError(content) {
- Notification.error(content)
- },
- // 成功通知
- notifySuccess(content) {
- Notification.success(content)
- },
- // 警告通知
- notifyWarning(content) {
- Notification.warning(content)
- },
- // 确认窗体
- confirm(content) {
- return MessageBox.confirm(content, "系统提示", {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: "warning",
- })
- },
- // 提交内容
- prompt(content) {
- return MessageBox.prompt(content, "系统提示", {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: "warning",
- })
- },
- // 打开遮罩层
- loading(content) {
- loadingInstance = Loading.service({
- lock: true,
- text: content,
- spinner: "el-icon-loading",
- background: "rgba(0, 0, 0, 0.7)",
- })
- },
- // 关闭遮罩层
- closeLoading() {
- loadingInstance.close()
- }
-}
diff --git a/ruoyi-ui/src/plugins/tab.js b/ruoyi-ui/src/plugins/tab.js
deleted file mode 100644
index 9929de3..0000000
--- a/ruoyi-ui/src/plugins/tab.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import store from '@/store'
-import router from '@/router'
-
-export default {
- // 刷新当前tab页签
- refreshPage(obj) {
- const { path, query, matched } = router.currentRoute
- // 防止在重定向过程中重复刷新
- if (path.startsWith('/redirect/')) {
- return Promise.resolve()
- }
- if (obj === undefined) {
- matched.forEach((m) => {
- if (m.components && m.components.default && m.components.default.name) {
- if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
- obj = { name: m.components.default.name, path: path, query: query }
- }
- }
- })
- }
- return store.dispatch('tagsView/delCachedView', obj).then(() => {
- const { path, query } = obj
- router.replace({
- path: '/redirect' + path,
- query: query
- })
- })
- },
- // 关闭当前tab页签,打开新页签
- closeOpenPage(obj) {
- store.dispatch("tagsView/delView", router.currentRoute)
- if (obj !== undefined) {
- return router.push(obj)
- }
- },
- // 关闭指定tab页签
- closePage(obj) {
- if (obj === undefined) {
- return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => {
- const latestView = visitedViews.slice(-1)[0]
- if (latestView) {
- return router.push(latestView.fullPath)
- }
- return router.push('/')
- })
- }
- return store.dispatch('tagsView/delView', obj)
- },
- // 关闭所有tab页签
- closeAllPage() {
- return store.dispatch('tagsView/delAllViews')
- },
- // 关闭左侧tab页签
- closeLeftPage(obj) {
- return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute)
- },
- // 关闭右侧tab页签
- closeRightPage(obj) {
- return store.dispatch('tagsView/delRightTags', obj || router.currentRoute)
- },
- // 关闭其他tab页签
- closeOtherPage(obj) {
- return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute)
- },
- // 添加tab页签
- openPage(title, url, params) {
- const obj = { path: url, meta: { title: title } }
- store.dispatch('tagsView/addView', obj)
- return router.push({ path: url, query: params })
- },
- // 修改tab页签
- updatePage(obj) {
- return store.dispatch('tagsView/updateVisitedView', obj)
- }
-}
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
deleted file mode 100644
index f4e884a..0000000
--- a/ruoyi-ui/src/router/index.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import Vue from 'vue'
-import Router from 'vue-router'
-
-Vue.use(Router)
-
-/* Layout */
-import Layout from '@/layout'
-
-/**
- * Note: 路由配置项
- *
- * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
- * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
- * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
- * // 若你想不管路由下面的 children 声明的个数都显示你的根路由
- * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
- * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
- * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
- * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
- * roles: ['admin', 'common'] // 访问路由的角色权限
- * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
- * meta : {
- noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
- title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
- icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
- breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
- activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
- }
- */
-
-// 公共路由
-export const constantRoutes = [
- {
- path: '/redirect',
- component: Layout,
- hidden: true,
- children: [
- {
- path: '/redirect/:path(.*)',
- component: () => import('@/views/redirect')
- }
- ]
- },
- {
- path: '/login',
- component: () => import('@/views/login'),
- hidden: true
- },
- {
- path: '/register',
- component: () => import('@/views/register'),
- hidden: true
- },
- {
- path: '/404',
- component: () => import('@/views/error/404'),
- hidden: true
- },
- {
- path: '/401',
- component: () => import('@/views/error/401'),
- hidden: true
- },
- {
- path: '',
- component: Layout,
- redirect: 'index',
- children: [
- {
- path: 'index',
- component: () => import('@/views/index'),
- name: 'Index',
- meta: { title: '首页', icon: 'dashboard', affix: true }
- }
- ]
- },
- {
- path: '/lock',
- component: () => import('@/views/lock'),
- hidden: true,
- meta: { title: '锁定屏幕' }
- },
- {
- path: '/user',
- component: Layout,
- hidden: true,
- redirect: 'noredirect',
- children: [
- {
- path: 'profile',
- component: () => import('@/views/system/user/profile/index'),
- name: 'Profile',
- meta: { title: '个人中心', icon: 'user' }
- }
- ]
- }
-]
-
-// 动态路由,基于用户权限动态去加载
-export const dynamicRoutes = [
- {
- path: '/system/user-auth',
- component: Layout,
- hidden: true,
- permissions: ['system:user:edit'],
- children: [
- {
- path: 'role/:userId(\\d+)',
- component: () => import('@/views/system/user/authRole'),
- name: 'AuthRole',
- meta: { title: '分配角色', activeMenu: '/system/user' }
- }
- ]
- },
- {
- path: '/system/role-auth',
- component: Layout,
- hidden: true,
- permissions: ['system:role:edit'],
- children: [
- {
- path: 'user/:roleId(\\d+)',
- component: () => import('@/views/system/role/authUser'),
- name: 'AuthUser',
- meta: { title: '分配用户', activeMenu: '/system/role' }
- }
- ]
- },
- {
- path: '/system/dict-data',
- component: Layout,
- hidden: true,
- permissions: ['system:dict:list'],
- children: [
- {
- path: 'index/:dictId(\\d+)',
- component: () => import('@/views/system/dict/data'),
- name: 'Data',
- meta: { title: '字典数据', activeMenu: '/system/dict' }
- }
- ]
- },
- {
- path: '/monitor/job-log',
- component: Layout,
- hidden: true,
- permissions: ['monitor:job:list'],
- children: [
- {
- path: 'index/:jobId(\\d+)',
- component: () => import('@/views/monitor/job/log'),
- name: 'JobLog',
- meta: { title: '调度日志', activeMenu: '/monitor/job' }
- }
- ]
- },
- {
- path: '/tool/gen-edit',
- component: Layout,
- hidden: true,
- permissions: ['tool:gen:edit'],
- children: [
- {
- path: 'index/:tableId(\\d+)',
- component: () => import('@/views/tool/gen/editTable'),
- name: 'GenEdit',
- meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
- }
- ]
- }
-]
-
-// 防止连续点击多次路由报错
-let routerPush = Router.prototype.push
-let routerReplace = Router.prototype.replace
-// push
-Router.prototype.push = function push(location) {
- return routerPush.call(this, location).catch(err => err)
-}
-// replace
-Router.prototype.replace = function push(location) {
- return routerReplace.call(this, location).catch(err => err)
-}
-
-export default new Router({
- mode: 'history', // 去掉url中的#
- scrollBehavior: () => ({ y: 0 }),
- routes: constantRoutes
-})
diff --git a/ruoyi-ui/src/settings.js b/ruoyi-ui/src/settings.js
deleted file mode 100644
index edfabf7..0000000
--- a/ruoyi-ui/src/settings.js
+++ /dev/null
@@ -1,66 +0,0 @@
-module.exports = {
- /**
- * 网页标题
- */
- title: process.env.VUE_APP_TITLE,
-
- /**
- * 侧边栏主题 深色主题theme-dark,浅色主题theme-light
- */
- sideTheme: 'theme-dark',
-
- /**
- * 系统布局配置
- */
- showSettings: true,
-
- /**
- * 菜单导航模式 1、纯左侧 2、混合(左侧+顶部) 3、纯顶部
- */
- navType: 1,
-
- /**
- * 是否显示 tagsView
- */
- tagsView: true,
-
- /**
- * 持久化标签页
- */
- tagsViewPersist: false,
-
- /**
- * 显示页签图标
- */
- tagsIcon: false,
-
- /**
- * 标签页样式:card 卡片(默认)、chrome 谷歌浏览器风格
- */
- tagsViewStyle: 'card',
-
- /**
- * 是否固定头部
- */
- fixedHeader: true,
-
- /**
- * 是否显示logo
- */
- sidebarLogo: true,
-
- /**
- * 是否显示动态标题
- */
- dynamicTitle: false,
-
- /**
- * 是否显示底部版权
- */
- footerVisible: false,
-
- /**
- * 底部版权文本内容
- */
- footerContent: 'Copyright © 2018-2026 RuoYi. All Rights Reserved.'
-}
diff --git a/ruoyi-ui/src/store/getters.js b/ruoyi-ui/src/store/getters.js
deleted file mode 100644
index 5545bb1..0000000
--- a/ruoyi-ui/src/store/getters.js
+++ /dev/null
@@ -1,23 +0,0 @@
-const getters = {
- sidebar: state => state.app.sidebar,
- size: state => state.app.size,
- device: state => state.app.device,
- dict: state => state.dict.dict,
- isLock: state => state.lock.isLock,
- lockPath: state => state.lock.lockPath,
- visitedViews: state => state.tagsView.visitedViews,
- cachedViews: state => state.tagsView.cachedViews,
- token: state => state.user.token,
- avatar: state => state.user.avatar,
- id: state => state.user.id,
- name: state => state.user.name,
- nickName: state => state.user.nickName,
- introduction: state => state.user.introduction,
- roles: state => state.user.roles,
- permissions: state => state.user.permissions,
- permission_routes: state => state.permission.routes,
- topbarRouters: state => state.permission.topbarRouters,
- defaultRoutes: state => state.permission.defaultRoutes,
- sidebarRouters: state => state.permission.sidebarRouters
-}
-export default getters
diff --git a/ruoyi-ui/src/store/index.js b/ruoyi-ui/src/store/index.js
deleted file mode 100644
index 293f5d1..0000000
--- a/ruoyi-ui/src/store/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-import app from './modules/app'
-import lock from './modules/lock'
-import dict from './modules/dict'
-import user from './modules/user'
-import tagsView from './modules/tagsView'
-import permission from './modules/permission'
-import settings from './modules/settings'
-import getters from './getters'
-
-Vue.use(Vuex)
-
-const store = new Vuex.Store({
- modules: {
- app,
- lock,
- dict,
- user,
- tagsView,
- permission,
- settings
- },
- getters
-})
-
-export default store
diff --git a/ruoyi-ui/src/store/modules/app.js b/ruoyi-ui/src/store/modules/app.js
deleted file mode 100644
index a7d7dfa..0000000
--- a/ruoyi-ui/src/store/modules/app.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import Cookies from 'js-cookie'
-
-const state = {
- sidebar: {
- opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
- withoutAnimation: false,
- hide: false
- },
- device: 'desktop',
- size: Cookies.get('size') || 'medium'
-}
-
-const mutations = {
- TOGGLE_SIDEBAR: state => {
- if (state.sidebar.hide) {
- return false
- }
- state.sidebar.opened = !state.sidebar.opened
- state.sidebar.withoutAnimation = false
- if (state.sidebar.opened) {
- Cookies.set('sidebarStatus', 1)
- } else {
- Cookies.set('sidebarStatus', 0)
- }
- },
- CLOSE_SIDEBAR: (state, withoutAnimation) => {
- Cookies.set('sidebarStatus', 0)
- state.sidebar.opened = false
- state.sidebar.withoutAnimation = withoutAnimation
- },
- TOGGLE_DEVICE: (state, device) => {
- state.device = device
- },
- SET_SIZE: (state, size) => {
- state.size = size
- Cookies.set('size', size)
- },
- SET_SIDEBAR_HIDE: (state, status) => {
- state.sidebar.hide = status
- }
-}
-
-const actions = {
- toggleSideBar({ commit }) {
- commit('TOGGLE_SIDEBAR')
- },
- closeSideBar({ commit }, { withoutAnimation }) {
- commit('CLOSE_SIDEBAR', withoutAnimation)
- },
- toggleDevice({ commit }, device) {
- commit('TOGGLE_DEVICE', device)
- },
- setSize({ commit }, size) {
- commit('SET_SIZE', size)
- },
- toggleSideBarHide({ commit }, status) {
- commit('SET_SIDEBAR_HIDE', status)
- }
-}
-
-export default {
- namespaced: true,
- state,
- mutations,
- actions
-}
diff --git a/ruoyi-ui/src/store/modules/dict.js b/ruoyi-ui/src/store/modules/dict.js
deleted file mode 100644
index 8b044b6..0000000
--- a/ruoyi-ui/src/store/modules/dict.js
+++ /dev/null
@@ -1,50 +0,0 @@
-const state = {
- dict: new Array()
-}
-const mutations = {
- SET_DICT: (state, { key, value }) => {
- if (key !== null && key !== "") {
- state.dict.push({
- key: key,
- value: value
- })
- }
- },
- REMOVE_DICT: (state, key) => {
- try {
- for (let i = 0; i < state.dict.length; i++) {
- if (state.dict[i].key == key) {
- state.dict.splice(i, 1)
- return true
- }
- }
- } catch (e) {
- }
- },
- CLEAN_DICT: (state) => {
- state.dict = new Array()
- }
-}
-
-const actions = {
- // 设置字典
- setDict({ commit }, data) {
- commit('SET_DICT', data)
- },
- // 删除字典
- removeDict({ commit }, key) {
- commit('REMOVE_DICT', key)
- },
- // 清空字典
- cleanDict({ commit }) {
- commit('CLEAN_DICT')
- }
-}
-
-export default {
- namespaced: true,
- state,
- mutations,
- actions
-}
-
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
deleted file mode 100644
index 7311f23..0000000
--- a/ruoyi-ui/src/store/modules/permission.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import auth from '@/plugins/auth'
-import router, { constantRoutes, dynamicRoutes } from '@/router'
-import { getRouters } from '@/api/menu'
-import Layout from '@/layout/index'
-import ParentView from '@/components/ParentView'
-import InnerLink from '@/layout/components/InnerLink'
-
-const permission = {
- state: {
- routes: [],
- addRoutes: [],
- defaultRoutes: [],
- topbarRouters: [],
- sidebarRouters: []
- },
- mutations: {
- SET_ROUTES: (state, routes) => {
- state.addRoutes = routes
- state.routes = constantRoutes.concat(routes)
- },
- SET_DEFAULT_ROUTES: (state, routes) => {
- state.defaultRoutes = constantRoutes.concat(routes)
- },
- SET_TOPBAR_ROUTES: (state, routes) => {
- state.topbarRouters = routes
- },
- SET_SIDEBAR_ROUTERS: (state, routes) => {
- state.sidebarRouters = routes
- },
- },
- actions: {
- // 生成路由
- GenerateRoutes({ commit }) {
- return new Promise(resolve => {
- // 向后端请求路由数据
- getRouters().then(res => {
- const sdata = JSON.parse(JSON.stringify(res.data))
- const rdata = JSON.parse(JSON.stringify(res.data))
- const sidebarRoutes = filterAsyncRouter(sdata)
- const rewriteRoutes = filterAsyncRouter(rdata, false, true)
- const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
- rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
- router.addRoutes(asyncRoutes)
- commit('SET_ROUTES', rewriteRoutes)
- commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
- commit('SET_DEFAULT_ROUTES', sidebarRoutes)
- commit('SET_TOPBAR_ROUTES', sidebarRoutes)
- resolve(rewriteRoutes)
- })
- })
- }
- }
-}
-
-// 遍历后台传来的路由字符串,转换为组件对象
-function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
- return asyncRouterMap.filter(route => {
- if (type && route.children) {
- route.children = filterChildren(route.children)
- }
- if (route.component) {
- // Layout ParentView 组件特殊处理
- if (route.component === 'Layout') {
- route.component = Layout
- } else if (route.component === 'ParentView') {
- route.component = ParentView
- } else if (route.component === 'InnerLink') {
- route.component = InnerLink
- } else {
- route.component = loadView(route.component)
- }
- }
- if (route.children != null && route.children && route.children.length) {
- route.children = filterAsyncRouter(route.children, route, type)
- } else {
- delete route['children']
- delete route['redirect']
- }
- return true
- })
-}
-
-function filterChildren(childrenMap, lastRouter = false) {
- var children = []
- childrenMap.forEach(el => {
- el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path
- if (el.children && el.children.length && el.component === 'ParentView') {
- children = children.concat(filterChildren(el.children, el))
- } else {
- children.push(el)
- }
- })
- return children
-}
-
-// 动态路由遍历,验证是否具备权限
-export function filterDynamicRoutes(routes) {
- const res = []
- routes.forEach(route => {
- if (route.permissions) {
- if (auth.hasPermiOr(route.permissions)) {
- res.push(route)
- }
- } else if (route.roles) {
- if (auth.hasRoleOr(route.roles)) {
- res.push(route)
- }
- }
- })
- return res
-}
-
-export const loadView = (view) => {
- if (process.env.NODE_ENV === 'development') {
- return (resolve) => require([`@/views/${view}`], resolve)
- } else {
- // 使用 import 实现生产环境的路由懒加载
- return () => import(`@/views/${view}`)
- }
-}
-
-export default permission
diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js
deleted file mode 100644
index 873003f..0000000
--- a/ruoyi-ui/src/store/modules/settings.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import defaultSettings from '@/settings'
-import { useDynamicTitle } from '@/utils/dynamicTitle'
-
-const { sideTheme, showSettings, navType, tagsView, tagsViewPersist, tagsIcon, tagsViewStyle, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings
-
-const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
-const state = {
- title: '',
- theme: storageSetting.theme || '#409EFF',
- sideTheme: storageSetting.sideTheme || sideTheme,
- showSettings: showSettings,
- navType: storageSetting.navType === undefined ? navType : storageSetting.navType,
- tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
- tagsViewPersist: storageSetting.tagsViewPersist === undefined ? tagsViewPersist : storageSetting.tagsViewPersist,
- tagsIcon: storageSetting.tagsIcon === undefined ? tagsIcon : storageSetting.tagsIcon,
- tagsViewStyle: storageSetting.tagsViewStyle === undefined ? tagsViewStyle : storageSetting.tagsViewStyle,
- fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
- sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
- dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle,
- footerVisible: storageSetting.footerVisible === undefined ? footerVisible : storageSetting.footerVisible,
- footerContent: footerContent
-}
-const mutations = {
- CHANGE_SETTING: (state, { key, value }) => {
- if (state.hasOwnProperty(key)) {
- state[key] = value
- }
- },
- SET_TITLE: (state, title) => {
- state.title = title
- }
-}
-
-const actions = {
- // 修改布局设置
- changeSetting({ commit }, data) {
- commit('CHANGE_SETTING', data)
- },
- // 设置网页标题
- setTitle({ commit }, title) {
- commit('SET_TITLE', title)
- useDynamicTitle()
- }
-}
-
-export default {
- namespaced: true,
- state,
- mutations,
- actions
-}
-
diff --git a/ruoyi-ui/src/store/modules/tagsView.js b/ruoyi-ui/src/store/modules/tagsView.js
deleted file mode 100644
index d3f52fb..0000000
--- a/ruoyi-ui/src/store/modules/tagsView.js
+++ /dev/null
@@ -1,275 +0,0 @@
-import store from '@/store'
-import cache from '@/plugins/cache'
-
-const PERSIST_KEY = 'tags-view-visited'
-
-function isPersistEnabled() {
- return store.state.settings.tagsViewPersist
-}
-
-function saveVisitedViews(views) {
- if (!isPersistEnabled()) return
- const toSave = views.filter(v => !(v.meta && v.meta.affix)).map(v => ({ path: v.path, fullPath: v.fullPath, name: v.name, title: v.title, query: v.query, meta: v.meta }))
- cache.local.setJSON(PERSIST_KEY, toSave)
-}
-
-function loadVisitedViews() {
- return cache.local.getJSON(PERSIST_KEY) || []
-}
-
-function clearVisitedViews() {
- cache.local.remove(PERSIST_KEY)
-}
-
-const state = {
- visitedViews: [],
- cachedViews: [],
- iframeViews: []
-}
-
-const mutations = {
- ADD_IFRAME_VIEW: (state, view) => {
- if (state.iframeViews.some(v => v.path === view.path)) return
- state.iframeViews.push(
- Object.assign({}, view, {
- title: view.meta.title || 'no-name'
- })
- )
- },
- ADD_VISITED_VIEW: (state, view) => {
- if (state.visitedViews.some(v => v.path === view.path)) return
- state.visitedViews.push(
- Object.assign({}, view, {
- title: view.meta.title || 'no-name'
- })
- )
- saveVisitedViews(state.visitedViews)
- },
- ADD_VISITED_VIEW_FIRST: (state, view) => {
- if (state.visitedViews.some(v => v.path === view.path)) return
- state.visitedViews.unshift(
- Object.assign({}, view, {
- title: view.meta.title || 'no-name'
- })
- )
- },
- ADD_CACHED_VIEW: (state, view) => {
- if (state.cachedViews.includes(view.name)) return
- if (view.meta && !view.meta.noCache) {
- state.cachedViews.push(view.name)
- }
- },
- DEL_VISITED_VIEW: (state, view) => {
- for (const [i, v] of state.visitedViews.entries()) {
- if (v.path === view.path) {
- state.visitedViews.splice(i, 1)
- break
- }
- }
- state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
- saveVisitedViews(state.visitedViews)
- },
- DEL_IFRAME_VIEW: (state, view) => {
- state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
- },
- DEL_CACHED_VIEW: (state, view) => {
- const index = state.cachedViews.indexOf(view.name)
- index > -1 && state.cachedViews.splice(index, 1)
- },
-
- DEL_OTHERS_VISITED_VIEWS: (state, view) => {
- state.visitedViews = state.visitedViews.filter(v => {
- return v.meta.affix || v.path === view.path
- })
- state.iframeViews = state.iframeViews.filter(item => item.path === view.path)
- saveVisitedViews(state.visitedViews)
- },
- DEL_OTHERS_CACHED_VIEWS: (state, view) => {
- const index = state.cachedViews.indexOf(view.name)
- if (index > -1) {
- state.cachedViews = state.cachedViews.slice(index, index + 1)
- } else {
- state.cachedViews = []
- }
- },
- DEL_ALL_VISITED_VIEWS: state => {
- // keep affix tags
- const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
- state.visitedViews = affixTags
- state.iframeViews = []
- clearVisitedViews()
- },
- DEL_ALL_CACHED_VIEWS: state => {
- state.cachedViews = []
- },
- UPDATE_VISITED_VIEW: (state, view) => {
- for (let v of state.visitedViews) {
- if (v.path === view.path) {
- v = Object.assign(v, view)
- break
- }
- }
- },
- DEL_RIGHT_VIEWS: (state, view) => {
- const index = state.visitedViews.findIndex(v => v.path === view.path)
- if (index === -1) {
- return
- }
- state.visitedViews = state.visitedViews.filter((item, idx) => {
- if (idx <= index || (item.meta && item.meta.affix)) {
- return true
- }
- const i = state.cachedViews.indexOf(item.name)
- if (i > -1) {
- state.cachedViews.splice(i, 1)
- }
- if(item.meta.link) {
- const fi = state.iframeViews.findIndex(v => v.path === item.path)
- state.iframeViews.splice(fi, 1)
- }
- return false
- })
- saveVisitedViews(state.visitedViews)
- },
- DEL_LEFT_VIEWS: (state, view) => {
- const index = state.visitedViews.findIndex(v => v.path === view.path)
- if (index === -1) {
- return
- }
- state.visitedViews = state.visitedViews.filter((item, idx) => {
- if (idx >= index || (item.meta && item.meta.affix)) {
- return true
- }
- const i = state.cachedViews.indexOf(item.name)
- if (i > -1) {
- state.cachedViews.splice(i, 1)
- }
- if(item.meta.link) {
- const fi = state.iframeViews.findIndex(v => v.path === item.path)
- state.iframeViews.splice(fi, 1)
- }
- return false
- })
- saveVisitedViews(state.visitedViews)
- }
-}
-
-const actions = {
- addView({ dispatch }, view) {
- dispatch('addVisitedView', view)
- dispatch('addCachedView', view)
- },
- addIframeView({ commit }, view) {
- commit('ADD_IFRAME_VIEW', view)
- },
- addVisitedView({ commit }, view) {
- commit('ADD_VISITED_VIEW', view)
- },
- addAffixView({ commit }, view) {
- commit('ADD_VISITED_VIEW_FIRST', view)
- },
- addCachedView({ commit }, view) {
- commit('ADD_CACHED_VIEW', view)
- },
- delView({ dispatch, state }, view) {
- return new Promise(resolve => {
- dispatch('delVisitedView', view)
- dispatch('delCachedView', view)
- resolve({
- visitedViews: [...state.visitedViews],
- cachedViews: [...state.cachedViews]
- })
- })
- },
- delVisitedView({ commit, state }, view) {
- return new Promise(resolve => {
- commit('DEL_VISITED_VIEW', view)
- resolve([...state.visitedViews])
- })
- },
- delIframeView({ commit, state }, view) {
- return new Promise(resolve => {
- commit('DEL_IFRAME_VIEW', view)
- resolve([...state.iframeViews])
- })
- },
- delCachedView({ commit, state }, view) {
- return new Promise(resolve => {
- commit('DEL_CACHED_VIEW', view)
- resolve([...state.cachedViews])
- })
- },
- delOthersViews({ dispatch, state }, view) {
- return new Promise(resolve => {
- dispatch('delOthersVisitedViews', view)
- dispatch('delOthersCachedViews', view)
- resolve({
- visitedViews: [...state.visitedViews],
- cachedViews: [...state.cachedViews]
- })
- })
- },
- delOthersVisitedViews({ commit, state }, view) {
- return new Promise(resolve => {
- commit('DEL_OTHERS_VISITED_VIEWS', view)
- resolve([...state.visitedViews])
- })
- },
- delOthersCachedViews({ commit, state }, view) {
- return new Promise(resolve => {
- commit('DEL_OTHERS_CACHED_VIEWS', view)
- resolve([...state.cachedViews])
- })
- },
- delAllViews({ dispatch, state }, view) {
- return new Promise(resolve => {
- dispatch('delAllVisitedViews', view)
- dispatch('delAllCachedViews', view)
- resolve({
- visitedViews: [...state.visitedViews],
- cachedViews: [...state.cachedViews]
- })
- })
- },
- delAllVisitedViews({ commit, state }) {
- return new Promise(resolve => {
- commit('DEL_ALL_VISITED_VIEWS')
- resolve([...state.visitedViews])
- })
- },
- delAllCachedViews({ commit, state }) {
- return new Promise(resolve => {
- commit('DEL_ALL_CACHED_VIEWS')
- resolve([...state.cachedViews])
- })
- },
- updateVisitedView({ commit }, view) {
- commit('UPDATE_VISITED_VIEW', view)
- },
- delRightTags({ commit }, view) {
- return new Promise(resolve => {
- commit('DEL_RIGHT_VIEWS', view)
- resolve([...state.visitedViews])
- })
- },
- delLeftTags({ commit }, view) {
- return new Promise(resolve => {
- commit('DEL_LEFT_VIEWS', view)
- resolve([...state.visitedViews])
- })
- },
- // 恢复持久化的 tags
- loadPersistedViews({ commit }) {
- const views = loadVisitedViews()
- views.forEach(view => {
- commit('ADD_VISITED_VIEW', view)
- })
- },
-}
-
-export default {
- namespaced: true,
- state,
- mutations,
- actions
-}
diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js
deleted file mode 100644
index 8769ea2..0000000
--- a/ruoyi-ui/src/store/modules/user.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import store from '@/store'
-import router from '@/router'
-import cache from '@/plugins/cache'
-import { MessageBox, } from 'element-ui'
-import { login, logout, getInfo, refreshToken } from '@/api/login'
-import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth'
-import { isEmpty } from "@/utils/validate"
-import defAva from '@/assets/images/profile.jpg'
-
-const user = {
- state: {
- token: getToken(),
- id: '',
- name: '',
- nickName: '',
- avatar: '',
- roles: [],
- permissions: []
- },
-
- mutations: {
- SET_TOKEN: (state, token) => {
- state.token = token
- },
- SET_EXPIRES_IN: (state, time) => {
- state.expires_in = time
- },
- SET_ID: (state, id) => {
- state.id = id
- },
- SET_NAME: (state, name) => {
- state.name = name
- },
- SET_NICK_NAME: (state, nickName) => {
- state.nickName = nickName
- },
- SET_AVATAR: (state, avatar) => {
- state.avatar = avatar
- },
- SET_ROLES: (state, roles) => {
- state.roles = roles
- },
- SET_PERMISSIONS: (state, permissions) => {
- state.permissions = permissions
- }
- },
-
- actions: {
- // 登录
- Login({ commit }, userInfo) {
- const username = userInfo.username.trim()
- const password = userInfo.password
- const code = userInfo.code
- const uuid = userInfo.uuid
- return new Promise((resolve, reject) => {
- login(username, password, code, uuid).then(res => {
- let data = res.data
- setToken(data.access_token)
- commit('SET_TOKEN', data.access_token)
- setExpiresIn(data.expires_in)
- commit('SET_EXPIRES_IN', data.expires_in)
- store.dispatch('lock/unlockScreen')
- resolve()
- }).catch(error => {
- reject(error)
- })
- })
- },
-
- // 获取用户信息
- GetInfo({ commit, state }) {
- return new Promise((resolve, reject) => {
- getInfo().then(res => {
- const user = res.user
- const avatar = (isEmpty(user.avatar)) ? defAva : user.avatar
- if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
- commit('SET_ROLES', res.roles)
- commit('SET_PERMISSIONS', res.permissions)
- } else {
- commit('SET_ROLES', ['ROLE_DEFAULT'])
- }
- commit('SET_ID', user.userId)
- commit('SET_NAME', user.userName)
- commit('SET_NICK_NAME', user.nickName)
- commit('SET_AVATAR', avatar)
- cache.session.set('pwrChrtype', res.pwdChrtype)
- /* 初始密码提示 */
- if(res.isDefaultModifyPwd) {
- MessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
- router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
- }).catch(() => {})
- }
- /* 过期密码提示 */
- if(!res.isDefaultModifyPwd && res.isPasswordExpired) {
- MessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
- router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
- }).catch(() => {})
- }
- resolve(res)
- }).catch(error => {
- reject(error)
- })
- })
- },
-
- // 刷新token
- RefreshToken({commit, state}) {
- return new Promise((resolve, reject) => {
- refreshToken(state.token).then(res => {
- setExpiresIn(res.data)
- commit('SET_EXPIRES_IN', res.data)
- resolve()
- }).catch(error => {
- reject(error)
- })
- })
- },
-
- // 退出系统
- LogOut({ commit, state }) {
- return new Promise((resolve, reject) => {
- logout(state.token).then(() => {
- commit('SET_TOKEN', '')
- commit('SET_ROLES', [])
- commit('SET_PERMISSIONS', [])
- removeToken()
- resolve()
- }).catch(error => {
- reject(error)
- })
- })
- },
-
- // 前端 登出
- FedLogOut({ commit }) {
- return new Promise(resolve => {
- commit('SET_TOKEN', '')
- removeToken()
- resolve()
- })
- }
- }
-}
-
-export default user
diff --git a/ruoyi-ui/src/utils/auth.js b/ruoyi-ui/src/utils/auth.js
deleted file mode 100644
index 7fa7559..0000000
--- a/ruoyi-ui/src/utils/auth.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import Cookies from 'js-cookie'
-
-const TokenKey = 'Admin-Token'
-
-const ExpiresInKey = 'Admin-Expires-In'
-
-export function getToken() {
- return Cookies.get(TokenKey)
-}
-
-export function setToken(token) {
- return Cookies.set(TokenKey, token)
-}
-
-export function removeToken() {
- return Cookies.remove(TokenKey)
-}
-
-export function getExpiresIn() {
- return Cookies.get(ExpiresInKey) || -1
-}
-
-export function setExpiresIn(time) {
- return Cookies.set(ExpiresInKey, time)
-}
-
-export function removeExpiresIn() {
- return Cookies.remove(ExpiresInKey)
-}
diff --git a/ruoyi-ui/src/utils/dict/Dict.js b/ruoyi-ui/src/utils/dict/Dict.js
deleted file mode 100644
index e97d794..0000000
--- a/ruoyi-ui/src/utils/dict/Dict.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import Vue from 'vue'
-import { mergeRecursive } from "@/utils/ruoyi"
-import DictMeta from './DictMeta'
-import DictData from './DictData'
-
-const DEFAULT_DICT_OPTIONS = {
- types: [],
-}
-
-/**
- * @classdesc 字典
- * @property {Object} label 标签对象,内部属性名为字典类型名称
- * @property {Object} dict 字段数组,内部属性名为字典类型名称
- * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
- */
-export default class Dict {
- constructor() {
- this.owner = null
- this.label = {}
- this.type = {}
- }
-
- init(options) {
- if (options instanceof Array) {
- options = { types: options }
- }
- const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
- if (opts.types === undefined) {
- throw new Error('need dict types')
- }
- const ps = []
- this._dictMetas = opts.types.map(t => DictMeta.parse(t))
- this._dictMetas.forEach(dictMeta => {
- const type = dictMeta.type
- Vue.set(this.label, type, {})
- Vue.set(this.type, type, [])
- if (dictMeta.lazy) {
- return
- }
- ps.push(loadDict(this, dictMeta))
- })
- return Promise.all(ps)
- }
-
- /**
- * 重新加载字典
- * @param {String} type 字典类型
- */
- reloadDict(type) {
- const dictMeta = this._dictMetas.find(e => e.type === type)
- if (dictMeta === undefined) {
- return Promise.reject(`the dict meta of ${type} was not found`)
- }
- return loadDict(this, dictMeta)
- }
-}
-
-/**
- * 加载字典
- * @param {Dict} dict 字典
- * @param {DictMeta} dictMeta 字典元数据
- * @returns {Promise}
- */
-function loadDict(dict, dictMeta) {
- return dictMeta.request(dictMeta)
- .then(response => {
- const type = dictMeta.type
- let dicts = dictMeta.responseConverter(response, dictMeta)
- if (!(dicts instanceof Array)) {
- console.error('the return of responseConverter must be Array.<DictData>')
- dicts = []
- } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
- console.error('the type of elements in dicts must be DictData')
- dicts = []
- }
- dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
- dicts.forEach(d => {
- Vue.set(dict.label[type], d.value, d.label)
- })
- return dicts
- })
-}
diff --git a/ruoyi-ui/src/utils/dict/DictConverter.js b/ruoyi-ui/src/utils/dict/DictConverter.js
deleted file mode 100644
index 576ff54..0000000
--- a/ruoyi-ui/src/utils/dict/DictConverter.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import DictOptions from './DictOptions'
-import DictData from './DictData'
-
-export default function(dict, dictMeta) {
- const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
- const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
- return new DictData(dict[label], dict[value], dict)
-}
-
-/**
- * 确定字典字段
- * @param {DictData} dict
- * @param {...String} fields
- */
-function determineDictField(dict, ...fields) {
- return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
-}
diff --git a/ruoyi-ui/src/utils/dict/DictData.js b/ruoyi-ui/src/utils/dict/DictData.js
deleted file mode 100644
index 37a60d5..0000000
--- a/ruoyi-ui/src/utils/dict/DictData.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * @classdesc 字典数据
- * @property {String} label 标签
- * @property {*} value 标签
- * @property {Object} raw 原始数据
- */
-export default class DictData {
- constructor(label, value, raw) {
- this.label = label
- this.value = value
- this.raw = raw
- }
-}
diff --git a/ruoyi-ui/src/utils/dict/DictMeta.js b/ruoyi-ui/src/utils/dict/DictMeta.js
deleted file mode 100644
index 1f695b1..0000000
--- a/ruoyi-ui/src/utils/dict/DictMeta.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { mergeRecursive } from "@/utils/ruoyi"
-import DictOptions from './DictOptions'
-
-/**
- * @classdesc 字典元数据
- * @property {String} type 类型
- * @property {Function} request 请求
- * @property {String} label 标签字段
- * @property {String} value 值字段
- */
-export default class DictMeta {
- constructor(options) {
- this.type = options.type
- this.request = options.request
- this.responseConverter = options.responseConverter
- this.labelField = options.labelField
- this.valueField = options.valueField
- this.lazy = options.lazy === true
- }
-}
-
-
-/**
- * 解析字典元数据
- * @param {Object} options
- * @returns {DictMeta}
- */
-DictMeta.parse= function(options) {
- let opts = null
- if (typeof options === 'string') {
- opts = DictOptions.metas[options] || {}
- opts.type = options
- } else if (typeof options === 'object') {
- opts = options
- }
- opts = mergeRecursive(DictOptions.metas['*'], opts)
- return new DictMeta(opts)
-}
diff --git a/ruoyi-ui/src/utils/dict/DictOptions.js b/ruoyi-ui/src/utils/dict/DictOptions.js
deleted file mode 100644
index c58bc17..0000000
--- a/ruoyi-ui/src/utils/dict/DictOptions.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import { mergeRecursive } from "@/utils/ruoyi"
-import dictConverter from './DictConverter'
-
-export const options = {
- metas: {
- '*': {
- /**
- * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
- */
- request: (dictMeta) => {
- console.log(`load dict ${dictMeta.type}`)
- return Promise.resolve([])
- },
- /**
- * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
- */
- responseConverter,
- labelField: 'label',
- valueField: 'value',
- },
- },
- /**
- * 默认标签字段
- */
- DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
- /**
- * 默认值字段
- */
- DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
-}
-
-/**
- * 映射字典
- * @param {Object} response 字典数据
- * @param {DictMeta} dictMeta 字典元数据
- * @returns {DictData}
- */
-function responseConverter(response, dictMeta) {
- const dicts = response.content instanceof Array ? response.content : response
- if (dicts === undefined) {
- console.warn(`no dict data of "${dictMeta.type}" found in the response`)
- return []
- }
- return dicts.map(d => dictConverter(d, dictMeta))
-}
-
-export function mergeOptions(src) {
- mergeRecursive(options, src)
-}
-
-export default options
diff --git a/ruoyi-ui/src/utils/dict/index.js b/ruoyi-ui/src/utils/dict/index.js
deleted file mode 100644
index d6fdb80..0000000
--- a/ruoyi-ui/src/utils/dict/index.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import Dict from './Dict'
-import { mergeOptions } from './DictOptions'
-
-export default function(Vue, options) {
- mergeOptions(options)
- Vue.mixin({
- data() {
- if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
- return {}
- }
- const dict = new Dict()
- dict.owner = this
- return {
- dict
- }
- },
- created() {
- if (!(this.dict instanceof Dict)) {
- return
- }
- options.onCreated && options.onCreated(this.dict)
- this.dict.init(this.$options.dicts).then(() => {
- options.onReady && options.onReady(this.dict)
- this.$nextTick(() => {
- this.$emit('dictReady', this.dict)
- if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
- this.$options.methods.onDictReady.call(this, this.dict)
- }
- })
- })
- },
- })
-}
diff --git a/ruoyi-ui/src/utils/errorCode.js b/ruoyi-ui/src/utils/errorCode.js
deleted file mode 100644
index b72d026..0000000
--- a/ruoyi-ui/src/utils/errorCode.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- '401': '认证失败,无法访问系统资源',
- '403': '当前操作没有权限',
- '404': '访问资源不存在',
- 'default': '系统未知错误,请反馈给管理员'
-}
diff --git a/ruoyi-ui/src/utils/generator/config.js b/ruoyi-ui/src/utils/generator/config.js
deleted file mode 100644
index 005140a..0000000
--- a/ruoyi-ui/src/utils/generator/config.js
+++ /dev/null
@@ -1,438 +0,0 @@
-export const formConf = {
- formRef: 'elForm',
- formModel: 'formData',
- size: 'medium',
- labelPosition: 'right',
- labelWidth: 100,
- formRules: 'rules',
- gutter: 15,
- disabled: false,
- span: 24,
- formBtns: true
-}
-
-export const inputComponents = [
- {
- label: '单行文本',
- tag: 'el-input',
- tagIcon: 'input',
- placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- clearable: true,
- prepend: '',
- append: '',
- 'prefix-icon': '',
- 'suffix-icon': '',
- maxlength: null,
- 'show-word-limit': false,
- readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
- },
- {
- label: '多行文本',
- tag: 'el-input',
- tagIcon: 'textarea',
- type: 'textarea',
- placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- autosize: {
- minRows: 4,
- maxRows: 4
- },
- style: { width: '100%' },
- maxlength: null,
- 'show-word-limit': false,
- readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
- },
- {
- label: '密码',
- tag: 'el-input',
- tagIcon: 'password',
- placeholder: '请输入',
- defaultValue: undefined,
- span: 24,
- 'show-password': true,
- labelWidth: null,
- style: { width: '100%' },
- clearable: true,
- prepend: '',
- append: '',
- 'prefix-icon': '',
- 'suffix-icon': '',
- maxlength: null,
- 'show-word-limit': false,
- readonly: false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input'
- },
- {
- label: '计数器',
- tag: 'el-input-number',
- tagIcon: 'number',
- placeholder: '',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- min: undefined,
- max: undefined,
- step: undefined,
- 'step-strictly': false,
- precision: undefined,
- 'controls-position': '',
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
- }
-]
-
-export const selectComponents = [
- {
- label: '下拉选择',
- tag: 'el-select',
- tagIcon: 'select',
- placeholder: '请选择',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- clearable: true,
- disabled: false,
- required: true,
- filterable: false,
- multiple: false,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/select'
- },
- {
- label: '级联选择',
- tag: 'el-cascader',
- tagIcon: 'cascader',
- placeholder: '请选择',
- defaultValue: [],
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- props: {
- props: {
- multiple: false
- }
- },
- 'show-all-levels': true,
- disabled: false,
- clearable: true,
- filterable: false,
- required: true,
- options: [{
- id: 1,
- value: 1,
- label: '选项1',
- children: [{
- id: 2,
- value: 2,
- label: '选项1-1'
- }]
- }],
- dataType: 'dynamic',
- labelKey: 'label',
- valueKey: 'value',
- childrenKey: 'children',
- separator: '/',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
- },
- {
- label: '单选框组',
- tag: 'el-radio-group',
- tagIcon: 'radio',
- defaultValue: undefined,
- span: 24,
- labelWidth: null,
- style: {},
- optionType: 'default',
- border: false,
- size: 'medium',
- disabled: false,
- required: true,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/radio'
- },
- {
- label: '多选框组',
- tag: 'el-checkbox-group',
- tagIcon: 'checkbox',
- defaultValue: [],
- span: 24,
- labelWidth: null,
- style: {},
- optionType: 'default',
- border: false,
- size: 'medium',
- disabled: false,
- required: true,
- options: [{
- label: '选项一',
- value: 1
- }, {
- label: '选项二',
- value: 2
- }],
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
- },
- {
- label: '开关',
- tag: 'el-switch',
- tagIcon: 'switch',
- defaultValue: false,
- span: 24,
- labelWidth: null,
- style: {},
- disabled: false,
- required: true,
- 'active-text': '',
- 'inactive-text': '',
- 'active-color': null,
- 'inactive-color': null,
- 'active-value': true,
- 'inactive-value': false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/switch'
- },
- {
- label: '滑块',
- tag: 'el-slider',
- tagIcon: 'slider',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- disabled: false,
- required: true,
- min: 0,
- max: 100,
- step: 1,
- 'show-stops': false,
- range: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/slider'
- },
- {
- label: '时间选择',
- tag: 'el-time-picker',
- tagIcon: 'time',
- placeholder: '请选择',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- disabled: false,
- clearable: true,
- required: true,
- 'picker-options': {
- selectableRange: '00:00:00-23:59:59'
- },
- format: 'HH:mm:ss',
- 'value-format': 'HH:mm:ss',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
- },
- {
- label: '时间范围',
- tag: 'el-time-picker',
- tagIcon: 'time-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- disabled: false,
- clearable: true,
- required: true,
- 'is-range': true,
- 'range-separator': '至',
- 'start-placeholder': '开始时间',
- 'end-placeholder': '结束时间',
- format: 'HH:mm:ss',
- 'value-format': 'HH:mm:ss',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
- },
- {
- label: '日期选择',
- tag: 'el-date-picker',
- tagIcon: 'date',
- placeholder: '请选择',
- defaultValue: null,
- type: 'date',
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- disabled: false,
- clearable: true,
- required: true,
- format: 'yyyy-MM-dd',
- 'value-format': 'yyyy-MM-dd',
- readonly: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
- },
- {
- label: '日期范围',
- tag: 'el-date-picker',
- tagIcon: 'date-range',
- defaultValue: null,
- span: 24,
- labelWidth: null,
- style: { width: '100%' },
- type: 'daterange',
- 'range-separator': '至',
- 'start-placeholder': '开始日期',
- 'end-placeholder': '结束日期',
- disabled: false,
- clearable: true,
- required: true,
- format: 'yyyy-MM-dd',
- 'value-format': 'yyyy-MM-dd',
- readonly: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
- },
- {
- label: '评分',
- tag: 'el-rate',
- tagIcon: 'rate',
- defaultValue: 0,
- span: 24,
- labelWidth: null,
- style: {},
- max: 5,
- 'allow-half': false,
- 'show-text': false,
- 'show-score': false,
- disabled: false,
- required: true,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/rate'
- },
- {
- label: '颜色选择',
- tag: 'el-color-picker',
- tagIcon: 'color',
- defaultValue: null,
- labelWidth: null,
- 'show-alpha': false,
- 'color-format': '',
- disabled: false,
- required: true,
- size: 'medium',
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
- },
- {
- label: '上传',
- tag: 'el-upload',
- tagIcon: 'upload',
- action: 'https://jsonplaceholder.typicode.com/posts/',
- defaultValue: null,
- labelWidth: null,
- disabled: false,
- required: true,
- accept: '',
- name: 'file',
- 'auto-upload': true,
- showTip: false,
- buttonText: '点击上传',
- fileSize: 2,
- sizeUnit: 'MB',
- 'list-type': 'text',
- multiple: false,
- regList: [],
- changeTag: true,
- document: 'https://element.eleme.cn/#/zh-CN/component/upload'
- }
-]
-
-export const layoutComponents = [
- {
- layout: 'rowFormItem',
- tagIcon: 'row',
- type: 'default',
- justify: 'start',
- align: 'top',
- label: '行容器',
- layoutTree: true,
- children: [],
- document: 'https://element.eleme.cn/#/zh-CN/component/layout'
- },
- {
- layout: 'colFormItem',
- label: '按钮',
- changeTag: true,
- labelWidth: null,
- tag: 'el-button',
- tagIcon: 'button',
- span: 24,
- default: '主要按钮',
- type: 'primary',
- icon: 'el-icon-search',
- size: 'medium',
- disabled: false,
- document: 'https://element.eleme.cn/#/zh-CN/component/button'
- }
-]
-
-// 组件rule的触发方式,无触发方式的组件不生成rule
-export const trigger = {
- 'el-input': 'blur',
- 'el-input-number': 'blur',
- 'el-select': 'change',
- 'el-radio-group': 'change',
- 'el-checkbox-group': 'change',
- 'el-cascader': 'change',
- 'el-time-picker': 'change',
- 'el-date-picker': 'change',
- 'el-rate': 'change'
-}
diff --git a/ruoyi-ui/src/utils/generator/css.js b/ruoyi-ui/src/utils/generator/css.js
deleted file mode 100644
index 0d7f075..0000000
--- a/ruoyi-ui/src/utils/generator/css.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const styles = {
- 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}',
- 'el-upload': '.el-upload__tip{line-height: 1.2;}'
-}
-
-function addCss(cssList, el) {
- const css = styles[el.tag]
- css && cssList.indexOf(css) === -1 && cssList.push(css)
- if (el.children) {
- el.children.forEach(el2 => addCss(cssList, el2))
- }
-}
-
-export function makeUpCss(conf) {
- const cssList = []
- conf.fields.forEach(el => addCss(cssList, el))
- return cssList.join('\n')
-}
diff --git a/ruoyi-ui/src/utils/generator/drawingDefault.js b/ruoyi-ui/src/utils/generator/drawingDefault.js
deleted file mode 100644
index 769f0df..0000000
--- a/ruoyi-ui/src/utils/generator/drawingDefault.js
+++ /dev/null
@@ -1,37 +0,0 @@
-export const drawingDefaultValue = []
-
-export function initDrawingDefaultValue() {
- if (drawingDefaultValue.length === 0) {
- drawingDefaultValue.push({
- layout: 'colFormItem',
- tagIcon: 'input',
- label: '手机号',
- vModel: 'mobile',
- formId: 6,
- tag: 'el-input',
- placeholder: '请输入手机号',
- defaultValue: '',
- span: 24,
- style: {width: '100%'},
- clearable: true,
- prepend: '',
- append: '',
- 'prefix-icon': 'el-icon-mobile',
- 'suffix-icon': '',
- maxlength: 11,
- 'show-word-limit': true,
- readonly: false,
- disabled: false,
- required: true,
- changeTag: true,
- regList: [{
- pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
- message: '手机号格式错误'
- }]
- })
- }
-}
-
-export function cleanDrawingDefaultValue() {
- drawingDefaultValue.splice(0, drawingDefaultValue.length)
-}
diff --git a/ruoyi-ui/src/utils/generator/html.js b/ruoyi-ui/src/utils/generator/html.js
deleted file mode 100644
index f4f619c..0000000
--- a/ruoyi-ui/src/utils/generator/html.js
+++ /dev/null
@@ -1,358 +0,0 @@
-import { trigger } from './config'
-
-let confGlobal
-let someSpanIsNot24
-
-export function dialogWrapper(str) {
- return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Title">
- ${str}
- <div slot="footer">
- <el-button @click="close">取消</el-button>
- <el-button type="primary" @click="handleConfirm">确定</el-button>
- </div>
- </el-dialog>`
-}
-
-export function vueTemplate(str) {
- return `<template>
- <div>
- ${str}
- </div>
- </template>`
-}
-
-export function vueScript(str) {
- return `<script>
- ${str}
- </script>`
-}
-
-export function cssStyle(cssStr) {
- return `<style>
- ${cssStr}
- </style>`
-}
-
-function buildFormTemplate(conf, child, type) {
- let labelPosition = ''
- if (conf.labelPosition !== 'right') {
- labelPosition = `label-position="${conf.labelPosition}"`
- }
- const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
- let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>
- ${child}
- ${buildFromBtns(conf, type)}
- </el-form>`
- if (someSpanIsNot24) {
- str = `<el-row :gutter="${conf.gutter}">
- ${str}
- </el-row>`
- }
- return str
-}
-
-function buildFromBtns(conf, type) {
- let str = ''
- if (conf.formBtns && type === 'file') {
- str = `<el-form-item size="large">
- <el-button type="primary" @click="submitForm">提交</el-button>
- <el-button @click="resetForm">重置</el-button>
- </el-form-item>`
- if (someSpanIsNot24) {
- str = `<el-col :span="24">
- ${str}
- </el-col>`
- }
- }
- return str
-}
-
-// span不为24的用el-col包裹
-function colWrapper(element, str) {
- if (someSpanIsNot24 || element.span !== 24) {
- return `<el-col :span="${element.span}">
- ${str}
- </el-col>`
- }
- return str
-}
-
-const layouts = {
- colFormItem(element) {
- let labelWidth = ''
- if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
- labelWidth = `label-width="${element.labelWidth}px"`
- }
- const required = !trigger[element.tag] && element.required ? 'required' : ''
- const tagDom = tags[element.tag] ? tags[element.tag](element) : null
- let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>
- ${tagDom}
- </el-form-item>`
- str = colWrapper(element, str)
- return str
- },
- rowFormItem(element) {
- const type = element.type === 'default' ? '' : `type="${element.type}"`
- const justify = element.type === 'default' ? '' : `justify="${element.justify}"`
- const align = element.type === 'default' ? '' : `align="${element.align}"`
- const gutter = element.gutter ? `gutter="${element.gutter}"` : ''
- const children = element.children.map(el => layouts[el.layout](el))
- let str = `<el-row ${type} ${justify} ${align} ${gutter}>
- ${children.join('\n')}
- </el-row>`
- str = colWrapper(element, str)
- return str
- }
-}
-
-const tags = {
- 'el-button': el => {
- const {
- tag, disabled
- } = attrBuilder(el)
- const type = el.type ? `type="${el.type}"` : ''
- const icon = el.icon ? `icon="${el.icon}"` : ''
- const size = el.size ? `size="${el.size}"` : ''
- let child = buildElButtonChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`
- },
- 'el-input': el => {
- const {
- disabled, vModel, clearable, placeholder, width
- } = attrBuilder(el)
- const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
- const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
- const readonly = el.readonly ? 'readonly' : ''
- const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''
- const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''
- const showPassword = el['show-password'] ? 'show-password' : ''
- const type = el.type ? `type="${el.type}"` : ''
- const autosize = el.autosize && el.autosize.minRows
- ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`
- : ''
- let child = buildElInputChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`
- },
- 'el-input-number': el => {
- const { disabled, vModel, placeholder } = attrBuilder(el)
- const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
- const min = el.min ? `:min='${el.min}'` : ''
- const max = el.max ? `:max='${el.max}'` : ''
- const step = el.step ? `:step='${el.step}'` : ''
- const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
- const precision = el.precision ? `:precision='${el.precision}'` : ''
-
- return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`
- },
- 'el-select': el => {
- const {
- disabled, vModel, clearable, placeholder, width
- } = attrBuilder(el)
- const filterable = el.filterable ? 'filterable' : ''
- const multiple = el.multiple ? 'multiple' : ''
- let child = buildElSelectChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`
- },
- 'el-radio-group': el => {
- const { disabled, vModel } = attrBuilder(el)
- const size = `size="${el.size}"`
- let child = buildElRadioGroupChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`
- },
- 'el-checkbox-group': el => {
- const { disabled, vModel } = attrBuilder(el)
- const size = `size="${el.size}"`
- const min = el.min ? `:min="${el.min}"` : ''
- const max = el.max ? `:max="${el.max}"` : ''
- let child = buildElCheckboxGroupChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`
- },
- 'el-switch': el => {
- const { disabled, vModel } = attrBuilder(el)
- const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
- const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
- const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
- const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''
- const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
- const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
-
- return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`
- },
- 'el-cascader': el => {
- const {
- disabled, vModel, clearable, placeholder, width
- } = attrBuilder(el)
- const options = el.options ? `:options="${el.vModel}Options"` : ''
- const props = el.props ? `:props="${el.vModel}Props"` : ''
- const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
- const filterable = el.filterable ? 'filterable' : ''
- const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
-
- return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`
- },
- 'el-slider': el => {
- const { disabled, vModel } = attrBuilder(el)
- const min = el.min ? `:min='${el.min}'` : ''
- const max = el.max ? `:max='${el.max}'` : ''
- const step = el.step ? `:step='${el.step}'` : ''
- const range = el.range ? 'range' : ''
- const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
-
- return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`
- },
- 'el-time-picker': el => {
- const {
- disabled, vModel, clearable, placeholder, width
- } = attrBuilder(el)
- const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
- const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
- const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
- const isRange = el['is-range'] ? 'is-range' : ''
- const format = el.format ? `format="${el.format}"` : ''
- const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
- const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
-
- return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`
- },
- 'el-date-picker': el => {
- const {
- disabled, vModel, clearable, placeholder, width
- } = attrBuilder(el)
- const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
- const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
- const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
- const format = el.format ? `format="${el.format}"` : ''
- const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
- const type = el.type === 'date' ? '' : `type="${el.type}"`
- const readonly = el.readonly ? 'readonly' : ''
-
- return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`
- },
- 'el-rate': el => {
- const { disabled, vModel } = attrBuilder(el)
- const max = el.max ? `:max='${el.max}'` : ''
- const allowHalf = el['allow-half'] ? 'allow-half' : ''
- const showText = el['show-text'] ? 'show-text' : ''
- const showScore = el['show-score'] ? 'show-score' : ''
-
- return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`
- },
- 'el-color-picker': el => {
- const { disabled, vModel } = attrBuilder(el)
- const size = `size="${el.size}"`
- const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
- const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
-
- return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`
- },
- 'el-upload': el => {
- const disabled = el.disabled ? ':disabled=\'true\'' : ''
- const action = el.action ? `:action="${el.vModel}Action"` : ''
- const multiple = el.multiple ? 'multiple' : ''
- const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''
- const accept = el.accept ? `accept="${el.accept}"` : ''
- const name = el.name !== 'file' ? `name="${el.name}"` : ''
- const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''
- const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`
- const fileList = `:file-list="${el.vModel}fileList"`
- const ref = `ref="${el.vModel}"`
- let child = buildElUploadChild(el)
-
- if (child) child = `\n${child}\n` // 换行
- return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`
- }
-}
-
-function attrBuilder(el) {
- return {
- vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
- clearable: el.clearable ? 'clearable' : '',
- placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
- width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
- disabled: el.disabled ? ':disabled=\'true\'' : ''
- }
-}
-
-// el-buttin 子级
-function buildElButtonChild(conf) {
- const children = []
- if (conf.default) {
- children.push(conf.default)
- }
- return children.join('\n')
-}
-
-// el-input innerHTML
-function buildElInputChild(conf) {
- const children = []
- if (conf.prepend) {
- children.push(`<template slot="prepend">${conf.prepend}</template>`)
- }
- if (conf.append) {
- children.push(`<template slot="append">${conf.append}</template>`)
- }
- return children.join('\n')
-}
-
-function buildElSelectChild(conf) {
- const children = []
- if (conf.options && conf.options.length) {
- children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)
- }
- return children.join('\n')
-}
-
-function buildElRadioGroupChild(conf) {
- const children = []
- if (conf.options && conf.options.length) {
- const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
- const border = conf.border ? 'border' : ''
- children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
- }
- return children.join('\n')
-}
-
-function buildElCheckboxGroupChild(conf) {
- const children = []
- if (conf.options && conf.options.length) {
- const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
- const border = conf.border ? 'border' : ''
- children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
- }
- return children.join('\n')
-}
-
-function buildElUploadChild(conf) {
- const list = []
- if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')
- else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)
- if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件</div>`)
- return list.join('\n')
-}
-
-export function makeUpHtml(conf, type) {
- const htmlList = []
- confGlobal = conf
- someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
- conf.fields.forEach(el => {
- htmlList.push(layouts[el.layout](el))
- })
- const htmlStr = htmlList.join('\n')
-
- let temp = buildFormTemplate(conf, htmlStr, type)
- if (type === 'dialog') {
- temp = dialogWrapper(temp)
- }
- confGlobal = null
- return temp
-}
diff --git a/ruoyi-ui/src/utils/generator/js.js b/ruoyi-ui/src/utils/generator/js.js
deleted file mode 100644
index 9241b45..0000000
--- a/ruoyi-ui/src/utils/generator/js.js
+++ /dev/null
@@ -1,235 +0,0 @@
-import { exportDefault, titleCase } from '@/utils/index'
-import { trigger } from './config'
-
-const units = {
- KB: '1024',
- MB: '1024 / 1024',
- GB: '1024 / 1024 / 1024'
-}
-let confGlobal
-const inheritAttrs = {
- file: '',
- dialog: 'inheritAttrs: false,'
-}
-
-
-export function makeUpJs(conf, type) {
- confGlobal = conf = JSON.parse(JSON.stringify(conf))
- const dataList = []
- const ruleList = []
- const optionsList = []
- const propsList = []
- const methodList = mixinMethod(type)
- const uploadVarList = []
-
- conf.fields.forEach(el => {
- buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
- })
-
- const script = buildexport(
- conf,
- type,
- dataList.join('\n'),
- ruleList.join('\n'),
- optionsList.join('\n'),
- uploadVarList.join('\n'),
- propsList.join('\n'),
- methodList.join('\n')
- )
- confGlobal = null
- return script
-}
-
-function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
- buildData(el, dataList)
- buildRules(el, ruleList)
-
- if (el.options && el.options.length) {
- buildOptions(el, optionsList)
- if (el.dataType === 'dynamic') {
- const model = `${el.vModel}Options`
- const options = titleCase(model)
- buildOptionMethod(`get${options}`, model, methodList)
- }
- }
-
- if (el.props && el.props.props) {
- buildProps(el, propsList)
- }
-
- if (el.action && el.tag === 'el-upload') {
- uploadVarList.push(
- `${el.vModel}Action: '${el.action}',
- ${el.vModel}fileList: [],`
- )
- methodList.push(buildBeforeUpload(el))
- if (!el['auto-upload']) {
- methodList.push(buildSubmitUpload(el))
- }
- }
-
- if (el.children) {
- el.children.forEach(el2 => {
- buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
- })
- }
-}
-
-function mixinMethod(type) {
- const list = []; const
- minxins = {
- file: confGlobal.formBtns ? {
- submitForm: `submitForm() {
- this.$refs['${confGlobal.formRef}'].validate(valid => {
- if(!valid) return
- // TODO 提交表单
- })
- },`,
- resetForm: `resetForm() {
- this.$refs['${confGlobal.formRef}'].resetFields()
- },`
- } : null,
- dialog: {
- onOpen: 'onOpen() {},',
- onClose: `onClose() {
- this.$refs['${confGlobal.formRef}'].resetFields()
- },`,
- close: `close() {
- this.$emit('update:visible', false)
- },`,
- handleConfirm: `handleConfirm() {
- this.$refs['${confGlobal.formRef}'].validate(valid => {
- if(!valid) return
- this.close()
- })
- },`
- }
- }
-
- const methods = minxins[type]
- if (methods) {
- Object.keys(methods).forEach(key => {
- list.push(methods[key])
- })
- }
-
- return list
-}
-
-function buildData(conf, dataList) {
- if (conf.vModel === undefined) return
- let defaultValue
- if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {
- defaultValue = `'${conf.defaultValue}'`
- } else {
- defaultValue = `${JSON.stringify(conf.defaultValue)}`
- }
- dataList.push(`${conf.vModel}: ${defaultValue},`)
-}
-
-function buildRules(conf, ruleList) {
- if (conf.vModel === undefined) return
- const rules = []
- if (trigger[conf.tag]) {
- if (conf.required) {
- const type = Array.isArray(conf.defaultValue) ? 'type: \'array\',' : ''
- let message = Array.isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder
- if (message === undefined) message = `${conf.label}不能为空`
- rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)
- }
- if (conf.regList && Array.isArray(conf.regList)) {
- conf.regList.forEach(item => {
- if (item.pattern) {
- rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
- }
- })
- }
- ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
- }
-}
-
-function buildOptions(conf, optionsList) {
- if (conf.vModel === undefined) return
- if (conf.dataType === 'dynamic') { conf.options = [] }
- const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`
- optionsList.push(str)
-}
-
-function buildProps(conf, propsList) {
- if (conf.dataType === 'dynamic') {
- conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)
- conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)
- conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)
- }
- const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`
- propsList.push(str)
-}
-
-function buildBeforeUpload(conf) {
- const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
- returnList = []
- if (conf.fileSize) {
- rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
- if(!isRightSize){
- this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
- }`
- returnList.push('isRightSize')
- }
- if (conf.accept) {
- acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
- if(!isAccept){
- this.$message.error('应该选择${conf.accept}类型的文件')
- }`
- returnList.push('isAccept')
- }
- const str = `${conf.vModel}BeforeUpload(file) {
- ${rightSizeCode}
- ${acceptCode}
- return ${returnList.join('&&')}
- },`
- return returnList.length ? str : ''
-}
-
-function buildSubmitUpload(conf) {
- const str = `submitUpload() {
- this.$refs['${conf.vModel}'].submit()
- },`
- return str
-}
-
-function buildOptionMethod(methodName, model, methodList) {
- const str = `${methodName}() {
- // TODO 发起请求获取数据
- this.${model}
- },`
- methodList.push(str)
-}
-
-function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
- const str = `${exportDefault}{
- ${inheritAttrs[type]}
- components: {},
- props: [],
- data () {
- return {
- ${conf.formModel}: {
- ${data}
- },
- ${conf.formRules}: {
- ${rules}
- },
- ${uploadVar}
- ${selectOptions}
- ${props}
- }
- },
- computed: {},
- watch: {},
- created () {},
- mounted () {},
- methods: {
- ${methods}
- }
-}`
- return str
-}
diff --git a/ruoyi-ui/src/utils/generator/render.js b/ruoyi-ui/src/utils/generator/render.js
deleted file mode 100644
index f187029..0000000
--- a/ruoyi-ui/src/utils/generator/render.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import { makeMap } from '@/utils/index'
-
-// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
-const isAttr = makeMap(
- 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
- + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
- + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
- + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
- + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
- + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
- + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
- + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
- + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
- + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
- + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
- + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
- + 'target,title,type,usemap,value,width,wrap'
-)
-
-function vModel(self, dataObject, defaultValue) {
- dataObject.props.value = defaultValue
-
- dataObject.on.input = val => {
- self.$emit('input', val)
- }
-}
-
-const componentChild = {
- 'el-button': {
- default(h, conf, key) {
- return conf[key]
- },
- },
- 'el-input': {
- prepend(h, conf, key) {
- return <template slot="prepend">{conf[key]}</template>
- },
- append(h, conf, key) {
- return <template slot="append">{conf[key]}</template>
- }
- },
- 'el-select': {
- options(h, conf, key) {
- const list = []
- conf.options.forEach(item => {
- list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
- })
- return list
- }
- },
- 'el-radio-group': {
- options(h, conf, key) {
- const list = []
- conf.options.forEach(item => {
- if (conf.optionType === 'button') list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
- else list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
- })
- return list
- }
- },
- 'el-checkbox-group': {
- options(h, conf, key) {
- const list = []
- conf.options.forEach(item => {
- if (conf.optionType === 'button') {
- list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
- } else {
- list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
- }
- })
- return list
- }
- },
- 'el-upload': {
- 'list-type': (h, conf, key) => {
- const list = []
- if (conf['list-type'] === 'picture-card') {
- list.push(<i class="el-icon-plus"></i>)
- } else {
- list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
- }
- if (conf.showTip) {
- list.push(<div slot="tip" class="el-upload__tip">只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件</div>)
- }
- return list
- }
- }
-}
-
-export default {
- render(h) {
- const dataObject = {
- attrs: {},
- props: {},
- on: {},
- style: {}
- }
- const confClone = JSON.parse(JSON.stringify(this.conf))
- const children = []
-
- const childObjs = componentChild[confClone.tag]
- if (childObjs) {
- Object.keys(childObjs).forEach(key => {
- const childFunc = childObjs[key]
- if (confClone[key]) {
- children.push(childFunc(h, confClone, key))
- }
- })
- }
-
- Object.keys(confClone).forEach(key => {
- const val = confClone[key]
- if (key === 'vModel') {
- vModel(this, dataObject, confClone.defaultValue)
- } else if (dataObject[key]) {
- dataObject[key] = val
- } else if (!isAttr(key)) {
- dataObject.props[key] = val
- } else {
- dataObject.attrs[key] = val
- }
- })
- return h(this.conf.tag, dataObject, children)
- },
- props: ['conf']
-}
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
deleted file mode 100644
index cac28dc..0000000
--- a/ruoyi-ui/src/utils/index.js
+++ /dev/null
@@ -1,390 +0,0 @@
-import { parseTime } from './ruoyi'
-
-/**
- * 表格时间格式化
- */
-export function formatDate(cellValue) {
- if (cellValue == null || cellValue == "") return ""
- var date = new Date(cellValue)
- var year = date.getFullYear()
- var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
- var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
- var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
- var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
- var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
- return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
-}
-
-/**
- * @param {number} time
- * @param {string} option
- * @returns {string}
- */
-export function formatTime(time, option) {
- if (('' + time).length === 10) {
- time = parseInt(time) * 1000
- } else {
- time = +time
- }
- const d = new Date(time)
- const now = Date.now()
-
- const diff = (now - d) / 1000
-
- if (diff < 30) {
- return '刚刚'
- } else if (diff < 3600) {
- // less 1 hour
- return Math.ceil(diff / 60) + '分钟前'
- } else if (diff < 3600 * 24) {
- return Math.ceil(diff / 3600) + '小时前'
- } else if (diff < 3600 * 24 * 2) {
- return '1天前'
- }
- if (option) {
- return parseTime(time, option)
- } else {
- return (
- d.getMonth() +
- 1 +
- '月' +
- d.getDate() +
- '日' +
- d.getHours() +
- '时' +
- d.getMinutes() +
- '分'
- )
- }
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function getQueryObject(url) {
- url = url == null ? window.location.href : url
- const search = url.substring(url.lastIndexOf('?') + 1)
- const obj = {}
- const reg = /([^?&=]+)=([^?&=]*)/g
- search.replace(reg, (rs, $1, $2) => {
- const name = decodeURIComponent($1)
- let val = decodeURIComponent($2)
- val = String(val)
- obj[name] = val
- return rs
- })
- return obj
-}
-
-/**
- * @param {string} input value
- * @returns {number} output value
- */
-export function byteLength(str) {
- // returns the byte length of an utf8 string
- let s = str.length
- for (var i = str.length - 1; i >= 0; i--) {
- const code = str.charCodeAt(i)
- if (code > 0x7f && code <= 0x7ff) s++
- else if (code > 0x7ff && code <= 0xffff) s += 2
- if (code >= 0xDC00 && code <= 0xDFFF) i--
- }
- return s
-}
-
-/**
- * @param {Array} actual
- * @returns {Array}
- */
-export function cleanArray(actual) {
- const newArray = []
- for (let i = 0; i < actual.length; i++) {
- if (actual[i]) {
- newArray.push(actual[i])
- }
- }
- return newArray
-}
-
-/**
- * @param {Object} json
- * @returns {Array}
- */
-export function param(json) {
- if (!json) return ''
- return cleanArray(
- Object.keys(json).map(key => {
- if (json[key] === undefined) return ''
- return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
- })
- ).join('&')
-}
-
-/**
- * @param {string} url
- * @returns {Object}
- */
-export function param2Obj(url) {
- const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
- if (!search) {
- return {}
- }
- const obj = {}
- const searchArr = search.split('&')
- searchArr.forEach(v => {
- const index = v.indexOf('=')
- if (index !== -1) {
- const name = v.substring(0, index)
- const val = v.substring(index + 1, v.length)
- obj[name] = val
- }
- })
- return obj
-}
-
-/**
- * @param {string} val
- * @returns {string}
- */
-export function html2Text(val) {
- const div = document.createElement('div')
- div.innerHTML = val
- return div.textContent || div.innerText
-}
-
-/**
- * Merges two objects, giving the last one precedence
- * @param {Object} target
- * @param {(Object|Array)} source
- * @returns {Object}
- */
-export function objectMerge(target, source) {
- if (typeof target !== 'object') {
- target = {}
- }
- if (Array.isArray(source)) {
- return source.slice()
- }
- Object.keys(source).forEach(property => {
- const sourceProperty = source[property]
- if (typeof sourceProperty === 'object') {
- target[property] = objectMerge(target[property], sourceProperty)
- } else {
- target[property] = sourceProperty
- }
- })
- return target
-}
-
-/**
- * @param {HTMLElement} element
- * @param {string} className
- */
-export function toggleClass(element, className) {
- if (!element || !className) {
- return
- }
- let classString = element.className
- const nameIndex = classString.indexOf(className)
- if (nameIndex === -1) {
- classString += '' + className
- } else {
- classString =
- classString.substr(0, nameIndex) +
- classString.substr(nameIndex + className.length)
- }
- element.className = classString
-}
-
-/**
- * @param {string} type
- * @returns {Date}
- */
-export function getTime(type) {
- if (type === 'start') {
- return new Date().getTime() - 3600 * 1000 * 24 * 90
- } else {
- return new Date(new Date().toDateString())
- }
-}
-
-/**
- * @param {Function} func
- * @param {number} wait
- * @param {boolean} immediate
- * @return {*}
- */
-export function debounce(func, wait, immediate) {
- let timeout, args, context, timestamp, result
-
- const later = function() {
- // 据上一次触发时间间隔
- const last = +new Date() - timestamp
-
- // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
- if (last < wait && last > 0) {
- timeout = setTimeout(later, wait - last)
- } else {
- timeout = null
- // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
- if (!immediate) {
- result = func.apply(context, args)
- if (!timeout) context = args = null
- }
- }
- }
-
- return function(...args) {
- context = this
- timestamp = +new Date()
- const callNow = immediate && !timeout
- // 如果延时不存在,重新设定延时
- if (!timeout) timeout = setTimeout(later, wait)
- if (callNow) {
- result = func.apply(context, args)
- context = args = null
- }
-
- return result
- }
-}
-
-/**
- * This is just a simple version of deep copy
- * Has a lot of edge cases bug
- * If you want to use a perfect deep copy, use lodash's _.cloneDeep
- * @param {Object} source
- * @returns {Object}
- */
-export function deepClone(source) {
- if (!source && typeof source !== 'object') {
- throw new Error('error arguments', 'deepClone')
- }
- const targetObj = source.constructor === Array ? [] : {}
- Object.keys(source).forEach(keys => {
- if (source[keys] && typeof source[keys] === 'object') {
- targetObj[keys] = deepClone(source[keys])
- } else {
- targetObj[keys] = source[keys]
- }
- })
- return targetObj
-}
-
-/**
- * @param {Array} arr
- * @returns {Array}
- */
-export function uniqueArr(arr) {
- return Array.from(new Set(arr))
-}
-
-/**
- * @returns {string}
- */
-export function createUniqueString() {
- const timestamp = +new Date() + ''
- const randomNum = parseInt((1 + Math.random()) * 65536) + ''
- return (+(randomNum + timestamp)).toString(32)
-}
-
-/**
- * Check if an element has a class
- * @param {HTMLElement} elm
- * @param {string} cls
- * @returns {boolean}
- */
-export function hasClass(ele, cls) {
- return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
-}
-
-/**
- * Add class to element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function addClass(ele, cls) {
- if (!hasClass(ele, cls)) ele.className += ' ' + cls
-}
-
-/**
- * Remove class from element
- * @param {HTMLElement} elm
- * @param {string} cls
- */
-export function removeClass(ele, cls) {
- if (hasClass(ele, cls)) {
- const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
- ele.className = ele.className.replace(reg, ' ')
- }
-}
-
-export function makeMap(str, expectsLowerCase) {
- const map = Object.create(null)
- const list = str.split(',')
- for (let i = 0; i < list.length; i++) {
- map[list[i]] = true
- }
- return expectsLowerCase
- ? val => map[val.toLowerCase()]
- : val => map[val]
-}
-
-export const exportDefault = 'export default '
-
-export const beautifierConf = {
- html: {
- indent_size: '2',
- indent_char: ' ',
- max_preserve_newlines: '-1',
- preserve_newlines: false,
- keep_array_indentation: false,
- break_chained_methods: false,
- indent_scripts: 'separate',
- brace_style: 'end-expand',
- space_before_conditional: true,
- unescape_strings: false,
- jslint_happy: false,
- end_with_newline: true,
- wrap_line_length: '110',
- indent_inner_html: true,
- comma_first: false,
- e4x: true,
- indent_empty_lines: true
- },
- js: {
- indent_size: '2',
- indent_char: ' ',
- max_preserve_newlines: '-1',
- preserve_newlines: false,
- keep_array_indentation: false,
- break_chained_methods: false,
- indent_scripts: 'normal',
- brace_style: 'end-expand',
- space_before_conditional: true,
- unescape_strings: false,
- jslint_happy: true,
- end_with_newline: true,
- wrap_line_length: '110',
- indent_inner_html: true,
- comma_first: false,
- e4x: true,
- indent_empty_lines: true
- }
-}
-
-// 首字母大小
-export function titleCase(str) {
- return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
-}
-
-// 下划转驼峰
-export function camelCase(str) {
- return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
-}
-
-export function isNumberStr(str) {
- return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
-}
-
diff --git a/ruoyi-ui/src/utils/jsencrypt.js b/ruoyi-ui/src/utils/jsencrypt.js
deleted file mode 100644
index 9f3a280..0000000
--- a/ruoyi-ui/src/utils/jsencrypt.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
-
-// 密钥对生成 http://web.chacuo.net/netrsakeypair
-
-const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' +
- 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
-
-const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
- '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
- 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
- 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
- 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
- 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
- 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
- 'UP8iWi1Qw0Y='
-
-// 加密
-export function encrypt(txt) {
- const encryptor = new JSEncrypt()
- encryptor.setPublicKey(publicKey) // 设置公钥
- return encryptor.encrypt(txt) // 对数据进行加密
-}
-
-// 解密
-export function decrypt(txt) {
- const encryptor = new JSEncrypt()
- encryptor.setPrivateKey(privateKey) // 设置私钥
- return encryptor.decrypt(txt) // 对数据进行解密
-}
-
diff --git a/ruoyi-ui/src/utils/permission.js b/ruoyi-ui/src/utils/permission.js
deleted file mode 100644
index 070d6b8..0000000
--- a/ruoyi-ui/src/utils/permission.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import store from '@/store'
-
-/**
- * 字符权限校验
- * @param {Array} value 校验值
- * @returns {Boolean}
- */
-export function checkPermi(value) {
- if (value && value instanceof Array && value.length > 0) {
- const permissions = store.getters && store.getters.permissions
- const permissionDatas = value
- const all_permission = "*:*:*"
-
- const hasPermission = permissions.some(permission => {
- return all_permission === permission || permissionDatas.includes(permission)
- })
-
- return hasPermission
-
- } else {
- console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
- return false
- }
-}
-
-/**
- * 角色权限校验
- * @param {Array} value 校验值
- * @returns {Boolean}
- */
-export function checkRole(value) {
- if (value && value instanceof Array && value.length > 0) {
- const roles = store.getters && store.getters.roles
- const permissionRoles = value
- const super_admin = "admin"
-
- const hasRole = roles.some(role => {
- return super_admin === role || permissionRoles.includes(role)
- })
-
- return hasRole
-
- } else {
- console.error(`need roles! Like checkRole="['admin','editor']"`)
- return false
- }
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
deleted file mode 100644
index 6798f5d..0000000
--- a/ruoyi-ui/src/utils/request.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import axios from 'axios'
-import { Notification, MessageBox, Message, Loading } from 'element-ui'
-import store from '@/store'
-import { getToken } from '@/utils/auth'
-import errorCode from '@/utils/errorCode'
-import { tansParams, blobValidate } from "@/utils/ruoyi"
-import cache from '@/plugins/cache'
-import { saveAs } from 'file-saver'
-
-let downloadLoadingInstance
-// 是否显示重新登录
-export let isRelogin = { show: false }
-
-axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
-// 创建axios实例
-const service = axios.create({
- // axios中请求配置有baseURL选项,表示请求URL公共部分
- baseURL: process.env.VUE_APP_BASE_API,
- // 超时
- timeout: 10000
-})
-
-// request拦截器
-service.interceptors.request.use(config => {
- // 是否需要设置 token
- const isToken = (config.headers || {}).isToken === false
- // 是否需要防止数据重复提交
- const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
- // 间隔时间(ms),小于此时间视为重复提交
- const interval = (config.headers || {}).interval || 1000
- if (getToken() && !isToken) {
- config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
- }
- // get请求映射params参数
- if (config.method === 'get' && config.params) {
- let url = config.url + '?' + tansParams(config.params)
- url = url.slice(0, -1)
- config.params = {}
- config.url = url
- }
- if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
- const requestObj = {
- url: config.url,
- data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
- time: new Date().getTime()
- }
- const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
- const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
- if (requestSize >= limitSize) {
- console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
- return config
- }
- const sessionObj = cache.session.getJSON('sessionObj')
- if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
- cache.session.setJSON('sessionObj', requestObj)
- } else {
- const s_url = sessionObj.url // 请求地址
- const s_data = sessionObj.data // 请求数据
- const s_time = sessionObj.time // 请求时间
- if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
- const message = '数据正在处理,请勿重复提交'
- console.warn(`[${s_url}]: ` + message)
- return Promise.reject(new Error(message))
- } else {
- cache.session.setJSON('sessionObj', requestObj)
- }
- }
- }
- return config
-}, error => {
- console.log(error)
- Promise.reject(error)
-})
-
-// 响应拦截器
-service.interceptors.response.use(res => {
- // 未设置状态码则默认成功状态
- const code = res.data.code || 200
- // 获取错误信息
- const msg = errorCode[code] || res.data.msg || errorCode['default']
- // 二进制数据则直接返回
- if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
- return res.data
- }
- if (code === 401) {
- if (!isRelogin.show) {
- isRelogin.show = true
- MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
- isRelogin.show = false
- store.dispatch('LogOut').then(() => {
- location.href = '/index'
- })
- }).catch(() => {
- isRelogin.show = false
- })
- }
- return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
- } else if (code === 500) {
- Message({ message: msg, type: 'error' })
- return Promise.reject(new Error(msg))
- } else if (code === 601) {
- Message({ message: msg, type: 'warning' })
- return Promise.reject('error')
- } else if (code !== 200) {
- Notification.error({ title: msg })
- return Promise.reject('error')
- } else {
- return res.data
- }
- },
- error => {
- console.log('err' + error)
- let { message } = error
- if (message == "Network Error") {
- message = "后端接口连接异常"
- } else if (message.includes("timeout")) {
- message = "系统接口请求超时"
- } else if (message.includes("Request failed with status code")) {
- message = "系统接口" + message.slice(-3) + "异常"
- }
- Message({ message: message, type: 'error', duration: 5 * 1000 })
- return Promise.reject(error)
- }
-)
-
-// 通用下载方法
-export function download(url, params, filename, config) {
- downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
- return service.post(url, params, {
- transformRequest: [(params) => { return tansParams(params) }],
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
- responseType: 'blob',
- ...config
- }).then(async (data) => {
- const isBlob = blobValidate(data)
- if (isBlob) {
- const blob = new Blob([data])
- saveAs(blob, filename)
- } else {
- const resText = await data.text()
- const rspObj = JSON.parse(resText)
- const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
- Message.error(errMsg)
- }
- downloadLoadingInstance.close()
- }).catch((r) => {
- console.error(r)
- Message.error('下载文件出现错误,请联系管理员!')
- downloadLoadingInstance.close()
- })
-}
-
-export default service
diff --git a/ruoyi-ui/src/utils/scroll-to.js b/ruoyi-ui/src/utils/scroll-to.js
deleted file mode 100644
index 709fa57..0000000
--- a/ruoyi-ui/src/utils/scroll-to.js
+++ /dev/null
@@ -1,58 +0,0 @@
-Math.easeInOutQuad = function(t, b, c, d) {
- t /= d / 2
- if (t < 1) {
- return c / 2 * t * t + b
- }
- t--
- return -c / 2 * (t * (t - 2) - 1) + b
-}
-
-// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
-var requestAnimFrame = (function() {
- return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
-})()
-
-/**
- * Because it's so fucking difficult to detect the scrolling element, just move them all
- * @param {number} amount
- */
-function move(amount) {
- document.documentElement.scrollTop = amount
- document.body.parentNode.scrollTop = amount
- document.body.scrollTop = amount
-}
-
-function position() {
- return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
-}
-
-/**
- * @param {number} to
- * @param {number} duration
- * @param {Function} callback
- */
-export function scrollTo(to, duration, callback) {
- const start = position()
- const change = to - start
- const increment = 20
- let currentTime = 0
- duration = (typeof (duration) === 'undefined') ? 500 : duration
- var animateScroll = function() {
- // increment the time
- currentTime += increment
- // find the value with the quadratic in-out easing function
- var val = Math.easeInOutQuad(currentTime, start, change, duration)
- // move the document.body
- move(val)
- // do the animation unless its over
- if (currentTime < duration) {
- requestAnimFrame(animateScroll)
- } else {
- if (callback && typeof (callback) === 'function') {
- // the animation is done so lets callback
- callback()
- }
- }
- }
- animateScroll()
-}
diff --git a/ruoyi-ui/src/utils/validate.js b/ruoyi-ui/src/utils/validate.js
deleted file mode 100644
index fddf7ac..0000000
--- a/ruoyi-ui/src/utils/validate.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * 路径匹配器
- * @param {string} pattern
- * @param {string} path
- * @returns {Boolean}
- */
-export function isPathMatch(pattern, path) {
- const regexPattern = pattern
- .replace(/([.+^${}()|\[\]\\])/g, '\\$1')
- .replace(/\*\*/g, '__DOUBLE_STAR__')
- .replace(/\*/g, '[^/]*')
- .replace(/__DOUBLE_STAR__/g, '.*')
- .replace(/\?/g, '[^/]')
- const regex = new RegExp(`^${regexPattern}$`)
- return regex.test(path)
-}
-
-/**
- * 判断value字符串是否为空
- * @param {string} value
- * @returns {Boolean}
- */
-export function isEmpty(value) {
- if (value == null || value == "" || value == undefined || value == "undefined") {
- return true
- }
- return false
-}
-
-/**
- * 判断url是否是http或https
- * @param {string} url
- * @returns {Boolean}
- */
-export function isHttp(url) {
- return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
-}
-
-/**
- * 判断path是否为外链
- * @param {string} path
- * @returns {Boolean}
- */
-export function isExternal(path) {
- return /^(https?:|mailto:|tel:)/.test(path)
-}
-
-/**
- * @param {string} str
- * @returns {Boolean}
- */
-export function validUsername(str) {
- const valid_map = ['admin', 'editor']
- return valid_map.indexOf(str.trim()) >= 0
-}
-
-/**
- * @param {string} url
- * @returns {Boolean}
- */
-export function validURL(url) {
- const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
- return reg.test(url)
-}
-
-/**
- * @param {string} str
- * @returns {Boolean}
- */
-export function validLowerCase(str) {
- const reg = /^[a-z]+$/
- return reg.test(str)
-}
-
-/**
- * @param {string} str
- * @returns {Boolean}
- */
-export function validUpperCase(str) {
- const reg = /^[A-Z]+$/
- return reg.test(str)
-}
-
-/**
- * @param {string} str
- * @returns {Boolean}
- */
-export function validAlphabets(str) {
- const reg = /^[A-Za-z]+$/
- return reg.test(str)
-}
-
-/**
- * @param {string} email
- * @returns {Boolean}
- */
-export function validEmail(email) {
- const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
- return reg.test(email)
-}
-
-/**
- * @param {string} str
- * @returns {Boolean}
- */
-export function isString(str) {
- return typeof str === 'string' || str instanceof String
-}
-
-/**
- * @param {Array} arg
- * @returns {Boolean}
- */
-export function isArray(arg) {
- if (typeof Array.isArray === 'undefined') {
- return Object.prototype.toString.call(arg) === '[object Array]'
- }
- return Array.isArray(arg)
-}
diff --git a/ruoyi-ui/src/views/dashboard/BarChart.vue b/ruoyi-ui/src/views/dashboard/BarChart.vue
deleted file mode 100644
index 116a431..0000000
--- a/ruoyi-ui/src/views/dashboard/BarChart.vue
+++ /dev/null
@@ -1,102 +0,0 @@
-<template>
- <div :class="className" :style="{height:height,width:width}" />
-</template>
-
-<script>
-import * as echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
-import resize from './mixins/resize'
-
-const animationDuration = 6000
-
-export default {
- mixins: [resize],
- props: {
- className: {
- type: String,
- default: 'chart'
- },
- width: {
- type: String,
- default: '100%'
- },
- height: {
- type: String,
- default: '300px'
- }
- },
- data() {
- return {
- chart: null
- }
- },
- mounted() {
- this.$nextTick(() => {
- this.initChart()
- })
- },
- beforeDestroy() {
- if (!this.chart) {
- return
- }
- this.chart.dispose()
- this.chart = null
- },
- methods: {
- initChart() {
- this.chart = echarts.init(this.$el, 'macarons')
-
- this.chart.setOption({
- tooltip: {
- trigger: 'axis',
- axisPointer: { // 坐标轴指示器,坐标轴触发有效
- type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
- }
- },
- grid: {
- top: 10,
- left: '2%',
- right: '2%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: [{
- type: 'category',
- data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
- axisTick: {
- alignWithLabel: true
- }
- }],
- yAxis: [{
- type: 'value',
- axisTick: {
- show: false
- }
- }],
- series: [{
- name: 'pageA',
- type: 'bar',
- stack: 'vistors',
- barWidth: '60%',
- data: [79, 52, 200, 334, 390, 330, 220],
- animationDuration
- }, {
- name: 'pageB',
- type: 'bar',
- stack: 'vistors',
- barWidth: '60%',
- data: [80, 52, 200, 334, 390, 330, 220],
- animationDuration
- }, {
- name: 'pageC',
- type: 'bar',
- stack: 'vistors',
- barWidth: '60%',
- data: [30, 52, 200, 334, 390, 330, 220],
- animationDuration
- }]
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/dashboard/LineChart.vue b/ruoyi-ui/src/views/dashboard/LineChart.vue
deleted file mode 100644
index cd59f24..0000000
--- a/ruoyi-ui/src/views/dashboard/LineChart.vue
+++ /dev/null
@@ -1,135 +0,0 @@
-<template>
- <div :class="className" :style="{height:height,width:width}" />
-</template>
-
-<script>
-import * as echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
-import resize from './mixins/resize'
-
-export default {
- mixins: [resize],
- props: {
- className: {
- type: String,
- default: 'chart'
- },
- width: {
- type: String,
- default: '100%'
- },
- height: {
- type: String,
- default: '350px'
- },
- autoResize: {
- type: Boolean,
- default: true
- },
- chartData: {
- type: Object,
- required: true
- }
- },
- data() {
- return {
- chart: null
- }
- },
- watch: {
- chartData: {
- deep: true,
- handler(val) {
- this.setOptions(val)
- }
- }
- },
- mounted() {
- this.$nextTick(() => {
- this.initChart()
- })
- },
- beforeDestroy() {
- if (!this.chart) {
- return
- }
- this.chart.dispose()
- this.chart = null
- },
- methods: {
- initChart() {
- this.chart = echarts.init(this.$el, 'macarons')
- this.setOptions(this.chartData)
- },
- setOptions({ expectedData, actualData } = {}) {
- this.chart.setOption({
- xAxis: {
- data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
- boundaryGap: false,
- axisTick: {
- show: false
- }
- },
- grid: {
- left: 10,
- right: 10,
- bottom: 20,
- top: 30,
- containLabel: true
- },
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'cross'
- },
- padding: [5, 10]
- },
- yAxis: {
- axisTick: {
- show: false
- }
- },
- legend: {
- data: ['expected', 'actual']
- },
- series: [{
- name: 'expected', itemStyle: {
- normal: {
- color: '#FF005A',
- lineStyle: {
- color: '#FF005A',
- width: 2
- }
- }
- },
- smooth: true,
- type: 'line',
- data: expectedData,
- animationDuration: 2800,
- animationEasing: 'cubicInOut'
- },
- {
- name: 'actual',
- smooth: true,
- type: 'line',
- itemStyle: {
- normal: {
- color: '#3888fa',
- lineStyle: {
- color: '#3888fa',
- width: 2
- },
- areaStyle: {
- color: '#f3f8ff'
- }
- }
- },
- data: actualData,
- animationDuration: 2800,
- animationEasing: 'quadraticOut'
- }]
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/dashboard/PanelGroup.vue b/ruoyi-ui/src/views/dashboard/PanelGroup.vue
deleted file mode 100644
index 8d3a73b..0000000
--- a/ruoyi-ui/src/views/dashboard/PanelGroup.vue
+++ /dev/null
@@ -1,181 +0,0 @@
-<template>
- <el-row :gutter="40" class="panel-group">
- <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
- <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
- <div class="card-panel-icon-wrapper icon-people">
- <svg-icon icon-class="peoples" class-name="card-panel-icon" />
- </div>
- <div class="card-panel-description">
- <div class="card-panel-text">
- 访客
- </div>
- <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
- </div>
- </div>
- </el-col>
- <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
- <div class="card-panel" @click="handleSetLineChartData('messages')">
- <div class="card-panel-icon-wrapper icon-message">
- <svg-icon icon-class="message" class-name="card-panel-icon" />
- </div>
- <div class="card-panel-description">
- <div class="card-panel-text">
- 消息
- </div>
- <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
- </div>
- </div>
- </el-col>
- <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
- <div class="card-panel" @click="handleSetLineChartData('purchases')">
- <div class="card-panel-icon-wrapper icon-money">
- <svg-icon icon-class="money" class-name="card-panel-icon" />
- </div>
- <div class="card-panel-description">
- <div class="card-panel-text">
- 金额
- </div>
- <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
- </div>
- </div>
- </el-col>
- <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
- <div class="card-panel" @click="handleSetLineChartData('shoppings')">
- <div class="card-panel-icon-wrapper icon-shopping">
- <svg-icon icon-class="shopping" class-name="card-panel-icon" />
- </div>
- <div class="card-panel-description">
- <div class="card-panel-text">
- 订单
- </div>
- <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
- </div>
- </div>
- </el-col>
- </el-row>
-</template>
-
-<script>
-import CountTo from 'vue-count-to'
-
-export default {
- components: {
- CountTo
- },
- methods: {
- handleSetLineChartData(type) {
- this.$emit('handleSetLineChartData', type)
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.panel-group {
- margin-top: 18px;
-
- .card-panel-col {
- margin-bottom: 32px;
- }
-
- .card-panel {
- height: 108px;
- cursor: pointer;
- font-size: 12px;
- position: relative;
- overflow: hidden;
- color: #666;
- background: #fff;
- box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
- border-color: rgba(0, 0, 0, .05);
-
- &:hover {
- .card-panel-icon-wrapper {
- color: #fff;
- }
-
- .icon-people {
- background: #40c9c6;
- }
-
- .icon-message {
- background: #36a3f7;
- }
-
- .icon-money {
- background: #f4516c;
- }
-
- .icon-shopping {
- background: #34bfa3
- }
- }
-
- .icon-people {
- color: #40c9c6;
- }
-
- .icon-message {
- color: #36a3f7;
- }
-
- .icon-money {
- color: #f4516c;
- }
-
- .icon-shopping {
- color: #34bfa3
- }
-
- .card-panel-icon-wrapper {
- float: left;
- margin: 14px 0 0 14px;
- padding: 16px;
- transition: all 0.38s ease-out;
- border-radius: 6px;
- }
-
- .card-panel-icon {
- float: left;
- font-size: 48px;
- }
-
- .card-panel-description {
- float: right;
- font-weight: bold;
- margin: 26px;
- margin-left: 0px;
-
- .card-panel-text {
- line-height: 18px;
- color: rgba(0, 0, 0, 0.45);
- font-size: 16px;
- margin-bottom: 12px;
- }
-
- .card-panel-num {
- font-size: 20px;
- }
- }
- }
-}
-
-@media (max-width:550px) {
- .card-panel-description {
- display: none;
- }
-
- .card-panel-icon-wrapper {
- float: none !important;
- width: 100%;
- height: 100%;
- margin: 0 !important;
-
- .svg-icon {
- display: block;
- margin: 14px auto !important;
- float: none !important;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/views/dashboard/PieChart.vue b/ruoyi-ui/src/views/dashboard/PieChart.vue
deleted file mode 100644
index 70c6076..0000000
--- a/ruoyi-ui/src/views/dashboard/PieChart.vue
+++ /dev/null
@@ -1,79 +0,0 @@
-<template>
- <div :class="className" :style="{height:height,width:width}" />
-</template>
-
-<script>
-import * as echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
-import resize from './mixins/resize'
-
-export default {
- mixins: [resize],
- props: {
- className: {
- type: String,
- default: 'chart'
- },
- width: {
- type: String,
- default: '100%'
- },
- height: {
- type: String,
- default: '300px'
- }
- },
- data() {
- return {
- chart: null
- }
- },
- mounted() {
- this.$nextTick(() => {
- this.initChart()
- })
- },
- beforeDestroy() {
- if (!this.chart) {
- return
- }
- this.chart.dispose()
- this.chart = null
- },
- methods: {
- initChart() {
- this.chart = echarts.init(this.$el, 'macarons')
-
- this.chart.setOption({
- tooltip: {
- trigger: 'item',
- formatter: '{a} <br/>{b} : {c} ({d}%)'
- },
- legend: {
- left: 'center',
- bottom: '10',
- data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
- },
- series: [
- {
- name: 'WEEKLY WRITE ARTICLES',
- type: 'pie',
- roseType: 'radius',
- radius: [15, 95],
- center: ['50%', '38%'],
- data: [
- { value: 320, name: 'Industries' },
- { value: 240, name: 'Technology' },
- { value: 149, name: 'Forex' },
- { value: 100, name: 'Gold' },
- { value: 59, name: 'Forecasts' }
- ],
- animationEasing: 'cubicInOut',
- animationDuration: 2600
- }
- ]
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/dashboard/RaddarChart.vue b/ruoyi-ui/src/views/dashboard/RaddarChart.vue
deleted file mode 100644
index 39d879b..0000000
--- a/ruoyi-ui/src/views/dashboard/RaddarChart.vue
+++ /dev/null
@@ -1,116 +0,0 @@
-<template>
- <div :class="className" :style="{height:height,width:width}" />
-</template>
-
-<script>
-import * as echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
-import resize from './mixins/resize'
-
-const animationDuration = 3000
-
-export default {
- mixins: [resize],
- props: {
- className: {
- type: String,
- default: 'chart'
- },
- width: {
- type: String,
- default: '100%'
- },
- height: {
- type: String,
- default: '300px'
- }
- },
- data() {
- return {
- chart: null
- }
- },
- mounted() {
- this.$nextTick(() => {
- this.initChart()
- })
- },
- beforeDestroy() {
- if (!this.chart) {
- return
- }
- this.chart.dispose()
- this.chart = null
- },
- methods: {
- initChart() {
- this.chart = echarts.init(this.$el, 'macarons')
-
- this.chart.setOption({
- tooltip: {
- trigger: 'axis',
- axisPointer: { // 坐标轴指示器,坐标轴触发有效
- type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
- }
- },
- radar: {
- radius: '66%',
- center: ['50%', '42%'],
- splitNumber: 8,
- splitArea: {
- areaStyle: {
- color: 'rgba(127,95,132,.3)',
- opacity: 1,
- shadowBlur: 45,
- shadowColor: 'rgba(0,0,0,.5)',
- shadowOffsetX: 0,
- shadowOffsetY: 15
- }
- },
- indicator: [
- { name: 'Sales', max: 10000 },
- { name: 'Administration', max: 20000 },
- { name: 'Information Techology', max: 20000 },
- { name: 'Customer Support', max: 20000 },
- { name: 'Development', max: 20000 },
- { name: 'Marketing', max: 20000 }
- ]
- },
- legend: {
- left: 'center',
- bottom: '10',
- data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
- },
- series: [{
- type: 'radar',
- symbolSize: 0,
- areaStyle: {
- normal: {
- shadowBlur: 13,
- shadowColor: 'rgba(0,0,0,.2)',
- shadowOffsetX: 0,
- shadowOffsetY: 10,
- opacity: 1
- }
- },
- data: [
- {
- value: [5000, 7000, 12000, 11000, 15000, 14000],
- name: 'Allocated Budget'
- },
- {
- value: [4000, 9000, 15000, 15000, 13000, 11000],
- name: 'Expected Spending'
- },
- {
- value: [5500, 11000, 12000, 15000, 12000, 12000],
- name: 'Actual Spending'
- }
- ],
- animationDuration: animationDuration
- }]
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/dashboard/mixins/resize.js b/ruoyi-ui/src/views/dashboard/mixins/resize.js
deleted file mode 100644
index d26194c..0000000
--- a/ruoyi-ui/src/views/dashboard/mixins/resize.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import { debounce } from '@/utils'
-
-export default {
- data() {
- return {
- $_sidebarElm: null,
- $_resizeHandler: null
- }
- },
- mounted() {
- this.initListener()
- },
- activated() {
- if (!this.$_resizeHandler) {
- // avoid duplication init
- this.initListener()
- }
-
- // when keep-alive chart activated, auto resize
- this.resize()
- },
- beforeDestroy() {
- this.destroyListener()
- },
- deactivated() {
- this.destroyListener()
- },
- methods: {
- // use $_ for mixins properties
- // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
- $_sidebarResizeHandler(e) {
- if (e.propertyName === 'width') {
- this.$_resizeHandler()
- }
- },
- initListener() {
- this.$_resizeHandler = debounce(() => {
- this.resize()
- }, 100)
- window.addEventListener('resize', this.$_resizeHandler)
-
- this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
- this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
- },
- destroyListener() {
- window.removeEventListener('resize', this.$_resizeHandler)
- this.$_resizeHandler = null
-
- this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
- },
- resize() {
- const { chart } = this
- chart && chart.resize()
- }
- }
-}
diff --git a/ruoyi-ui/src/views/error/401.vue b/ruoyi-ui/src/views/error/401.vue
deleted file mode 100644
index 9664fba..0000000
--- a/ruoyi-ui/src/views/error/401.vue
+++ /dev/null
@@ -1,88 +0,0 @@
-<template>
- <div class="errPage-container">
- <el-button icon="arrow-left" class="pan-back-btn" @click="back">
- 返回
- </el-button>
- <el-row>
- <el-col :span="12">
- <h1 class="text-jumbo text-ginormous">
- 401错误!
- </h1>
- <h2>您没有访问权限!</h2>
- <h6>对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面</h6>
- <ul class="list-unstyled">
- <li class="link-type">
- <router-link to="/">
- 回首页
- </router-link>
- </li>
- </ul>
- </el-col>
- <el-col :span="12">
- <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
- </el-col>
- </el-row>
- </div>
-</template>
-
-<script>
-import errGif from '@/assets/401_images/401.gif'
-
-export default {
- name: 'Page401',
- data() {
- return {
- errGif: errGif + '?' + +new Date()
- }
- },
- methods: {
- back() {
- if (this.$route.query.noGoBack) {
- this.$router.push({ path: '/' })
- } else {
- this.$router.go(-1)
- }
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
- .errPage-container {
- width: 800px;
- max-width: 100%;
- margin: 100px auto;
- .pan-back-btn {
- background: #008489;
- color: #fff;
- border: none!important;
- }
- .pan-gif {
- margin: 0 auto;
- display: block;
- }
- .pan-img {
- display: block;
- margin: 0 auto;
- width: 100%;
- }
- .text-jumbo {
- font-size: 60px;
- font-weight: 700;
- color: #484848;
- }
- .list-unstyled {
- font-size: 14px;
- li {
- padding-bottom: 5px;
- }
- a {
- color: #008489;
- text-decoration: none;
- &:hover {
- text-decoration: underline;
- }
- }
- }
- }
-</style>
diff --git a/ruoyi-ui/src/views/error/404.vue b/ruoyi-ui/src/views/error/404.vue
deleted file mode 100644
index 666d27c..0000000
--- a/ruoyi-ui/src/views/error/404.vue
+++ /dev/null
@@ -1,233 +0,0 @@
-<template>
- <div class="wscn-http404-container">
- <div class="wscn-http404">
- <div class="pic-404">
- <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
- <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
- <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
- <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
- </div>
- <div class="bullshit">
- <div class="bullshit__oops">
- 404错误!
- </div>
- <div class="bullshit__headline">
- {{ message }}
- </div>
- <div class="bullshit__info">
- 对不起,您正在寻找的页面不存在。尝试检查URL的错误,然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。
- </div>
- <router-link to="/" class="bullshit__return-home">
- 返回首页
- </router-link>
- </div>
- </div>
- </div>
-</template>
-
-<script>
-
-export default {
- name: 'Page404',
- computed: {
- message() {
- return '找不到网页!'
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.wscn-http404-container{
- transform: translate(-50%,-50%);
- position: absolute;
- top: 40%;
- left: 50%;
-}
-.wscn-http404 {
- position: relative;
- width: 1200px;
- padding: 0 50px;
- overflow: hidden;
- .pic-404 {
- position: relative;
- float: left;
- width: 600px;
- overflow: hidden;
- &__parent {
- width: 100%;
- }
- &__child {
- position: absolute;
- &.left {
- width: 80px;
- top: 17px;
- left: 220px;
- opacity: 0;
- animation-name: cloudLeft;
- animation-duration: 2s;
- animation-timing-function: linear;
- animation-fill-mode: forwards;
- animation-delay: 1s;
- }
- &.mid {
- width: 46px;
- top: 10px;
- left: 420px;
- opacity: 0;
- animation-name: cloudMid;
- animation-duration: 2s;
- animation-timing-function: linear;
- animation-fill-mode: forwards;
- animation-delay: 1.2s;
- }
- &.right {
- width: 62px;
- top: 100px;
- left: 500px;
- opacity: 0;
- animation-name: cloudRight;
- animation-duration: 2s;
- animation-timing-function: linear;
- animation-fill-mode: forwards;
- animation-delay: 1s;
- }
- @keyframes cloudLeft {
- 0% {
- top: 17px;
- left: 220px;
- opacity: 0;
- }
- 20% {
- top: 33px;
- left: 188px;
- opacity: 1;
- }
- 80% {
- top: 81px;
- left: 92px;
- opacity: 1;
- }
- 100% {
- top: 97px;
- left: 60px;
- opacity: 0;
- }
- }
- @keyframes cloudMid {
- 0% {
- top: 10px;
- left: 420px;
- opacity: 0;
- }
- 20% {
- top: 40px;
- left: 360px;
- opacity: 1;
- }
- 70% {
- top: 130px;
- left: 180px;
- opacity: 1;
- }
- 100% {
- top: 160px;
- left: 120px;
- opacity: 0;
- }
- }
- @keyframes cloudRight {
- 0% {
- top: 100px;
- left: 500px;
- opacity: 0;
- }
- 20% {
- top: 120px;
- left: 460px;
- opacity: 1;
- }
- 80% {
- top: 180px;
- left: 340px;
- opacity: 1;
- }
- 100% {
- top: 200px;
- left: 300px;
- opacity: 0;
- }
- }
- }
- }
- .bullshit {
- position: relative;
- float: left;
- width: 300px;
- padding: 30px 0;
- overflow: hidden;
- &__oops {
- font-size: 32px;
- font-weight: bold;
- line-height: 40px;
- color: #1482f0;
- opacity: 0;
- margin-bottom: 20px;
- animation-name: slideUp;
- animation-duration: 0.5s;
- animation-fill-mode: forwards;
- }
- &__headline {
- font-size: 20px;
- line-height: 24px;
- color: #222;
- font-weight: bold;
- opacity: 0;
- margin-bottom: 10px;
- animation-name: slideUp;
- animation-duration: 0.5s;
- animation-delay: 0.1s;
- animation-fill-mode: forwards;
- }
- &__info {
- font-size: 13px;
- line-height: 21px;
- color: grey;
- opacity: 0;
- margin-bottom: 30px;
- animation-name: slideUp;
- animation-duration: 0.5s;
- animation-delay: 0.2s;
- animation-fill-mode: forwards;
- }
- &__return-home {
- display: block;
- float: left;
- width: 110px;
- height: 36px;
- background: #1482f0;
- border-radius: 100px;
- text-align: center;
- color: #ffffff;
- opacity: 0;
- font-size: 14px;
- line-height: 36px;
- cursor: pointer;
- animation-name: slideUp;
- animation-duration: 0.5s;
- animation-delay: 0.3s;
- animation-fill-mode: forwards;
- }
- @keyframes slideUp {
- 0% {
- transform: translateY(60px);
- opacity: 0;
- }
- 100% {
- transform: translateY(0);
- opacity: 1;
- }
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
deleted file mode 100644
index cc876ba..0000000
--- a/ruoyi-ui/src/views/index.vue
+++ /dev/null
@@ -1,1099 +0,0 @@
-<template>
- <div class="app-container home">
- <el-row :gutter="20">
- <el-col :sm="24" :lg="12" style="padding-left: 20px">
- <h2>若依后台管理框架</h2>
- <p>
- 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
- </p>
- <p>
- <b>当前版本:</b> <span>v{{ version }}</span>
- </p>
- <p>
- <el-tag type="danger">¥免费开源</el-tag>
- </p>
- <p>
- <el-button
- type="primary"
- size="mini"
- icon="el-icon-cloudy"
- plain
- @click="goTarget('https://gitee.com/y_project/RuoYi-Cloud')"
- >访问码云</el-button
- >
- <el-button
- size="mini"
- icon="el-icon-s-home"
- plain
- @click="goTarget('http://ruoyi.vip')"
- >访问主页</el-button
- >
- </p>
- </el-col>
-
- <el-col :sm="24" :lg="12" style="padding-left: 50px">
- <el-row>
- <el-col :span="12">
- <h2>技术选型</h2>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="6">
- <h4>后端技术</h4>
- <ul>
- <li>SpringBoot</li>
- <li>SpringCloud</li>
- <li>Nacos</li>
- <li>Sentinel</li>
- <li>Seata</li>
- <li>Minio</li>
- <li>...</li>
- </ul>
- </el-col>
- <el-col :span="6">
- <h4>前端技术</h4>
- <ul>
- <li>Vue</li>
- <li>Vuex</li>
- <li>Element-ui</li>
- <li>Axios</li>
- <li>Echarts</li>
- <li>Quill</li>
- <li>...</li>
- </ul>
- </el-col>
- </el-row>
- </el-col>
- </el-row>
- <el-divider />
- <el-row :gutter="20">
- <el-col :xs="24" :sm="24" :md="12" :lg="8">
- <el-card class="update-log">
- <div slot="header" class="clearfix">
- <span>联系信息</span>
- </div>
- <div class="body">
- <p>
- <i class="el-icon-s-promotion"></i> 官网:<el-link
- href="http://www.ruoyi.vip"
- target="_blank"
- >http://www.ruoyi.vip</el-link
- >
- </p>
- <p>
- <i class="el-icon-user-solid"></i> QQ群: <s> 满42799195 </s> <s> 满170157040 </s>
- <s> 满130643120 </s> <s> 满225920371 </s> <s> 满201705537 </s> <s> 满236543183 </s>
- <s> 满213618602 </s> <s> 满148794840 </s> <s> 满118752664 </s> <s> 满101038945 </s>
- <s> 满128355254 </s> <s> 满179219821 </s> <s> 满158753145 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=jR7HqTiLzuLocIH6aNNtTW3LlCV8UQ6d&authKey=GJZj%2Bnwmsvk6j%2FWrX7FKstAaRjgUC1WL%2F%2B8aVTaPbHX5wOimH5q9igaOSXP7cF9L&noverify=0&group_code=112869560" target="_blank">112869560</a>
- </p>
- <p>
- <i class="el-icon-chat-dot-round"></i> 微信:<a
- href="javascript:;"
- >/ *若依</a
- >
- </p>
- <p>
- <i class="el-icon-money"></i> 支付宝:<a
- href="javascript:;"
- class="支付宝信息"
- >/ *若依</a
- >
- </p>
- </div>
- </el-card>
- </el-col>
- <el-col :xs="24" :sm="24" :md="12" :lg="8">
- <el-card class="update-log">
- <div slot="header" class="clearfix">
- <span>更新日志</span>
- </div>
- <el-collapse accordion>
- <el-collapse-item title="v3.6.8 - 2026-03-30">
- <ol>
- <li>新增锁定屏幕功能</li>
- <li>首页新增通知公告消息提醒</li>
- <li>添加持久化标签页开关功能</li>
- <li>菜单搜索支持文本高亮&数量提示</li>
- <li>添加菜单路由地址和名称的校验规则</li>
- <li>字典类型列表新增抽屉效果详细信息</li>
- <li>升级axios到最新版本0.30.3</li>
- <li>升级spring-cloud到最新版2025.1.0</li>
- <li>升级spring-cloud-alibaba到最新版2025.1.0.0</li>
- <li>升级spring-boot-admin到最新版4.0.2</li>
- <li>升级dynamic-ds到最新版本4.5.0</li>
- <li>升级springdoc到最新版本3.0.2</li>
- <li>升级transmittable-thread-local到最新版本2.14.5</li>
- <li>升级spring-boot到最新版本4.0.3</li>
- <li>升级druid到最新版本1.2.28</li>
- <li>升级pagehelper到最新版2.1.1</li>
- <li>优化操作日志详细页面</li>
- <li>部门管理支持批量保存排序</li>
- <li>菜单管理支持批量保存排序</li>
- <li>菜单管理列表新增类型显示</li>
- <li>代码生成模板支持TypeScript版本</li>
- <li>优化菜单主题风格显示</li>
- <li>优化点击任务名称查看详细</li>
- <li>优化字典类型属性提醒说明</li>
- <li>优化防重提交间隔时间可自定义</li>
- <li>优化页签功能&支持全屏按钮操作</li>
- <li>优化RightToolbar搜索栏切换动画</li>
- <li>修复Excel自定义格式样式污染问题</li>
- <li>优化isAdmin方法统一到SecurityUtils</li>
- <li>优化定时任务详情页展示&补充执行时间字段</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.7 - 2025-12-22">
- <ol>
- <li>支持防盗链功能</li>
- <li>菜单导航设置支持纯顶部</li>
- <li>用户头像更换后移除旧头像文件</li>
- <li>支持Excel导出对象的多个子列表</li>
- <li>升级druid到最新版本1.2.27</li>
- <li>升级fastjson到最新版2.0.60</li>
- <li>升级tomcat到最新版本9.0.112</li>
- <li>升级commons.io到最新版本2.21.0</li>
- <li>用户导入添加验证提示</li>
- <li>显示列信息支持对象格式</li>
- <li>网页标题设置新增SET_TITLE方法</li>
- <li>自动识别json对象白名单配置范围缩小</li>
- <li>登录/注册页面底部版权信息修改为读取配置</li>
- <li>修复用户归属部门无法修改为空问题</li>
- <li>修复固定头部时出现的导航栏偏移问题</li>
- <li>修复v3时间控件between选择后清空报错问题</li>
- <li>修复comboReadDict属性下多个sheet出现的报错</li>
- <li>修复表单构建移除所有控件后切换路由回来空白问题</li>
- <li>优化布局设置显示</li>
- <li>优化字典组件值宽松匹配</li>
- <li>优化生成代码下载的zip文件名</li>
- <li>优化日志记录参数拼装提升效率</li>
- <li>优化导入文件检查标题行不能为空</li>
- <li>优化表单构建关闭页签销毁复制插件</li>
- <li>优化Excel统计行数值的单元格样式显示</li>
- <li>优化数据权限控制逻辑,放开permission限制</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.6 - 2025-05-30">
- <ol>
- <li>优化菜单搜索查询页</li>
- <li>导航栏显示昵称&设置</li>
- <li>用户管理支持分栏拖动</li>
- <li>修改主题样式本地读取</li>
- <li>菜单管理新增路由名称</li>
- <li>添加底部版权信息&开关</li>
- <li>分配角色禁用不允许勾选</li>
- <li>添加页签图标显示开关功能</li>
- <li>用户管理过滤掉已禁用部门</li>
- <li>上传组件新增拖动排序属性</li>
- <li>显隐列组件支持全选/全不选</li>
- <li>白名单支持对通配符路径匹配</li>
- <li>初始密码支持自定义修改策略</li>
- <li>账号密码支持自定义更新周期</li>
- <li>菜单面包屑导航支持多层级显示</li>
- <li>支持富文本复制粘贴图片上传至url</li>
- <li>支持文件&图片组件自定义地址&参数</li>
- <li>更新ry-config的nacos表结构到最新版本</li>
- <li>代码生成新增配置是否允许文件覆盖到本地</li>
- <li>使用CacheRequestBody代替CacheRequestFilter</li>
- <li>升级tomcat到最新版本9.0.105</li>
- <li>升级fastjson到最新版2.0.57</li>
- <li>升级commons.io到最新版本2.19.0</li>
- <li>package.json移除runjs&eslint&vue-meta依赖</li>
- <li>修复导出子列表对象只能在最后的问题</li>
- <li>修复TopNav无法正确获取active的问题</li>
- <li>修复默认关闭Tags-Views内链页面打不开</li>
- <li>Excel注解支持wrapText是否允许内容换行</li>
- <li>优化文件上传组件新增类型</li>
- <li>优化导入带标题文件关闭清理</li>
- <li>优化参数键值更换为多行文本</li>
- <li>优化特殊字符密码修改失败问题</li>
- <li>优化代码生成列表支持按时间排序</li>
- <li>优化TopNav内链菜单点击没有高亮</li>
- <li>优化文件异常输入流未关闭的问题</li>
- <li>优化菜单管理切换Mini布局错乱问题</li>
- <li>优化空指针异常时无法获取错误信息问题</li>
- <li>优化文件&图片上传组件新增disabled属性</li>
- <li>优化isAdmin方法,避免脱敏模块security依赖</li>
- <li>优化定时任务字符包含多个括号导致数据错误</li>
- <li>优化登录&注册页表头使用VUE_APP_TITLE配置值</li>
- <li>优化导出Excel日期格式双击离开后与设定的格式不一致问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.5 - 2024-11-13">
- <ol>
- <li>使用SpringDoc代替Swagger</li>
- <li>菜单管理新增路由名称</li>
- <li>新增数据脱敏过滤注解</li>
- <li>限制用户操作数据权限范围</li>
- <li>支持自定义显示Excel属性列</li>
- <li>操作日志记录DELETE请求参数</li>
- <li>用户登录后记录最后登录IP&时间</li>
- <li>升级druid到最新版本1.2.23</li>
- <li>升级fastjson到最新版2.0.53</li>
- <li>升级dynamic-ds到最新版本4.3.1</li>
- <li>升级spring-cloud到最新版2021.0.9</li>
- <li>升级spring-boot-admin到最新版2.7.16</li>
- <li>升级spring-cloud-alibaba到最新版2021.0.6.1</li>
- <li>升级quill到最新版本2.0.2</li>
- <li>升级axios到最新版本0.28.1</li>
- <li>升级core-js到最新版本3.37.1</li>
- <li>升级其他依赖到安全版本,防止漏洞风险</li>
- <li>修复角色禁用权限不失效问题</li>
- <li>优化身份证脱敏正则</li>
- <li>优化权限更新后同步缓存</li>
- <li>优化查询时间范围日期格式</li>
- <li>优化代码生成上级菜单字段类型</li>
- <li>优化无用户编号不校验数据权限</li>
- <li>优化代码生成主子表关联查询方式</li>
- <li>优化校检文件名是否包含特殊字符</li>
- <li>优化查表特殊字符使用反斜杠进行转义</li>
- <li>优化多个自定数据权限使用in查询,避免多次拼接</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.4 - 2024-04-01">
- <ol>
- <li>全局数据存储用户编号</li>
- <li>用户密码新增非法字符验证</li>
- <li>代码生成支持选择前端模板类型</li>
- <li>操作日志列表新增IP地址查询</li>
- <li>显隐列组件支持复选框弹出类型</li>
- <li>Excel注解ColumnType类型新增文本</li>
- <li>Excel自定义数据处理器增加单元格/工作簿对象</li>
- <li>升级element-ui到最新版本2.15.14</li>
- <li>升级compression-webpack-plugin到6.1.2以兼容node18+</li>
- <li>升级druid到最新版本1.2.20</li>
- <li>升级fastjson到最新版2.0.43</li>
- <li>升级pagehelper到最新版2.0.0</li>
- <li>升级dynamic-ds到最新版本4.2.0</li>
- <li>升级commons.io到最新版本2.13.0</li>
- <li>升级spring-boot到最新版本2.7.18</li>
- <li>升级spring-boot-admin到最新版2.7.15</li>
- <li>升级transmittable-thread-local到最新版本2.14.4</li>
- <li>修复五级路由缓存无效问题</li>
- <li>修复外链带端口出现的异常</li>
- <li>修复内链iframe没有传递参数问题</li>
- <li>修复自定义字典样式不生效的问题</li>
- <li>修复字典缓存删除方法参数错误问题</li>
- <li>修复Excel导入数据临时文件无法删除问题</li>
- <li>修复未登录带参数访问成功后参数丢失问题</li>
- <li>修复HeaderSearch组件跳转query参数丢失问题</li>
- <li>修复数据字典列表页重置后标签值无法输入问题</li>
- <li>修复Excels导入时无法获取到readConverterExp内容转表达式问题</li>
- <li>优化Xss注解匹配方式</li>
- <li>优化权限字符匹配方式</li>
- <li>优化下载zip方法新增遮罩层</li>
- <li>优化头像上传参数新增文件名称</li>
- <li>优化字典标签支持自定义分隔符</li>
- <li>优化定时任务白名单配置范围缩小</li>
- <li>优化菜单管理类型为按钮状态可选</li>
- <li>优化前端防重复提交数据大小限制</li>
- <li>优化TopNav菜单没有图标svg不显示</li>
- <li>优化富文本Editor组件检验图片格式</li>
- <li>优化数字金额大写转换精度丢失问题</li>
- <li>优化个人中心/基本资料修改时数据显示问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.3 - 2023-07-07">
- <ol>
- <li>支持登录IP黑名单限制</li>
- <li>操作日志新增消耗时间属性</li>
- <li>屏蔽定时任务bean违规的字符</li>
- <li>日志管理使用索引提升查询性能</li>
- <li>日志注解支持排除指定的请求参数</li>
- <li>支持自定义隐藏属性列过滤子对象</li>
- <li>升级spring-boot到最新版本2.7.13</li>
- <li>升级spring-cloud到最新版2021.0.8</li>
- <li>升级spring-cloud-alibaba到最新版2021.0.5.0</li>
- <li>升级druid到最新版本1.2.16</li>
- <li>升级fastjson到最新版2.0.34</li>
- <li>升级pagehelper到最新版1.4.7</li>
- <li>升级transmittable-thread-local到最新版本2.14.3</li>
- <li>升级element-ui到最新版本2.15.13</li>
- <li>移除apache/commons-fileupload依赖</li>
- <li>修复页面切换时布局错乱的问题</li>
- <li>修复用户多角色数据权限可能出现权限抬升的情况</li>
- <li>修复导入用户时无法更新存在用户数据的问题</li>
- <li>修复开启TopNav后一级菜单路由参数设置无效问题</li>
- <li>优化文件下载出现的异常</li>
- <li>优化选择图标组件高亮回显</li>
- <li>优化修改密码日志存储明文问题</li>
- <li>优化排序属性orderBy参数限制长度</li>
- <li>优化页签栏关闭其他出现的异常问题</li>
- <li>优化页签关闭左侧选项排除首页选项</li>
- <li>优化关闭当前tab页跳转最右侧tab页</li>
- <li>优化文件上传服务关闭InputStream</li>
- <li>优化页签在Firefox浏览器被遮挡的问题</li>
- <li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li>
- <li>优化DictTag组件value没有匹配的值时则展示value</li>
- <li>优化去除@EnableCustomSwagger注解后会启动失败问题</li>
- <li>优化upload接口在文件过大和文件名过长的情况返回提示信息</li>
- <li>优化异步保存日志发生报错不进RemoteLogFallbackFactory问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.2 - 2023-01-16">
- <ol>
- <li>重置时取消部门选中</li>
- <li>新增返回警告消息提示</li>
- <li>忽略不必要的属性数据返回</li>
- <li>修改参数键名时移除前缓存配置</li>
- <li>开启TopNav没有子菜单隐藏侧边栏</li>
- <li>删除fuse无效选项maxPatternLength</li>
- <li>兼容Excel下拉框内容过多无法显示的问题</li>
- <li>修复文件上传组件格式验证问题</li>
- <li>修复回显数据字典数组异常问题</li>
- <li>修复sheet超出最大行数异常问题</li>
- <li>修复Log注解GET请求记录不到参数问题</li>
- <li>修复gateway流控规则生效但不显示问题</li>
- <li>修复主题颜色在Drawer组件不会加载问题</li>
- <li>修复调度日志点击多次数据不变化的问题</li>
- <li>修复用户编辑时角色和部门存在无法修改情况</li>
- <li>修复使用透明底png图片时,自动填充黑色背景</li>
- <li>修复table中更多按钮切换主题色未生效修复问题</li>
- <li>修复某些特性的环境生成代码变乱码TXT文件问题</li>
- <li>修复代码生成图片/文件/单选时选择必填无法校验问题</li>
- <li>升级spring-cloud到最新版2021.0.5</li>
- <li>升级spring-boot到最新版本2.7.7</li>
- <li>升级spring-boot-admin到最新版2.7.10</li>
- <li>升级kaptcha到最新版2.3.3</li>
- <li>升级druid到最新版本1.2.15</li>
- <li>升级fastjson到最新版2.0.22</li>
- <li>升级pagehelper到最新版1.4.6</li>
- <li>升级transmittable-thread-local到最新版本2.14.2</li>
- <li>升级echarts到最新版本5.4.0</li>
- <li>升级core-js到最新版本3.25.3</li>
- <li>升级element-ui到最新版本2.15.12</li>
- <li>移除commons-collections多余的依赖</li>
- <li>优化弹窗内容过多展示不全问题</li>
- <li>优化导出对象的子列表为空会出现[]问题</li>
- <li>优化字符未使用下划线不进行驼峰式处理</li>
- <li>优化nacos修改xss开关时同步过滤器验证</li>
- <li>优化修改头像在小屏幕上页面布局错位的问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.1 - 2022-10-01">
- <ol>
- <li>数据逻辑删除不进行唯一验证</li>
- <li>支持多权限字符匹配角色数据权限</li>
- <li>页面内嵌iframe切换tab不刷新数据</li>
- <li>新增密码最大错误次数/锁定时间</li>
- <li>登录日志新增解锁账户功能</li>
- <li>通用下载方法新增config配置选项</li>
- <li>操作日志记录支持排除敏感属性字段</li>
- <li>Excel注解支持导出对象的子列表方法</li>
- <li>Excel注解支持自定义隐藏属性列</li>
- <li>Excel注解支持backgroundColor属性设置背景色</li>
- <li>升级spring-cloud-alibaba到最新版2021.0.4.0</li>
- <li>升级spring-cloud到最新版2021.0.4</li>
- <li>升级spring-boot到最新版本2.7.3</li>
- <li>升级spring-boot-admin到最新版2.7.5</li>
- <li>升级seata到最新版1.5.2</li>
- <li>升级druid到最新版本1.2.12</li>
- <li>升级fastjson到最新版2.0.14</li>
- <li>升级pagehelper到最新版1.4.5</li>
- <li>升级core-js到最新版本3.25.2</li>
- <li>升级dynamic-ds到最新版本3.5.2</li>
- <li>升级element-ui到最新版本2.15.10</li>
- <li>修复多文件上传报错出现的异常问题</li>
- <li>修复图片预览组件src属性为null值控制台报错问题</li>
- <li>修复使用FastDFS上传头像失败提示文件名没有后缀问题</li>
- <li>优化seata单独依赖模块</li>
- <li>优化任务过期不执行调度</li>
- <li>优化字典数据使用store存取</li>
- <li>优化代码生成同步后值NULL问题</li>
- <li>优化定时任务支持执行父类方法</li>
- <li>优化修改资料头像被覆盖的问题</li>
- <li>优化修改用户登录账号重复验证</li>
- <li>优化用户个人信息接口防止修改部门</li>
- <li>优化布局设置使用el-drawer抽屉显示</li>
- <li>优化日志注解记录限制请求地址的长度</li>
- <li>优化导入更新用户数据前校验数据权限</li>
- <li>优化excel/scale属性导出单元格数值类型</li>
- <li>优化日志操作中重置按钮时重复查询的问题</li>
- <li>优化多个相同角色数据导致权限SQL重复问题</li>
- <li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.6.0 - 2022-07-16">
- <ol>
- <li>Excel注解支持color字体颜色</li>
- <li>用户头像上传限制只能为图片格式</li>
- <li>检查定时任务bean所在包名是否为白名单配置</li>
- <li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
- <li>升级spring-cloud-alibaba到最新版2021.0.1.0</li>
- <li>升级spring-cloud到最新版2021.0.3</li>
- <li>升级spring-boot到最新版本2.7.1</li>
- <li>升级spring-boot-admin到最新版2.7.2</li>
- <li>升级seata到最新版1.5.1</li>
- <li>升级pagehelper到最新版1.4.3</li>
- <li>升级dynamic-ds到最新版本3.5.1</li>
- <li>升级fastjson到最新版2.0.9</li>
- <li>升级druid到最新版本1.2.11</li>
- <li>升级transmittable-thread-local到最新版本2.13.2</li>
- <li>升级element-ui到最新版本2.15.9</li>
- <li>修复字典数据显示不全问题</li>
- <li>修复操作日志查询类型条件为0时会查到所有数据</li>
- <li>优化验证码开关变量名</li>
- <li>优化设置分页参数默认值</li>
- <li>优化对空字符串参数处理的过滤</li>
- <li>优化Maven使用阿里云镜像站加速</li>
- <li>优化用户列表查询不显示密码字段</li>
- <li>优化表单构建按钮不显示正则校验</li>
- <li>优化字典类型删除多余的mapper注解</li>
- <li>优化字典数据回显样式下拉框显示值</li>
- <li>优化用户管理左侧树型组件增加选中高亮保持</li>
- <li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
- <li>优化数据监控Spring Security权限认证过时代码</li>
- <li>优化岗位长主键溢出问题将查询返回类型改为Long</li>
- <li>优化删除无用admin-client依赖声明,避免造成误解</li>
- <li>优化默认不启用压缩文件缓存防止node_modules过大</li>
- <li>优化获取body请求数据缓存过滤器CacheRequestFilter</li>
- <li>优化网关通过注解解决循环引用及Bean重复问题删除allow配置</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.5.0 - 2022-04-11">
- <ol>
- <li>开启TopNav没有子菜单情况隐藏侧边栏</li>
- <li>侧边栏菜单名称过长悬停显示标题</li>
- <li>用户访问控制时校验数据权限,防止越权</li>
- <li>导出Excel时屏蔽公式,防止CSV注入风险</li>
- <li>组件ImageUpload支持多图同时选择上传</li>
- <li>组件FileUpload支持多文件同时选择上传</li>
- <li>代码生成树表新增(展开/折叠)</li>
- <li>代码生成子表支持日期/字典配置</li>
- <li>代码生成编辑修改打开新页签</li>
- <li>添加页签openPage支持传递参数</li>
- <li>添加清理分页的线程变量方法</li>
- <li>修改npm即将过期的注册源地址</li>
- <li>用户缓存信息添加部门ancestors祖级列表</li>
- <li>升级spring-cloud到最新版2021.0.1</li>
- <li>升级spring-boot到最新版本2.6.6</li>
- <li>升级spring-boot-admin到最新版2.6.6</li>
- <li>升级spring-boot-mybatis到最新版2.2.2</li>
- <li>降级jsencrypt版本兼容IE浏览器</li>
- <li>修复分页组件请求两次问题</li>
- <li>修复表单清除元素位置未垂直居中问题</li>
- <li>修复Excel注解prompt/combo同时使用不生效问题</li>
- <li>修复导入Excel时字典字段类型为Long转义为空问题</li>
- <li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
- <li>修复Xss注解字段值为空时的异常问题</li>
- <li>优化IP地址获取到多个的问题</li>
- <li>优化文件上传兼容Weblogic环境</li>
- <li>代码生成同步保留必填/类型选项</li>
- <li>优化Excel格式化不同类型的日期对象</li>
- <li>优化菜单表关键字导致的插件报错问题</li>
- <li>优化Oracle用户头像列为空时不显示问题</li>
- <li>优化页面若未匹配到字典标签则返回原字典值</li>
- <li>优化修复登录失效后多次请求提示多次弹窗问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.4.0 - 2022-01-24">
- <ol>
- <li>新增Vue3前端代码生成模板</li>
- <li>新增图片预览组件</li>
- <li>新增压缩插件实现打包Gzip</li>
- <li>新增docker一键复制的脚本</li>
- <li>自定义xss校验注解实现</li>
- <li>路由支持单独配置菜单或角色权限</li>
- <li>前端支持设置是否需要防止数据重复提交</li>
- <li>预览组件支持多图显示</li>
- <li>代码生成列表图片支持预览</li>
- <li>代码生成新增Java类型Boolean</li>
- <li>定时任务目标字符串过滤特殊字符</li>
- <li>定时任务目标字符串验证包名白名单</li>
- <li>升级nacos到最新版2.0.4</li>
- <li>升级spring-cloud到最新版2021.0.0</li>
- <li>升级spring-boot到最新版本2.6.3</li>
- <li>升级spring-boot-admin到最新版2.6.1</li>
- <li>升级pagehelper到最新版1.4.1</li>
- <li>升级fastjson到最新版1.2.79</li>
- <li>SQL工具类新增检查关键字方法</li>
- <li>修复打包后字体图标偶现的乱码问题</li>
- <li>修复版本差异导致的懒加载报错问题</li>
- <li>修复选项卡点击右键刷新丢失参数问题</li>
- <li>修复登录失效后多次请求提示多次弹窗问题</li>
- <li>优化加载字典缓存数据</li>
- <li>优化代码生成同步更新字段</li>
- <li>优化代码生成字典组重复问题</li>
- <li>优化空值不进行回显数据字典</li>
- <li>优化用户导入提示溢出则显示滚动条</li>
- <li>优化定时任务cron表达式小时设置24</li>
- <li>优化部门修改缩放后出现的错位问题</li>
- <li>优化分页方法设置成通用方便灵活调用</li>
- <li>优化用户管理部门查询选择节点后分页参数初始</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.3.0 - 2021-12-13">
- <ol>
- <li>新增配套并同步的Vue3前端版本</li>
- <li>新增认证对象简化权限验证</li>
- <li>新增tab对象简化页签操作</li>
- <li>修改获取缓存信息方式</li>
- <li>修改权限认证注解实现</li>
- <li>自定义文字复制剪贴指令</li>
- <li>升级axios到最新版本0.24.0</li>
- <li>升级core-js到最新版本3.19.1</li>
- <li>升级jsencrypt到最新版本3.2.1</li>
- <li>升级js-cookie到最新版本3.0.1</li>
- <li>升级clipboard到最新版本2.0.8</li>
- <li>升级velocity到最新版本2.3</li>
- <li>升级spring-boot到最新版本2.5.6</li>
- <li>升级spring-boot-admin到最新版2.5.4</li>
- <li>升级dynamic-ds到最新版本3.5.0</li>
- <li>代码生成预览支持复制内容</li>
- <li>修复五级以上菜单出现的404问题</li>
- <li>生产环境使用路由懒加载提升页面响应速度</li>
- <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
- <li>优化用户个人信息接口防止修改用户名</li>
- <li>优化登录/验证码请求headers不设置token</li>
- <li>优化注册成功提示消息类型success</li>
- <li>优化下载解析blob响应是否登录失效</li>
- <li>修复字符串无法被反转义问题</li>
- <li>修复响应体过大出现的乱码问题</li>
- <li>修复回显数据字典组的键值错误</li>
- <li>修复代码生成复选框字典遗漏问题</li>
- <li>修复代码生成模板主子表删除缺少事务</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.2.0 - 2021-10-12">
- <ol>
- <li>菜单管理支持配置路由参数</li>
- <li>定时任务支持在线生成cron表达式</li>
- <li>自定义弹层溢出滚动样式</li>
- <li>自定义可拖动弹窗宽度指令</li>
- <li>自定义可拖动弹窗高度指令</li>
- <li>修改时检查用户数据权限范围</li>
- <li>修复保存配置主题颜色失效问题</li>
- <li>新增暗色菜单风格主题</li>
- <li>菜单&部门新增展开/折叠功能</li>
- <li>页签新增关闭左侧&添加图标</li>
- <li>代码生成主子表多选行数据</li>
- <li>日期范围支持添加多组</li>
- <li>Excel导入支持@Excels注解</li>
- <li>Excel注解支持导入导出标题信息</li>
- <li>Excel注解支持自定义数据处理器</li>
- <li>日志注解新增是否保存响应参数</li>
- <li>定时任务对检查异常进行事务回滚</li>
- <li>补充定时任务表字段注释</li>
- <li>定时任务屏蔽ldap远程调用</li>
- <li>新增通用方法简化下载使用</li>
- <li>新增通用方法简化模态/缓存使用</li>
- <li>新增data-dict组件简化数据字典使用</li>
- <li>禁用dict-tag组件的渐变动画</li>
- <li>默认首页使用keep-alive缓存</li>
- <li>升级springcloud到最新版2020.0.4</li>
- <li>升级spring-boot到最新版本2.5.5</li>
- <li>升级spring-boot-admin到最新版2.5.2</li>
- <li>升级pagehelper到最新版1.4.0</li>
- <li>升级fastjson到最新版1.2.78</li>
- <li>升级druid到最新版1.2.8</li>
- <li>升级element-ui到最新版本2.15.6</li>
- <li>升级sass-loader到最新版本10.1.1</li>
- <li>升级dart-sass到版本1.32.13</li>
- <li>升级file-saver到最新版本2.0.5</li>
- <li>优化异常处理信息</li>
- <li>验证码默认20s超时</li>
- <li>优化代码生成导入表按创建时间排序</li>
- <li>优化代码生成点击预览重置激活tab</li>
- <li>修复主子表代码模板方法名错误问题</li>
- <li>修复xss过滤后格式出现的异常</li>
- <li>修复多图组件验证失败被删除问题</li>
- <li>请求参数新增reasonable分页合理化属性</li>
- <li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
- <li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.1.0 - 2021-08-02">
- <ol>
- <li>支持配置XSS跨站脚本过滤</li>
- <li>支持配置验证码开关&类型</li>
- <li>新增是否开启用户注册功能</li>
- <li>用户管理新增分配角色功能</li>
- <li>角色管理新增分配用户功能</li>
- <li>系统布局配置支持动态标题开关</li>
- <li>增加字典标签样式回显dict组件</li>
- <li>FileUpload组件支持多文件上传</li>
- <li>ImageUpload组件支持多图片上传</li>
- <li>封装通用iframe组件</li>
- <li>菜单路由配置支持内链访问</li>
- <li>全局注册通用组件</li>
- <li>富文本默认上传返回url类型</li>
- <li>富文本新增上传文件大小限制</li>
- <li>增加自定义弹窗拖拽指令</li>
- <li>顶部菜单排除隐藏的默认路由</li>
- <li>跳转路由高亮相对应的菜单栏</li>
- <li>日志列表支持排序操作</li>
- <li>分页组件新增pagerCount属性</li>
- <li>定时任务屏蔽http(s)远程调用</li>
- <li>文件服务本地资源允许跨域访问</li>
- <li>升级spring-boot到最新版本2.5.3</li>
- <li>升级spring-boot-admin到最新版2.4.3</li>
- <li>升级spring-boot-mybatis到最新版2.2.0</li>
- <li>升级nacos到最新版2.0.3</li>
- <li>升级pagehelper到最新版1.3.1</li>
- <li>升级minio到最新版本8.2.2</li>
- <li>升级tobato到最新版本1.27.2</li>
- <li>升级dynamic-ds到最新版本3.4.1</li>
- <li>升级commons.io到最新版本v2.11.0</li>
- <li>升级common-pool到最新版本2.10.0</li>
- <li>升级commons.fileupload到最新版本v1.4</li>
- <li>升级element-ui到最新版本2.15.3</li>
- <li>优化统一网关错误码响应</li>
- <li>修复导出含params属性对象参数问题</li>
- <li>修复任意账户越权问题</li>
- <li>修复定时任务日志执行状态显示</li>
- <li>修改登录失效返回值code401</li>
- <li>用户信息长度校验限制</li>
- <li>角色&菜单新增字段属性提示信息</li>
- <li>修复用户搜索分页变量错误</li>
- <li>优化部门父级启用状态</li>
- <li>启用部门状态排除顶级节点</li>
- <li>定时任务新增更多操作</li>
- <li>优化代码生成模板</li>
- <li>优化顶部菜单显示样式</li>
- <li>优化导入用户显示样式</li>
- <li>优化用户不能删除自己</li>
- <li>密码框新增显示切换密码图标</li>
- <li>BLOB下载时清除URL对象引用</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v3.0.0 - 2021-06-10">
- <ol>
- <li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li>
- <li>布局设置支持保存&重置配置</li>
- <li>富文本编辑器支持自定义上传地址</li>
- <li>富文本编辑组件新增readOnly属性</li>
- <li>优化参数&字典缓存操作</li>
- <li>新增IE浏览器版本过低提示页面</li>
- <li>页签TagsView新增关闭右侧功能</li>
- <li>显隐列组件加载初始默认隐藏列</li>
- <li>关闭头像上传窗口还原默认图片</li>
- <li>个人信息添加手机&邮箱重复验证</li>
- <li>代码生成模板树表操作列添加新增按钮</li>
- <li>代码生成模板修复主子表字段重名问题</li>
- <li>支持docker部署项目</li>
- <li>升级springcloud到最新版2020.0.3</li>
- <li>升级spring-boot-alibaba到最新版2021.1</li>
- <li>升级nacos到最新版2.0.1 性能提升</li>
- <li>升级spring-boot到最新版本2.5.0</li>
- <li>升级spring-boot-admin到最新版2.4.1</li>
- <li>升级swagger到最新版本3.0.0</li>
- <li>升级mybatis到最新版3.5.6</li>
- <li>升级dynamic-ds到最新版本3.3.2</li>
- <li>升级minio到最新版本8.2.1</li>
- <li>升级fastjson到最新版1.2.76</li>
- <li>升级druid到最新版本v1.2.6</li>
- <li>修复四级菜单无法显示问题</li>
- <li>修复树表数据显示不全&加载慢问题</li>
- <li>修复关闭confirm提示框控制台报错问题</li>
- <li>上传媒体类型添加视频格式</li>
- <li>增加feign客户端IP头部信息</li>
- <li>修复两处存在SQL注入漏洞问题</li>
- <li>优化图片工具类读取文件,防止异常</li>
- <li>修复导出角色数据范围翻译缺少仅本人</li>
- <li>修复表单构建选择下拉选择控制台报错问题</li>
- <li>修复请求形参未传值记录日志异常问题</li>
- <li>调整sql默认为当前时间</li>
- <li>修改ip字段长度防止ipv6地址长度不够</li>
- <li>删除操作日志记录信息</li>
- <li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
- <li>用户&角色单条删除时使其逻辑删除</li>
- <li>优化树表代码生成模板</li>
- <li>修正通知公告日志记录类型</li>
- <li>修正后端导入表权限标识</li>
- <li>过滤BindingResult对象,防止异常</li>
- <li>Redis设置HashKey序列化</li>
- <li>优化Excel导入增加空行判断</li>
- <li>树级结构更新子节点使用replaceFirst</li>
- <li>富文本工具栏配置视频</li>
- <li>修正模板字符编码</li>
- <li>优化通用下载完成后删除节点</li>
- <li>角色非自定义权限范围清空选择值</li>
- <li>修改主题后mini类型按钮无效问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v2.5.0 - 2021-02-02">
- <ol>
- <li>增加分布式事务seata支持</li>
- <li>代码生成模板支持主子表</li>
- <li>表格右侧工具栏组件支持显隐列</li>
- <li>图片组件添加预览&移除功能</li>
- <li>Excel注解支持Image图片导出</li>
- <li>操作按钮组调整为朴素按钮样式</li>
- <li>代码生成支持文件上传组件</li>
- <li>代码生成日期控件区分范围</li>
- <li>代码生成数据库文本类型生成表单文本域</li>
- <li>用户手机邮箱&菜单组件修改允许空字符串</li>
- <li>修复header获取username中文情况下乱码</li>
- <li>修复角色管理-编辑角色-功能权限显示异常</li>
- <li>修正操作日志删除接口路径</li>
- <li>修复IE11浏览器报错问题</li>
- <li>修复sentinel流量告警前端不响应</li>
- <li>修正侧边栏静态路由丢失问题</li>
- <li>修复导入数据为负浮点数时丢失精度问题</li>
- <li>修复Get请求参数特殊值无法正确的传参</li>
- <li>更换过期的共享配置属性</li>
- <li>添加启动执行脚本</li>
- <li>升级element-ui到最新版本2.15.0</li>
- <li>升级spring-boot到最新版本2.3.7</li>
- <li>升级spring-cloud到Hoxton.SR9</li>
- <li>升级spring-boot-alibaba到最新版2.2.5</li>
- <li>升级spring-boot-admin到最新版2.3.1</li>
- <li>升级druid到最新版本v1.2.4</li>
- <li>升级fastjson到最新版1.2.75</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v2.4.0 - 2020-12-22">
- <ol>
- <li>增加分布式文件Minio支持</li>
- <li>支持多数据源切换</li>
- <li>修复多级菜单之间切换无法缓存的问题</li>
- <li>三级菜单自动配置组件</li>
- <li>支持主题风格配置</li>
- <li>服务之间feign调用传递用户信息</li>
- <li>删除用户和角色解绑关联</li>
- <li>去除用户手机邮箱部门必填验证</li>
- <li>代码生成预览支持高亮显示</li>
- <li>获取请求token方法移至权限工具类</li>
- <li>代码生成预览提供滚动机制</li>
- <li>权限工具类增加管理员判断</li>
- <li>日志记录增加过滤多文件场景</li>
- <li>修改用户头像预览宽高</li>
- <li>Excel支持注解align对齐方式</li>
- <li>项目添加robots.txt 防止系统被搜索引擎收录</li>
- <li>移除path-to-regexp正则匹配插件</li>
- <li>修改Set可能导致嵌套的问题</li>
- <li>调整代码生成页列宽</li>
- <li>回显数据字典防止空值报错</li>
- <li>支持get请求映射params参数</li>
- <li>登录后push添加catch防止出现检查错误</li>
- <li>防止安全扫描YUI出现的风险提示</li>
- <li>代码生成删除多余的数字float类型</li>
- <li>Excel支持导入Boolean型数据</li>
- <li>修正转换字符串的目标字符集属性</li>
- <li>删除多余的依赖</li>
- <li>修改node-sass为dart-sass</li>
- <li>升级poi到最新版本4.1.2</li>
- <li>升级axios到最新版本0.21.0</li>
- <li>升级element-ui到最新版本2.14.1</li>
- <li>升级vue到最新版本2.6.12</li>
- <li>升级vuex到最新版本3.6.0</li>
- <li>升级vue-cli到版本4.5.9</li>
- <li>升级vue-router到最新版本3.4.9</li>
- <li>升级vue-cli到最新版本4.4.6</li>
- <li>升级vue-cropper到最新版本0.5.5</li>
- <li>升级clipboard到最新版本2.0.6</li>
- <li>升级core-js到最新版本3.8.1</li>
- <li>升级echarts到最新版本4.9.0</li>
- <li>升级file-saver到最新版本2.0.4</li>
- <li>升级fuse.js到最新版本6.4.3</li>
- <li>升级js-beautify到最新版本1.13.0</li>
- <li>升级js-cookie到最新版本2.2.1</li>
- <li>升级path-to-regexp到最新版本6.2.0</li>
- <li>升级quill到最新版本1.3.7</li>
- <li>升级screenfull到最新版本5.0.2</li>
- <li>升级sortablejs到最新版本1.10.2</li>
- <li>升级vuedraggable到最新版本2.24.3</li>
- <li>升级chalk到最新版本4.1.0</li>
- <li>升级eslint到最新版本7.15.0</li>
- <li>升级eslint-plugin-vue到最新版本7.2.0</li>
- <li>升级lint-staged到最新版本10.5.3</li>
- <li>升级runjs到最新版本4.4.2</li>
- <li>升级sass-loader到最新版本10.1.0</li>
- <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
- <li>升级svg-sprite-loader到最新版本5.1.1</li>
- <li>升级vue-template-compiler到最新版本2.6.12</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v2.3.0 - 2020-11-20">
- <ol>
- <li>新增文件服务应用(支持本地、FastDFS)</li>
- <li>优化头像样式,鼠标移入悬停遮罩</li>
- <li>AjaxResult重写put方法,以方便链式调用</li>
- <li>代码生成支持上传控件</li>
- <li>新增图片上传组件</li>
- <li>支持用户头像更新</li>
- <li>调整默认首页</li>
- <li>角色权限验证hasRole匹配改为equals</li>
- <li>修正数组权限为空判断</li>
- <li>修正注释选中节点和半选节点获取</li>
- <li>升级pagehelper到最新版1.3.0</li>
- <li>升级fastjson到最新版1.2.74</li>
- <li>修正定时任务执行一次权限标识</li>
- <li>修复页签关闭所有固定标签路由不刷新问题</li>
- <li>表单构建布局型组件新增按钮</li>
- <li>调整日志路径到模块目录</li>
- <li>修正菜单提示信息错误</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v2.2.0 - 2020-10-10">
- <ol>
- <li>移除 OAuth2 改为 Redis</li>
- <li>升级SpringCloud到最新版本Hoxton.SR8</li>
- <li>升级SpringCloud Alibaba到最新版本2.2.3</li>
- <li>升级SpringBoot Admin到最新版本2.3.0</li>
- <li>升级Fastjson到最新版1.2.73</li>
- <li>新增在线用户会话管理</li>
- <li>修改用户个人资料/密码同步缓存信息</li>
- <li>修复前端通用导出方法参数传值请求方式问题</li>
- <li>菜单新增是否缓存keep-alive</li>
- <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
- <li>Job与Gen模块增加Redis默认配置</li>
- <li>新增表格右侧工具栏组件right-toolbar</li>
- <li>代码生成支持同步数据库</li>
- <li>代码生成支持富文本控件</li>
- <li>代码生成树模板去掉多余双引号</li>
- <li>代码生成添加select必填选项</li>
- <li>代码生成页面时不忽略remark属性</li>
- <li>修复代码生成下载路径错误</li>
- <li>左侧菜单文字过长显示省略号</li>
- <li>表格操作列间距调整</li>
- <li>Excel注解支持自动统计数据总和</li>
- <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
- <li>导入Excel整形值校验优化</li>
- <li>导出Excel类型NUMERIC支持精度浮点类型</li>
- <li>导出Excel调整targetAttr获取值方法,防止get方法不规范</li>
- <li>Token续期调整为后端刷新</li>
- <li>Token设置默认有效期时长12小时</li>
- <li>网关白名单放入nacos配置&支持模糊匹配</li>
- <li>修复富文本工具栏样式不对齐问题</li>
- <li>Editor组件优化,支持自定义高度&图片冲突问题</li>
- <li>修复富文本空格和缩进保存后不生效问题&删除重复的placeholder</li>
- <li>限制系统内置参数不允许删除</li>
- <li>修正调用目标字符串最大长度</li>
- <li>修改自定义权限实现</li>
- <li>优化递归菜单&部门子节点</li>
- <li>修改sass为node-sass,避免el-icon图标乱码</li>
- <li>修复根节点为子部门时,树状结构显示问题</li>
- <li>全局异常状态汉化拦截处理</li>
- <li>唯一限制条件只返回单条数据</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
-
- <el-collapse-item title="v2.1.0 - 2020-08-02">
- <ol>
- <li>表格工具栏右侧添加刷新&显隐查询栏</li>
- <li>OAuth自动刷新续签Token</li>
- <li>网关支持黑名单配置</li>
- <li>权限配置自动注册</li>
- <li>Feign配置自动注册</li>
- <li>代码生成支持选择上级菜单</li>
- <li>代码生成支持复选框</li>
- <li>代码生成支持自定义路径</li>
- <li>验证码类型支持(数组计算、字符验证)</li>
- <li>Excel支持sort导出排序</li>
- <li>Excel支持分割字符串组内容</li>
- <li>excel 导入数字不需要格式化 ,导入允许列和属性个数不一致</li>
- <li>新增菜单默认主类目</li>
- <li>升级vue-cli版本到4.4.4</li>
- <li>修改 node-sass 为 dart-sass</li>
- <li>升级element-ui版本到2.13.2</li>
- <li>删除babel,提高编译速度</li>
- <li>修复验证码异常时network面板的中文会出现乱码问题</li>
- <li>修复 utils/index.js 中不包含 parseTime 函数的 bug</li>
- <li>优化selectDictLabel方法,数组迭代器换为some</li>
- <li>修复客户端模式认证会出现错误</li>
- <li>检查字符支持小数点&降级改成异常提醒</li>
- <li>定时任务添加cron表达式验证</li>
- <li>代码生成查询条件修正</li>
- <li>修正角色管理导出权限权限字符</li>
- <li>修正防止切换权限用户后登录出现404</li>
- <li>终端设置安全码加密&更新缓存</li>
- <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
- <li>修复布局为small者mini用户表单显示错位问题</li>
- <li>修复代码生成点击多次表修改数据不变化的问题</li>
- <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
- <li>修复角色权限修改时已有权限未自动勾选异常</li>
- <li>创建用户不允许选择系统管理员角色</li>
- <li>添加全局异常处理(网关异常&业务异常)</li>
- <li>修复终端查询Enter键搜索时是刷新页面而不是查询列表</li>
- <li>删除job重复表单参数</li>
- <li>代码生成浮点型改用BigDecimal</li>
- <li>表单类型为Integer/Long设置整形默认值</li>
- <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
- <li>RedisCache中所有方法参数添加final,并优化list取出效率,添加其它常用redis方法</li>
- <li>修正定时任务日志权限字符</li>
- <li>添加Jackson时区配置</li>
- <li>代码生成相关问题修复</li>
- <li>自定义oauth2返回异常信息</li>
- <li>升级nacos到最新版1.3.0 全新内核构建</li>
- <li>修正【代码生成】功能无法下载的问题</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
-
- <el-collapse-item title="v2.0.0 - 2019-12-02">
- <ol>
- <li>新增代码生成</li>
- <li>新增@RepeatSubmit注解,防止重复提交</li>
- <li>新增菜单主目录添加/删除操作</li>
- <li>日志记录过滤特殊对象,防止转换异常</li>
- <li>修改代码生成路由脚本错误</li>
- <li>用户上传头像实时同步缓存,无需重新登录</li>
- <li>调整切换页签后不重新加载数据</li>
- <li>添加jsencrypt实现参数的前端加密</li>
- <li>系统退出删除用户缓存记录</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v2.0.0 - 2020-06-10">
- <ol>
- <li>使用Sentinel代替Hystrix</li>
- <li>菜单新增终端管理配置</li>
- <li>菜单新增Nacos&Sentinel控制台</li>
- <li>代码生成适配Cloud</li>
- <li>记录登录退出日志信息</li>
- <li>网关验证码过滤器添加放行校验</li>
- <li>个性化的定制自动加载类</li>
- <li>定时任务调整label-width,防止部署出现错位</li>
- <li>调整表头固定列默认样式</li>
- <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
- <li>代码生成字典Integer/Long使用parseInt</li>
- <li>修复退出登录重定向到登录页,登录后参数丢失。</li>
- <li>修正岗位导出权限注解</li>
- <li>修复首页搜索菜单外链无法点击跳转问题</li>
- <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
- <li>用户管理部门分支节点不可检查&显示计数</li>
- <li>数据范围过滤属性调整</li>
- <li>字典管理添加缓存读取</li>
- <li>参数管理支持缓存操作</li>
- <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
- <li>dev启动默认打开浏览器</li>
- <li>使用vue-cli默认source-map</li>
- <li>slidebar eslint报错优化</li>
- <li>当tags-view滚动关闭右键菜单</li>
- <li>支持一级菜单(和主页同级)在main区域显示</li>
- <li>限制外链地址必须以http(s)😕/开头</li>
- <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
- <li>修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序</li>
- <li>权限部分代码调整</li>
- <li>其他细节优化</li>
- </ol>
- </el-collapse-item>
- <el-collapse-item title="v1.0.0 - 2020-05-20">
- <ol>
- <li>若依微服务系统正式发布</li>
- </ol>
- </el-collapse-item>
- </el-collapse>
- </el-card>
- </el-col>
- <el-col :xs="24" :sm="24" :md="12" :lg="8">
- <el-card class="update-log">
- <div slot="header" class="clearfix">
- <span>捐赠支持</span>
- </div>
- <div class="body">
- <img
- src="@/assets/images/pay.png"
- alt="donate"
- width="100%"
- />
- <span style="display: inline-block; height: 30px; line-height: 30px"
- >你可以请作者喝杯咖啡表示鼓励</span
- >
- </div>
- </el-card>
- </el-col>
- </el-row>
- </div>
-</template>
-
-<script>
-export default {
- name: "Index",
- data() {
- return {
- // 版本号
- version: "3.6.8"
- }
- },
- methods: {
- goTarget(href) {
- window.open(href, "_blank")
- }
- }
-}
-</script>
-
-<style scoped lang="scss">
-.home {
- blockquote {
- padding: 10px 20px;
- margin: 0 0 20px;
- font-size: 17.5px;
- border-left: 5px solid #eee;
- }
- hr {
- margin-top: 20px;
- margin-bottom: 20px;
- border: 0;
- border-top: 1px solid #eee;
- }
- .col-item {
- margin-bottom: 20px;
- }
-
- ul {
- padding: 0;
- margin: 0;
- }
-
- font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 13px;
- color: #676a6c;
- overflow-x: hidden;
-
- ul {
- list-style-type: none;
- }
-
- h4 {
- margin-top: 0px;
- }
-
- h2 {
- margin-top: 10px;
- font-size: 26px;
- font-weight: 100;
- }
-
- p {
- margin-top: 10px;
-
- b {
- font-weight: 700;
- }
- }
-
- .update-log {
- ol {
- display: block;
- list-style-type: decimal;
- margin-block-start: 1em;
- margin-block-end: 1em;
- margin-inline-start: 0;
- margin-inline-end: 0;
- padding-inline-start: 40px;
- }
- }
-}
-</style>
-
diff --git a/ruoyi-ui/src/views/index_v1.vue b/ruoyi-ui/src/views/index_v1.vue
deleted file mode 100644
index 4828d88..0000000
--- a/ruoyi-ui/src/views/index_v1.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-<template>
- <div class="dashboard-editor-container">
-
- <panel-group @handleSetLineChartData="handleSetLineChartData" />
-
- <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
- <line-chart :chart-data="lineChartData" />
- </el-row>
-
- <el-row :gutter="32">
- <el-col :xs="24" :sm="24" :lg="8">
- <div class="chart-wrapper">
- <raddar-chart />
- </div>
- </el-col>
- <el-col :xs="24" :sm="24" :lg="8">
- <div class="chart-wrapper">
- <pie-chart />
- </div>
- </el-col>
- <el-col :xs="24" :sm="24" :lg="8">
- <div class="chart-wrapper">
- <bar-chart />
- </div>
- </el-col>
- </el-row>
-
-
- </div>
-</template>
-
-<script>
-import PanelGroup from './dashboard/PanelGroup'
-import LineChart from './dashboard/LineChart'
-import RaddarChart from './dashboard/RaddarChart'
-import PieChart from './dashboard/PieChart'
-import BarChart from './dashboard/BarChart'
-
-const lineChartData = {
- newVisitis: {
- expectedData: [100, 120, 161, 134, 105, 160, 165],
- actualData: [120, 82, 91, 154, 162, 140, 145]
- },
- messages: {
- expectedData: [200, 192, 120, 144, 160, 130, 140],
- actualData: [180, 160, 151, 106, 145, 150, 130]
- },
- purchases: {
- expectedData: [80, 100, 121, 104, 105, 90, 100],
- actualData: [120, 90, 100, 138, 142, 130, 130]
- },
- shoppings: {
- expectedData: [130, 140, 141, 142, 145, 150, 160],
- actualData: [120, 82, 91, 154, 162, 140, 130]
- }
-}
-
-export default {
- name: 'Index',
- components: {
- PanelGroup,
- LineChart,
- RaddarChart,
- PieChart,
- BarChart
- },
- data() {
- return {
- lineChartData: lineChartData.newVisitis
- }
- },
- methods: {
- handleSetLineChartData(type) {
- this.lineChartData = lineChartData[type]
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.dashboard-editor-container {
- padding: 32px;
- background-color: rgb(240, 242, 245);
- position: relative;
-
- .chart-wrapper {
- background: #fff;
- padding: 16px 16px 0;
- margin-bottom: 32px;
- }
-}
-
-@media (max-width:1024px) {
- .chart-wrapper {
- padding: 8px;
- }
-}
-</style>
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
deleted file mode 100644
index 30ff921..0000000
--- a/ruoyi-ui/src/views/login.vue
+++ /dev/null
@@ -1,223 +0,0 @@
-<template>
- <div class="login">
- <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
- <h3 class="title">{{title}}</h3>
- <el-form-item prop="username">
- <el-input
- v-model="loginForm.username"
- type="text"
- auto-complete="off"
- placeholder="账号"
- >
- <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
- </el-input>
- </el-form-item>
- <el-form-item prop="password">
- <el-input
- v-model="loginForm.password"
- type="password"
- auto-complete="off"
- placeholder="密码"
- @keyup.enter.native="handleLogin"
- >
- <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
- </el-input>
- </el-form-item>
- <el-form-item prop="code" v-if="captchaEnabled">
- <el-input
- v-model="loginForm.code"
- auto-complete="off"
- placeholder="验证码"
- style="width: 63%"
- @keyup.enter.native="handleLogin"
- >
- <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
- </el-input>
- <div class="login-code">
- <img :src="codeUrl" @click="getCode" class="login-code-img"/>
- </div>
- </el-form-item>
- <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
- <el-form-item style="width:100%;">
- <el-button
- :loading="loading"
- size="medium"
- type="primary"
- style="width:100%;"
- @click.native.prevent="handleLogin"
- >
- <span v-if="!loading">登 录</span>
- <span v-else>登 录 中...</span>
- </el-button>
- <div style="float: right;" v-if="register">
- <router-link class="link-type" :to="'/register'">立即注册</router-link>
- </div>
- </el-form-item>
- </el-form>
- <!-- 底部 -->
- <div class="el-login-footer">
- <span>{{ footerContent }}</span>
- </div>
- </div>
-</template>
-
-<script>
-import { getCodeImg } from "@/api/login"
-import Cookies from "js-cookie"
-import { encrypt, decrypt } from '@/utils/jsencrypt'
-import defaultSettings from '@/settings'
-
-export default {
- name: "Login",
- data() {
- return {
- title: process.env.VUE_APP_TITLE,
- footerContent: defaultSettings.footerContent,
- codeUrl: "",
- loginForm: {
- username: "admin",
- password: "admin123",
- rememberMe: false,
- code: "",
- uuid: ""
- },
- loginRules: {
- username: [
- { required: true, trigger: "blur", message: "请输入您的账号" }
- ],
- password: [
- { required: true, trigger: "blur", message: "请输入您的密码" }
- ],
- code: [{ required: true, trigger: "change", message: "请输入验证码" }]
- },
- loading: false,
- // 验证码开关
- captchaEnabled: true,
- // 注册开关
- register: false,
- redirect: undefined
- }
- },
- watch: {
- $route: {
- handler: function(route) {
- this.redirect = route.query && route.query.redirect
- },
- immediate: true
- }
- },
- created() {
- this.getCode()
- this.getCookie()
- },
- methods: {
- getCode() {
- getCodeImg().then(res => {
- this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
- if (this.captchaEnabled) {
- this.codeUrl = "data:image/gif;base64," + res.img
- this.loginForm.uuid = res.uuid
- }
- })
- },
- getCookie() {
- const username = Cookies.get("username")
- const password = Cookies.get("password")
- const rememberMe = Cookies.get('rememberMe')
- this.loginForm = {
- username: username === undefined ? this.loginForm.username : username,
- password: password === undefined ? this.loginForm.password : decrypt(password),
- rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
- }
- },
- handleLogin() {
- this.$refs.loginForm.validate(valid => {
- if (valid) {
- this.loading = true
- if (this.loginForm.rememberMe) {
- Cookies.set("username", this.loginForm.username, { expires: 30 })
- Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
- Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
- } else {
- Cookies.remove("username")
- Cookies.remove("password")
- Cookies.remove('rememberMe')
- }
- this.$store.dispatch("Login", this.loginForm).then(() => {
- this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
- }).catch(() => {
- this.loading = false
- if (this.captchaEnabled) {
- this.getCode()
- }
- })
- }
- })
- }
- }
-}
-</script>
-
-<style rel="stylesheet/scss" lang="scss" scoped>
-.login {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- background-image: url("../assets/images/login-background.jpg");
- background-size: cover;
-}
-.title {
- margin: 0px auto 30px auto;
- text-align: center;
- color: #707070;
-}
-
-.login-form {
- border-radius: 6px;
- background: #ffffff;
- width: 400px;
- padding: 25px 25px 5px 25px;
- z-index: 1;
- .el-input {
- height: 38px;
- input {
- height: 38px;
- }
- }
- .input-icon {
- height: 39px;
- width: 14px;
- margin-left: 2px;
- }
-}
-.login-tip {
- font-size: 13px;
- text-align: center;
- color: #bfbfbf;
-}
-.login-code {
- width: 33%;
- height: 38px;
- float: right;
- img {
- cursor: pointer;
- vertical-align: middle;
- }
-}
-.el-login-footer {
- height: 40px;
- line-height: 40px;
- position: fixed;
- bottom: 0;
- width: 100%;
- text-align: center;
- color: #fff;
- font-family: Arial;
- font-size: 12px;
- letter-spacing: 1px;
-}
-.login-code-img {
- height: 38px;
-}
-</style>
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
deleted file mode 100644
index 15b253f..0000000
--- a/ruoyi-ui/src/views/monitor/job/index.vue
+++ /dev/null
@@ -1,471 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="任务名称" prop="jobName">
- <el-input
- v-model="queryParams.jobName"
- placeholder="请输入任务名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="任务组名" prop="jobGroup">
- <el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable>
- <el-option
- v-for="dict in dict.type.sys_job_group"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="任务状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>
- <el-option
- v-for="dict in dict.type.sys_job_status"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['monitor:job:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['monitor:job:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['monitor:job:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['monitor:job:export']"
- >导出</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="info"
- plain
- icon="el-icon-s-operation"
- size="mini"
- @click="handleJobLog"
- v-hasPermi="['monitor:job:query']"
- >日志</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="任务编号" width="100" align="center" prop="jobId" />
- <el-table-column label="任务名称" align="center" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <a class="link-type" style="cursor:pointer" @click="handleView(scope.row)">{{ scope.row.jobName }}</a>
- </template>
- </el-table-column>
- <el-table-column label="任务组名" align="center" prop="jobGroup">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
- </template>
- </el-table-column>
- <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
- <el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
- <el-table-column label="状态" align="center">
- <template slot-scope="scope">
- <el-switch
- v-model="scope.row.status"
- active-value="0"
- inactive-value="1"
- @change="handleStatusChange(scope.row)"
- ></el-switch>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['monitor:job:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['monitor:job:remove']"
- >删除</el-button>
- <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['monitor:job:changeStatus', 'monitor:job:query']">
- <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="handleRun" icon="el-icon-caret-right"
- v-hasPermi="['monitor:job:changeStatus']">执行一次</el-dropdown-item>
- <el-dropdown-item command="handleJobLog" icon="el-icon-s-operation"
- v-hasPermi="['monitor:job:query']">调度日志</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改定时任务对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="120px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="任务名称" prop="jobName">
- <el-input v-model="form.jobName" placeholder="请输入任务名称" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="任务分组" prop="jobGroup">
- <el-select v-model="form.jobGroup" placeholder="请选择任务分组">
- <el-option
- v-for="dict in dict.type.sys_job_group"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item prop="invokeTarget">
- <span slot="label">
- 调用方法
- <el-tooltip placement="top">
- <div slot="content">
- Bean调用示例:ryTask.ryParams('ry')
- <br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
- <br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
- </div>
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="cron表达式" prop="cronExpression">
- <el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
- <template slot="append">
- <el-button type="primary" @click="handleShowCron">
- 生成表达式
- <i class="el-icon-time el-icon--right"></i>
- </el-button>
- </template>
- </el-input>
- </el-form-item>
- </el-col>
- <el-col :span="24" v-if="form.jobId !== undefined">
- <el-form-item label="状态">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_job_status"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="执行策略" prop="misfirePolicy">
- <el-radio-group v-model="form.misfirePolicy" size="small">
- <el-radio-button label="1">立即执行</el-radio-button>
- <el-radio-button label="2">执行一次</el-radio-button>
- <el-radio-button label="3">放弃执行</el-radio-button>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="是否并发" prop="concurrent">
- <el-radio-group v-model="form.concurrent" size="small">
- <el-radio-button label="0">允许</el-radio-button>
- <el-radio-button label="1">禁止</el-radio-button>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
-
- <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
- <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
- </el-dialog>
-
- <!-- 任务日志详细 -->
- <job-detail :visible.sync="openView" :row="form" type="job" />
- </div>
-</template>
-
-<script>
-import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"
-import JobDetail from './detail'
-import Crontab from '@/components/Crontab'
-
-export default {
- components: { Crontab, JobDetail },
- name: "Job",
- dicts: ['sys_job_group', 'sys_job_status'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 定时任务表格数据
- jobList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 是否显示详细弹出层
- openView: false,
- // 是否显示Cron表达式弹出层
- openCron: false,
- // 传入的表达式
- expression: "",
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- jobName: undefined,
- jobGroup: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- jobName: [
- { required: true, message: "任务名称不能为空", trigger: "blur" }
- ],
- invokeTarget: [
- { required: true, message: "调用目标字符串不能为空", trigger: "blur" }
- ],
- cronExpression: [
- { required: true, message: "cron执行表达式不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询定时任务列表 */
- getList() {
- this.loading = true
- listJob(this.queryParams).then(response => {
- this.jobList = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- // 任务组名字典翻译
- jobGroupFormat(row, column) {
- return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup)
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- jobId: undefined,
- jobName: undefined,
- jobGroup: undefined,
- invokeTarget: undefined,
- cronExpression: undefined,
- misfirePolicy: 1,
- concurrent: 1,
- status: "0"
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.jobId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- // 更多操作触发
- handleCommand(command, row) {
- switch (command) {
- case "handleRun":
- this.handleRun(row)
- break
- case "handleView":
- this.handleView(row)
- break
- case "handleJobLog":
- this.handleJobLog(row)
- break
- default:
- break
- }
- },
- // 任务状态修改
- handleStatusChange(row) {
- let text = row.status === "0" ? "启用" : "停用"
- this.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function() {
- return changeJobStatus(row.jobId, row.status)
- }).then(() => {
- this.$modal.msgSuccess(text + "成功")
- }).catch(function() {
- row.status = row.status === "0" ? "1" : "0"
- })
- },
- /* 立即执行一次 */
- handleRun(row) {
- this.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function() {
- return runJob(row.jobId, row.jobGroup)
- }).then(() => {
- this.$modal.msgSuccess("执行成功")
- }).catch(() => {})
- },
- /** 任务详细信息 */
- handleView(row) {
- getJob(row.jobId).then(response => {
- this.form = response.data
- this.openView = true
- })
- },
- /** cron表达式按钮操作 */
- handleShowCron() {
- this.expression = this.form.cronExpression
- this.openCron = true
- },
- /** 确定后回传值 */
- crontabFill(value) {
- this.form.cronExpression = value
- },
- /** 任务日志列表查询 */
- handleJobLog(row) {
- const jobId = row.jobId || 0
- this.$router.push('/monitor/job-log/index/' + jobId)
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加任务"
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const jobId = row.jobId || this.ids
- getJob(jobId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改任务"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.jobId != undefined) {
- updateJob(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addJob(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const jobIds = row.jobId || this.ids
- this.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function() {
- return delJob(jobIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('schedule/job/export', {
- ...this.queryParams
- }, `job_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/monitor/job/log.vue b/ruoyi-ui/src/views/monitor/job/log.vue
deleted file mode 100644
index 56dc96f..0000000
--- a/ruoyi-ui/src/views/monitor/job/log.vue
+++ /dev/null
@@ -1,265 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="任务名称" prop="jobName">
- <el-input
- v-model="queryParams.jobName"
- placeholder="请输入任务名称"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="任务组名" prop="jobGroup">
- <el-select
- v-model="queryParams.jobGroup"
- placeholder="请选择任务组名"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_job_group"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="执行状态" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="请选择执行状态"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_common_status"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="执行时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['monitor:job:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- @click="handleClean"
- v-hasPermi="['monitor:job:remove']"
- >清空</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['monitor:job:export']"
- >导出</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-close"
- size="mini"
- @click="handleClose"
- >关闭</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
- <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
- <el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
- </template>
- </el-table-column>
- <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
- <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
- <el-table-column label="执行状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="执行时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-view"
- @click="handleView(scope.row)"
- v-hasPermi="['monitor:job:query']"
- >详细</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <job-log-detail :visible.sync="open" :row="form" type="log" />
- </div>
-</template>
-
-<script>
-import { getJob} from "@/api/monitor/job"
-import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog"
-import JobLogDetail from './detail'
-
-export default {
- name: "JobLog",
- components: { JobLogDetail },
- dicts: ['sys_common_status', 'sys_job_group'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 调度日志表格数据
- jobLogList: [],
- // 是否显示弹出层
- open: false,
- // 日期范围
- dateRange: [],
- // 表单参数
- form: {},
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- jobName: undefined,
- jobGroup: undefined,
- status: undefined
- }
- }
- },
- created() {
- const jobId = this.$route.params && this.$route.params.jobId
- if (jobId !== undefined && jobId != 0) {
- getJob(jobId).then(response => {
- this.queryParams.jobName = response.data.jobName
- this.queryParams.jobGroup = response.data.jobGroup
- this.getList()
- })
- } else {
- this.getList()
- }
- },
- methods: {
- /** 查询调度日志列表 */
- getList() {
- this.loading = true
- listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.jobLogList = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- // 返回按钮
- handleClose() {
- const obj = { path: "/monitor/job" }
- this.$tab.closeOpenPage(obj)
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.jobLogId)
- this.multiple = !selection.length
- },
- /** 详细按钮操作 */
- handleView(row) {
- this.open = true
- this.form = row
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const jobLogIds = this.ids
- this.$modal.confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?').then(function() {
- return delJobLog(jobLogIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 清空按钮操作 */
- handleClean() {
- this.$modal.confirm('是否确认清空所有调度日志数据项?').then(function() {
- return cleanJobLog()
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("清空成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('schedule/job/log/export', {
- ...this.queryParams
- }, `log_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/monitor/online/index.vue
deleted file mode 100644
index 83e9ebd..0000000
--- a/ruoyi-ui/src/views/monitor/online/index.vue
+++ /dev/null
@@ -1,118 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
- <el-form-item label="登录地址" prop="ipaddr">
- <el-input
- v-model="queryParams.ipaddr"
- placeholder="请输入登录地址"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="用户名称" prop="userName">
- <el-input
- v-model="queryParams.userName"
- placeholder="请输入用户名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
-
- </el-form>
- <el-table
- v-loading="loading"
- :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
- style="width: 100%;"
- >
- <el-table-column label="序号" type="index" align="center">
- <template slot-scope="scope">
- <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
- </template>
- </el-table-column>
- <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
- <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
- <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
- <el-table-column label="登录时间" align="center" prop="loginTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.loginTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleForceLogout(scope.row)"
- v-hasPermi="['monitor:online:forceLogout']"
- >强退</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
- </div>
-</template>
-
-<script>
-import { list, forceLogout } from "@/api/monitor/online";
-
-export default {
- name: "Online",
- data() {
- return {
- // 遮罩层
- loading: true,
- // 总条数
- total: 0,
- // 表格数据
- list: [],
- pageNum: 1,
- pageSize: 10,
- // 查询参数
- queryParams: {
- ipaddr: undefined,
- userName: undefined
- }
- };
- },
- created() {
- this.getList();
- },
- methods: {
- /** 查询登录日志列表 */
- getList() {
- this.loading = true;
- list(this.queryParams).then(response => {
- this.list = response.rows;
- this.total = response.total;
- this.loading = false;
- });
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.pageNum = 1;
- this.getList();
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm");
- this.handleQuery();
- },
- /** 强退按钮操作 */
- handleForceLogout(row) {
- this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function() {
- return forceLogout(row.tokenId);
- }).then(() => {
- this.getList();
- this.$modal.msgSuccess("强退成功");
- }).catch(() => {});
- }
- }
-};
-</script>
-
diff --git a/ruoyi-ui/src/views/redirect.vue b/ruoyi-ui/src/views/redirect.vue
deleted file mode 100644
index 6a62cb7..0000000
--- a/ruoyi-ui/src/views/redirect.vue
+++ /dev/null
@@ -1,12 +0,0 @@
-<script>
-export default {
- created() {
- const { params, query } = this.$route
- const { path } = params
- this.$router.replace({ path: '/' + path, query })
- },
- render: function(h) {
- return h() // avoid warning message
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue
deleted file mode 100644
index 6dbfa87..0000000
--- a/ruoyi-ui/src/views/register.vue
+++ /dev/null
@@ -1,214 +0,0 @@
-<template>
- <div class="register">
- <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
- <h3 class="title">{{title}}</h3>
- <el-form-item prop="username">
- <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
- <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
- </el-input>
- </el-form-item>
- <el-form-item prop="password" :rules="registerPwdValidator">
- <el-input
- v-model="registerForm.password"
- type="password"
- auto-complete="off"
- placeholder="密码"
- @keyup.enter.native="handleRegister"
- >
- <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
- </el-input>
- </el-form-item>
- <el-form-item prop="confirmPassword">
- <el-input
- v-model="registerForm.confirmPassword"
- type="password"
- auto-complete="off"
- placeholder="确认密码"
- @keyup.enter.native="handleRegister"
- >
- <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
- </el-input>
- </el-form-item>
- <el-form-item prop="code" v-if="captchaEnabled">
- <el-input
- v-model="registerForm.code"
- auto-complete="off"
- placeholder="验证码"
- style="width: 63%"
- @keyup.enter.native="handleRegister"
- >
- <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
- </el-input>
- <div class="register-code">
- <img :src="codeUrl" @click="getCode" class="register-code-img"/>
- </div>
- </el-form-item>
- <el-form-item style="width:100%;">
- <el-button
- :loading="loading"
- size="medium"
- type="primary"
- style="width:100%;"
- @click.native.prevent="handleRegister"
- >
- <span v-if="!loading">注 册</span>
- <span v-else>注 册 中...</span>
- </el-button>
- <div style="float: right;">
- <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
- </div>
- </el-form-item>
- </el-form>
- <!-- 底部 -->
- <div class="el-register-footer">
- <span>{{ footerContent }}</span>
- </div>
- </div>
-</template>
-
-<script>
-import { getCodeImg, register } from "@/api/login"
-import passwordRule from "@/utils/passwordRule"
-import defaultSettings from '@/settings'
-
-export default {
- mixins: [passwordRule],
- data() {
- return {
- title: process.env.VUE_APP_TITLE,
- footerContent: defaultSettings.footerContent,
- codeUrl: "",
- registerForm: {
- username: "",
- password: "",
- confirmPassword: "",
- code: "",
- uuid: ""
- },
- loading: false,
- captchaEnabled: true
- }
- },
- computed: {
- registerRules() {
- return {
- username: [
- { required: true, trigger: "blur", message: "请输入您的账号" },
- { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
- ],
- confirmPassword: [
- { required: true, message: "请再次输入您的密码", trigger: "blur" },
- {
- validator: (rule, value, callback) => {
- if (this.registerForm.password !== value) {
- callback(new Error("两次输入的密码不一致"))
- } else {
- callback()
- }
- }, trigger: "blur"
- }
- ],
- code: [{ required: true, trigger: "change", message: "请输入验证码" }]
- }
- }
- },
- created() {
- this.getCode()
- },
- methods: {
- getCode() {
- getCodeImg().then(res => {
- this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
- if (this.captchaEnabled) {
- this.codeUrl = "data:image/gif;base64," + res.img
- this.registerForm.uuid = res.uuid
- }
- })
- },
- handleRegister() {
- this.$refs.registerForm.validate(valid => {
- if (valid) {
- this.loading = true
- register(this.registerForm).then(() => {
- const username = this.registerForm.username
- this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
- dangerouslyUseHTMLString: true,
- type: 'success'
- }).then(() => {
- this.$router.push("/login")
- }).catch(() => {})
- }).catch(() => {
- this.loading = false
- if (this.captchaEnabled) {
- this.getCode()
- }
- })
- }
- })
- }
- }
-}
-</script>
-
-<style rel="stylesheet/scss" lang="scss" scoped>
-.register {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- background-image: url("../assets/images/login-background.jpg");
- background-size: cover;
-}
-.title {
- margin: 0px auto 30px auto;
- text-align: center;
- color: #707070;
-}
-
-.register-form {
- border-radius: 6px;
- background: #ffffff;
- width: 400px;
- padding: 25px 25px 5px 25px;
- .el-input {
- height: 38px;
- input {
- height: 38px;
- }
- }
- .input-icon {
- height: 39px;
- width: 14px;
- margin-left: 2px;
- }
-}
-.register-tip {
- font-size: 13px;
- text-align: center;
- color: #bfbfbf;
-}
-.register-code {
- width: 33%;
- height: 38px;
- float: right;
- img {
- cursor: pointer;
- vertical-align: middle;
- }
-}
-.el-register-footer {
- height: 40px;
- line-height: 40px;
- position: fixed;
- bottom: 0;
- width: 100%;
- text-align: center;
- color: #fff;
- font-family: Arial;
- font-size: 12px;
- letter-spacing: 1px;
-}
-.register-code-img {
- height: 38px;
-}
-</style>
diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue
deleted file mode 100644
index 73fa939..0000000
--- a/ruoyi-ui/src/views/system/config/index.vue
+++ /dev/null
@@ -1,343 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="参数名称" prop="configName">
- <el-input
- v-model="queryParams.configName"
- placeholder="请输入参数名称"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="参数键名" prop="configKey">
- <el-input
- v-model="queryParams.configKey"
- placeholder="请输入参数键名"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="系统内置" prop="configType">
- <el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
- <el-option
- v-for="dict in dict.type.sys_yes_no"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="创建时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:config:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:config:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:config:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:config:export']"
- >导出</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-refresh"
- size="mini"
- @click="handleRefreshCache"
- v-hasPermi="['system:config:remove']"
- >刷新缓存</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="参数主键" align="center" prop="configId" />
- <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
- <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
- <el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
- <el-table-column label="系统内置" align="center" prop="configType">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.configType"/>
- </template>
- </el-table-column>
- <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:config:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:config:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改参数配置对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-form-item label="参数名称" prop="configName">
- <el-input v-model="form.configName" placeholder="请输入参数名称" />
- </el-form-item>
- <el-form-item label="参数键名" prop="configKey">
- <el-input v-model="form.configKey" placeholder="请输入参数键名" />
- </el-form-item>
- <el-form-item label="参数键值" prop="configValue">
- <el-input v-model="form.configValue" type="textarea" placeholder="请输入参数键值" />
- </el-form-item>
- <el-form-item label="系统内置" prop="configType">
- <el-radio-group v-model="form.configType">
- <el-radio
- v-for="dict in dict.type.sys_yes_no"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config"
-
-export default {
- name: "Config",
- dicts: ['sys_yes_no'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 参数表格数据
- configList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 日期范围
- dateRange: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- configName: undefined,
- configKey: undefined,
- configType: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- configName: [
- { required: true, message: "参数名称不能为空", trigger: "blur" }
- ],
- configKey: [
- { required: true, message: "参数键名不能为空", trigger: "blur" }
- ],
- configValue: [
- { required: true, message: "参数键值不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询参数列表 */
- getList() {
- this.loading = true
- listConfig(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.configList = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- configId: undefined,
- configName: undefined,
- configKey: undefined,
- configValue: undefined,
- configType: "Y",
- remark: undefined
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加参数"
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.configId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const configId = row.configId || this.ids
- getConfig(configId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改参数"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.configId != undefined) {
- updateConfig(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addConfig(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const configIds = row.configId || this.ids
- this.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function() {
- return delConfig(configIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/config/export', {
- ...this.queryParams
- }, `config_${new Date().getTime()}.xlsx`)
- },
- /** 刷新缓存按钮操作 */
- handleRefreshCache() {
- refreshCache().then(() => {
- this.$modal.msgSuccess("刷新成功")
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue
deleted file mode 100644
index 88aab20..0000000
--- a/ruoyi-ui/src/views/system/dept/index.vue
+++ /dev/null
@@ -1,392 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
- <el-form-item label="部门名称" prop="deptName">
- <el-input
- v-model="queryParams.deptName"
- placeholder="请输入部门名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:dept:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-check"
- size="mini"
- @click="handleSaveSort"
- v-hasPermi="['system:dept:edit']"
- >保存排序</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="info"
- plain
- icon="el-icon-sort"
- size="mini"
- @click="toggleExpandAll"
- >展开/折叠</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table
- v-if="refreshTable"
- v-loading="loading"
- :data="deptList"
- row-key="deptId"
- :default-expand-all="isExpandAll"
- :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
- >
- <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
- <el-table-column prop="orderNum" label="排序" width="200">
- <template slot-scope="scope">
- <el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" size="mini" style="width: 88px" />
- </template>
- </el-table-column>
- <el-table-column prop="status" label="状态" width="100">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" width="200">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:dept:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-plus"
- @click="handleAdd(scope.row)"
- v-hasPermi="['system:dept:add']"
- >新增</el-button>
- <el-button
- v-if="scope.row.parentId != 0"
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:dept:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <!-- 添加或修改部门对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-row>
- <el-col :span="24" v-if="form.parentId !== 0">
- <el-form-item label="上级部门" prop="parentId">
- <treeselect v-model="form.parentId" :options="deptOptions" :normalizer="normalizer" placeholder="选择上级部门" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="部门名称" prop="deptName">
- <el-input v-model="form.deptName" placeholder="请输入部门名称" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="显示排序" prop="orderNum">
- <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="负责人" prop="leader">
- <el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="联系电话" prop="phone">
- <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="邮箱" prop="email">
- <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="部门状态">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listDept, getDept, delDept, addDept, updateDept, updateDeptSort, listDeptExcludeChild } from "@/api/system/dept"
-import Treeselect from "@riophae/vue-treeselect"
-import "@riophae/vue-treeselect/dist/vue-treeselect.css"
-
-export default {
- name: "Dept",
- dicts: ['sys_normal_disable'],
- components: { Treeselect },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 显示搜索条件
- showSearch: true,
- // 表格树数据
- deptList: [],
- // 部门树选项
- deptOptions: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 是否展开,默认全部展开
- isExpandAll: true,
- // 重新渲染表格状态
- refreshTable: true,
- // 记录原始排序,用于对比变更
- originalOrders: {},
- // 查询参数
- queryParams: {
- deptName: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- parentId: [
- { required: true, message: "上级部门不能为空", trigger: "blur" }
- ],
- deptName: [
- { required: true, message: "部门名称不能为空", trigger: "blur" }
- ],
- orderNum: [
- { required: true, message: "显示排序不能为空", trigger: "blur" }
- ],
- email: [
- {
- type: "email",
- message: "请输入正确的邮箱地址",
- trigger: ["blur", "change"]
- }
- ],
- phone: [
- {
- pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
- message: "请输入正确的手机号码",
- trigger: "blur"
- }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询部门列表 */
- getList() {
- this.loading = true
- listDept(this.queryParams).then(response => {
- this.deptList = this.handleTree(response.data, "deptId")
- // 记录原始排序值
- this.recordOriginalOrders(this.deptList)
- this.loading = false
- })
- },
- /** 转换部门数据结构 */
- normalizer(node) {
- if (node.children && !node.children.length) {
- delete node.children
- }
- return {
- id: node.deptId,
- label: node.deptName,
- children: node.children
- }
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- deptId: undefined,
- parentId: undefined,
- deptName: undefined,
- orderNum: undefined,
- leader: undefined,
- phone: undefined,
- email: undefined,
- status: "0"
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd(row) {
- this.reset()
- if (row != undefined) {
- this.form.parentId = row.deptId
- }
- this.open = true
- this.title = "添加部门"
- listDept().then(response => {
- this.deptOptions = this.handleTree(response.data, "deptId")
- })
- },
- /** 展开/折叠操作 */
- toggleExpandAll() {
- this.refreshTable = false
- this.isExpandAll = !this.isExpandAll
- this.$nextTick(() => {
- this.refreshTable = true
- })
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- getDept(row.deptId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改部门"
- listDeptExcludeChild(row.deptId).then(response => {
- this.deptOptions = this.handleTree(response.data, "deptId")
- if (this.deptOptions.length == 0) {
- const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] }
- this.deptOptions.push(noResultsOptions)
- }
- })
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.deptId != undefined) {
- updateDept(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addDept(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 递归记录原始排序 */
- recordOriginalOrders(list) {
- list.forEach(item => {
- this.originalOrders[item.deptId] = item.orderNum
- if (item.children && item.children.length) {
- this.recordOriginalOrders(item.children)
- }
- })
- },
- /** 保存排序 */
- handleSaveSort() {
- const changedDeptIds = []
- const changedOrderNums = []
- const collectChanged = (list) => {
- list.forEach(item => {
- if (String(this.originalOrders[item.deptId]) !== String(item.orderNum)) {
- changedDeptIds.push(item.deptId)
- changedOrderNums.push(item.orderNum)
- }
- if (item.children && item.children.length) {
- collectChanged(item.children)
- }
- })
- }
- collectChanged(this.deptList)
- if (changedDeptIds.length === 0) {
- this.$modal.msgWarning("未检测到排序修改")
- return
- }
- updateDeptSort({ deptIds: changedDeptIds.join(","), orderNums: changedOrderNums.join(",") }).then(() => {
- this.$modal.msgSuccess("排序保存成功")
- this.recordOriginalOrders(this.deptList)
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
- return delDept(row.deptId)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
deleted file mode 100644
index 42d8438..0000000
--- a/ruoyi-ui/src/views/system/dict/data.vue
+++ /dev/null
@@ -1,402 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="字典名称" prop="dictType">
- <el-select v-model="queryParams.dictType">
- <el-option
- v-for="item in typeOptions"
- :key="item.dictId"
- :label="item.dictName"
- :value="item.dictType"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="字典标签" prop="dictLabel">
- <el-input
- v-model="queryParams.dictLabel"
- placeholder="请输入字典标签"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="数据状态" clearable>
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:dict:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:dict:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:dict:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:dict:export']"
- >导出</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-close"
- size="mini"
- @click="handleClose"
- >关闭</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="字典编码" align="center" prop="dictCode" />
- <el-table-column label="字典标签" align="center" prop="dictLabel">
- <template slot-scope="scope">
- <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
- <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="字典键值" align="center" prop="dictValue" />
- <el-table-column label="字典排序" align="center" prop="dictSort" />
- <el-table-column label="状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:dict:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:dict:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改参数配置对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-form-item label="字典类型">
- <el-input v-model="form.dictType" :disabled="true" />
- </el-form-item>
- <el-form-item label="数据标签" prop="dictLabel">
- <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
- </el-form-item>
- <el-form-item label="数据键值" prop="dictValue">
- <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
- </el-form-item>
- <el-form-item label="样式属性" prop="cssClass">
- <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
- </el-form-item>
- <el-form-item label="显示排序" prop="dictSort">
- <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
- </el-form-item>
- <el-form-item label="回显样式" prop="listClass">
- <el-select v-model="form.listClass">
- <el-option
- v-for="item in listClassOptions"
- :key="item.value"
- :label="item.label + '(' + item.value + ')'"
- :value="item.value"
- ></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"
-import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type"
-
-export default {
- name: "Data",
- dicts: ['sys_normal_disable'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 字典表格数据
- dataList: [],
- // 默认字典类型
- defaultDictType: "",
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 数据标签回显样式
- listClassOptions: [
- {
- value: "default",
- label: "默认"
- },
- {
- value: "primary",
- label: "主要"
- },
- {
- value: "success",
- label: "成功"
- },
- {
- value: "info",
- label: "信息"
- },
- {
- value: "warning",
- label: "警告"
- },
- {
- value: "danger",
- label: "危险"
- }
- ],
- // 类型数据字典
- typeOptions: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- dictType: undefined,
- dictLabel: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- dictLabel: [
- { required: true, message: "数据标签不能为空", trigger: "blur" }
- ],
- dictValue: [
- { required: true, message: "数据键值不能为空", trigger: "blur" }
- ],
- dictSort: [
- { required: true, message: "数据顺序不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- const dictId = this.$route.params && this.$route.params.dictId
- this.getType(dictId)
- this.getTypeList()
- },
- methods: {
- /** 查询字典类型详细 */
- getType(dictId) {
- getType(dictId).then(response => {
- this.queryParams.dictType = response.data.dictType
- this.defaultDictType = response.data.dictType
- this.getList()
- })
- },
- /** 查询字典类型列表 */
- getTypeList() {
- getDictOptionselect().then(response => {
- this.typeOptions = response.data
- })
- },
- /** 查询字典数据列表 */
- getList() {
- this.loading = true
- listData(this.queryParams).then(response => {
- this.dataList = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- dictCode: undefined,
- dictLabel: undefined,
- dictValue: undefined,
- cssClass: undefined,
- listClass: 'default',
- dictSort: 0,
- status: "0",
- remark: undefined
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 返回按钮操作 */
- handleClose() {
- const obj = { path: "/system/dict" }
- this.$tab.closeOpenPage(obj)
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.queryParams.dictType = this.defaultDictType
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加字典数据"
- this.form.dictType = this.queryParams.dictType
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.dictCode)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const dictCode = row.dictCode || this.ids
- getData(dictCode).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改字典数据"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.dictCode != undefined) {
- updateData(this.form).then(() => {
- this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addData(this.form).then(() => {
- this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const dictCodes = row.dictCode || this.ids
- this.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
- return delData(dictCodes)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/dict/data/export', {
- ...this.queryParams
- }, `data_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dict/index.vue b/ruoyi-ui/src/views/system/dict/index.vue
deleted file mode 100644
index c63ceb0..0000000
--- a/ruoyi-ui/src/views/system/dict/index.vue
+++ /dev/null
@@ -1,375 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="字典名称" prop="dictName">
- <el-input
- v-model="queryParams.dictName"
- placeholder="请输入字典名称"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="字典类型" prop="dictType">
- <el-input
- v-model="queryParams.dictType"
- placeholder="请输入字典类型"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="字典状态"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="创建时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:dict:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:dict:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:dict:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:dict:export']"
- >导出</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-refresh"
- size="mini"
- @click="handleRefreshCache"
- v-hasPermi="['system:dict:remove']"
- >刷新缓存</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="字典编号" align="center" prop="dictId" />
- <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
- <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.dictType }}</a>
- </template>
- </el-table-column>
- <el-table-column label="状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:dict:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-s-operation"
- @click="handleDataList(scope.row)"
- v-hasPermi="['system:dict:edit']"
- >列表</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:dict:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改参数配置对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <el-form-item label="字典名称" prop="dictName">
- <el-input v-model="form.dictName" placeholder="请输入字典名称" />
- </el-form-item>
- <el-form-item prop="dictType">
- <el-input v-model="form.dictType" placeholder="请输入字典类型" maxlength="100" />
- <span slot="label">
- <el-tooltip content="数据存储中的Key值,如:sys_user_sex" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 字典类型
- </span>
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
-
- <dict-data-drawer :visible.sync="drawerVisible" :row="drawerRow" />
- </div>
-</template>
-
-<script>
-import DictDataDrawer from './detail'
-import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type"
-
-export default {
- name: "Dict",
- components: { DictDataDrawer },
- dicts: ['sys_normal_disable'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 字典表格数据
- typeList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 字典数据抽屉状态
- drawerVisible: false,
- // 字典数据信息
- drawerRow: {},
- // 日期范围
- dateRange: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- dictName: undefined,
- dictType: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- dictName: [
- { required: true, message: "字典名称不能为空", trigger: "blur" }
- ],
- dictType: [
- { required: true, message: "字典类型不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询字典类型列表 */
- getList() {
- this.loading = true
- listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.typeList = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- dictId: undefined,
- dictName: undefined,
- dictType: undefined,
- status: "0",
- remark: undefined
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加字典类型"
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.dictId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- /** 字典数据抽屉显示信息 */
- handleViewData(row) {
- this.drawerRow = row
- this.drawerVisible = true
- },
- /** 字典数据列表页面 */
- handleDataList(row) {
- this.$tab.openPage("字典数据", '/system/dict-data/index/' + row.dictId)
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const dictId = row.dictId || this.ids
- getType(dictId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改字典类型"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.dictId != undefined) {
- updateType(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addType(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const dictIds = row.dictId || this.ids
- this.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
- return delType(dictIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/dict/type/export', {
- ...this.queryParams
- }, `type_${new Date().getTime()}.xlsx`)
- },
- /** 刷新缓存按钮操作 */
- handleRefreshCache() {
- refreshCache().then(() => {
- this.$modal.msgSuccess("刷新成功")
- this.$store.dispatch('dict/cleanDict')
- })
- }
- }
-}
-</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/logininfor/index.vue b/ruoyi-ui/src/views/system/logininfor/index.vue
deleted file mode 100644
index 76d2d75..0000000
--- a/ruoyi-ui/src/views/system/logininfor/index.vue
+++ /dev/null
@@ -1,243 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="登录地址" prop="ipaddr">
- <el-input
- v-model="queryParams.ipaddr"
- placeholder="请输入登录地址"
- clearable
- style="width: 240px;"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="用户名称" prop="userName">
- <el-input
- v-model="queryParams.userName"
- placeholder="请输入用户名称"
- clearable
- style="width: 240px;"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="登录状态"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_common_status"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="登录时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd HH:mm:ss"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :default-time="['00:00:00', '23:59:59']"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:logininfor:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- @click="handleClean"
- v-hasPermi="['system:logininfor:remove']"
- >清空</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-unlock"
- size="mini"
- :disabled="single"
- @click="handleUnlock"
- v-hasPermi="['system:logininfor:unlock']"
- >解锁</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:logininfor:export']"
- >导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="访问编号" align="center" prop="infoId" />
- <el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
- <el-table-column label="地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
- <el-table-column label="登录状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
- <el-table-column label="访问时间" align="center" prop="accessTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.accessTime) }}</span>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- </div>
-</template>
-
-<script>
-import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/system/logininfor"
-
-export default {
- name: "Logininfor",
- dicts: ['sys_common_status'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 选择用户名
- selectName: "",
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 表格数据
- list: [],
- // 日期范围
- dateRange: [],
- // 默认排序
- defaultSort: { prop: "accessTime", order: "descending" },
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- ipaddr: undefined,
- userName: undefined,
- status: undefined
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询登录日志列表 */
- getList() {
- this.loading = true
- list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.list = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.queryParams.pageNum = 1
- this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
- },
- /** 多选框选中数据 */
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.infoId)
- this.single = selection.length!=1
- this.multiple = !selection.length
- this.selectName = selection.map(item => item.userName)
- },
- /** 排序触发事件 */
- handleSortChange(column, prop, order) {
- this.queryParams.orderByColumn = column.prop
- this.queryParams.isAsc = column.order
- this.getList()
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const infoIds = row.infoId || this.ids
- this.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function() {
- return delLogininfor(infoIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 清空按钮操作 */
- handleClean() {
- this.$modal.confirm('是否确认清空所有登录日志数据项?').then(function() {
- return cleanLogininfor()
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("清空成功")
- }).catch(() => {})
- },
- /** 解锁按钮操作 */
- handleUnlock() {
- const username = this.selectName
- this.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function() {
- return unlockLogininfor(username)
- }).then(() => {
- this.$modal.msgSuccess("用户" + username + "解锁成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/logininfor/export', {
- ...this.queryParams
- }, `logininfor_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
-
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
deleted file mode 100644
index 1ac0451..0000000
--- a/ruoyi-ui/src/views/system/menu/index.vue
+++ /dev/null
@@ -1,533 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
- <el-form-item label="菜单名称" prop="menuName">
- <el-input
- v-model="queryParams.menuName"
- placeholder="请输入菜单名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:menu:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-check"
- size="mini"
- @click="handleSaveSort"
- v-hasPermi="['system:menu:edit']"
- >保存排序</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="info"
- plain
- icon="el-icon-sort"
- size="mini"
- @click="toggleExpandAll"
- >展开/折叠</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table
- v-if="refreshTable"
- v-loading="loading"
- :data="menuList"
- row-key="menuId"
- :default-expand-all="isExpandAll"
- :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
- >
- <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="220">
- <template slot-scope="scope">
- <svg-icon :icon-class="scope.row.icon" />
- <span class="ml5">{{ scope.row.menuName }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="menuName" label="类型" :show-overflow-tooltip="true" width="100">
- <template slot-scope="scope">
- <el-tag v-if="scope.row.menuType === 'M' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
- <el-tag v-else-if="scope.row.menuType === 'M'" type="primary" size="small">目录</el-tag>
- <el-tag v-else-if="scope.row.menuType === 'C' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
- <el-tag v-else-if="scope.row.menuType === 'C'" type="success" size="small">菜单</el-tag>
- <el-tag v-else-if="scope.row.menuType === 'F'" type="warning" size="small">按钮</el-tag>
- </template>
- </el-table-column>
- <el-table-column prop="orderNum" label="排序" width="200">
- <template slot-scope="scope">
- <el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" size="mini" style="width: 88px" />
- </template>
- </el-table-column>
- <el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true" />
- <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true" />
- <el-table-column prop="status" label="状态" width="80">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status" />
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:menu:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-plus"
- @click="handleAdd(scope.row)"
- v-hasPermi="['system:menu:add']"
- >新增</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:menu:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <!-- 添加或修改菜单对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <el-row>
- <el-col :span="24">
- <el-form-item label="上级菜单" prop="parentId">
- <treeselect
- v-model="form.parentId"
- :options="menuOptions"
- :normalizer="normalizer"
- :show-count="true"
- placeholder="选择上级菜单"
- />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24">
- <el-form-item label="菜单类型" prop="menuType">
- <el-radio-group v-model="form.menuType">
- <el-radio label="M">目录</el-radio>
- <el-radio label="C">菜单</el-radio>
- <el-radio label="F">按钮</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" v-if="form.menuType != 'F'">
- <el-form-item label="菜单图标" prop="icon">
- <el-popover
- placement="bottom-start"
- width="460"
- trigger="click"
- @show="$refs['iconSelect'].reset()"
- >
- <IconSelect ref="iconSelect" @selected="selected" :active-icon="form.icon" />
- <el-input slot="reference" v-model="form.icon" placeholder="点击选择图标" readonly>
- <svg-icon
- v-if="form.icon"
- slot="prefix"
- :icon-class="form.icon"
- style="width: 25px;"
- />
- <i v-else slot="prefix" class="el-icon-search el-input__icon" />
- </el-input>
- </el-popover>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="显示排序" prop="orderNum">
- <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="菜单名称" prop="menuName">
- <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.menuType == 'C'">
- <el-form-item prop="routeName">
- <el-input v-model="form.routeName" placeholder="请输入路由名称" />
- <span slot="label">
- <el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 路由名称
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" v-if="form.menuType != 'F'">
- <el-form-item prop="isFrame">
- <span slot="label">
- <el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 是否外链
- </span>
- <el-radio-group v-model="form.isFrame">
- <el-radio label="0">是</el-radio>
- <el-radio label="1">否</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.menuType != 'F'">
- <el-form-item prop="path">
- <span slot="label">
- <el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 路由地址
- </span>
- <el-input v-model="form.path" placeholder="请输入路由地址" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" v-if="form.menuType == 'C'">
- <el-form-item prop="component">
- <span slot="label">
- <el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 组件路径
- </span>
- <el-input v-model="form.component" placeholder="请输入组件路径" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.menuType != 'M'">
- <el-form-item prop="perms">
- <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
- <span slot="label">
- <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 权限字符
- </span>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" v-if="form.menuType == 'C'">
- <el-form-item prop="query">
- <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
- <span slot="label">
- <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 路由参数
- </span>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.menuType == 'C'">
- <el-form-item prop="isCache">
- <span slot="label">
- <el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 是否缓存
- </span>
- <el-radio-group v-model="form.isCache">
- <el-radio label="0">缓存</el-radio>
- <el-radio label="1">不缓存</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12" v-if="form.menuType != 'F'">
- <el-form-item prop="visible">
- <span slot="label">
- <el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 显示状态
- </span>
- <el-radio-group v-model="form.visible">
- <el-radio
- v-for="dict in dict.type.sys_show_hide"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item prop="status">
- <span slot="label">
- <el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 菜单状态
- </span>
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listMenu, getMenu, delMenu, addMenu, updateMenu, updateMenuSort } from "@/api/system/menu"
-import Treeselect from "@riophae/vue-treeselect"
-import "@riophae/vue-treeselect/dist/vue-treeselect.css"
-import IconSelect from "@/components/IconSelect"
-
-export default {
- name: "Menu",
- dicts: ['sys_show_hide', 'sys_normal_disable'],
- components: { Treeselect, IconSelect },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 显示搜索条件
- showSearch: true,
- // 菜单表格树数据
- menuList: [],
- // 菜单树选项
- menuOptions: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 是否展开,默认全部折叠
- isExpandAll: false,
- // 重新渲染表格状态
- refreshTable: true,
- // 记录原始排序,用于对比变更
- originalOrders: {},
- // 查询参数
- queryParams: {
- menuName: undefined,
- visible: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- menuName: [
- { required: true, message: "菜单名称不能为空", trigger: "blur" }
- ],
- orderNum: [
- { required: true, message: "菜单顺序不能为空", trigger: "blur" }
- ],
- path: [
- { required: true, message: "路由地址不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- // 选择图标
- selected(name) {
- this.form.icon = name
- },
- /** 查询菜单列表 */
- getList() {
- this.loading = true
- listMenu(this.queryParams).then(response => {
- this.menuList = this.handleTree(response.data, "menuId")
- // 记录原始排序值
- this.recordOriginalOrders(this.menuList)
- this.loading = false
- })
- },
- /** 转换菜单数据结构 */
- normalizer(node) {
- if (node.children && !node.children.length) {
- delete node.children
- }
- return {
- id: node.menuId,
- label: node.menuName,
- children: node.children
- }
- },
- /** 查询菜单下拉树结构 */
- getTreeselect() {
- listMenu().then(response => {
- this.menuOptions = []
- const menu = { menuId: 0, menuName: '主类目', children: [] }
- menu.children = this.handleTree(response.data, "menuId")
- this.menuOptions.push(menu)
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- menuId: undefined,
- parentId: 0,
- menuName: undefined,
- icon: undefined,
- menuType: "M",
- orderNum: undefined,
- isFrame: "1",
- isCache: "0",
- visible: "0",
- status: "0"
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 新增按钮操作 */
- handleAdd(row) {
- this.reset()
- this.getTreeselect()
- if (row != null && row.menuId) {
- this.form.parentId = row.menuId
- } else {
- this.form.parentId = 0
- }
- this.open = true
- this.title = "添加菜单"
- },
- /** 展开/折叠操作 */
- toggleExpandAll() {
- this.refreshTable = false
- this.isExpandAll = !this.isExpandAll
- this.$nextTick(() => {
- this.refreshTable = true
- })
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- this.getTreeselect()
- getMenu(row.menuId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改菜单"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.menuId != undefined) {
- updateMenu(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addMenu(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 递归记录原始排序 */
- recordOriginalOrders(list) {
- list.forEach(item => {
- this.originalOrders[item.menuId] = item.orderNum
- if (item.children && item.children.length) {
- this.recordOriginalOrders(item.children)
- }
- })
- },
- /** 保存排序 */
- handleSaveSort() {
- const changedMenuIds = []
- const changedOrderNums = []
- const collectChanged = (list) => {
- list.forEach(item => {
- if (String(this.originalOrders[item.menuId]) !== String(item.orderNum)) {
- changedMenuIds.push(item.menuId)
- changedOrderNums.push(item.orderNum)
- }
- if (item.children && item.children.length) {
- collectChanged(item.children)
- }
- })
- }
- collectChanged(this.menuList)
- if (changedMenuIds.length === 0) {
- this.$modal.msgWarning("未检测到排序修改")
- return
- }
- updateMenuSort({ menuIds: changedMenuIds.join(","), orderNums: changedOrderNums.join(",") }).then(() => {
- this.$modal.msgSuccess("排序保存成功")
- this.recordOriginalOrders(this.menuList)
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- this.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
- return delMenu(row.menuId)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/notice/index.vue b/ruoyi-ui/src/views/system/notice/index.vue
deleted file mode 100644
index 5b0f0b6..0000000
--- a/ruoyi-ui/src/views/system/notice/index.vue
+++ /dev/null
@@ -1,332 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="公告标题" prop="noticeTitle">
- <el-input
- v-model="queryParams.noticeTitle"
- placeholder="请输入公告标题"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="操作人员" prop="createBy">
- <el-input
- v-model="queryParams.createBy"
- placeholder="请输入操作人员"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="类型" prop="noticeType">
- <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable>
- <el-option
- v-for="dict in dict.type.sys_notice_type"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:notice:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:notice:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:notice:remove']"
- >删除</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="序号" align="center" prop="noticeId" width="100" />
- <el-table-column label="公告标题" align="center" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.noticeTitle }}</a>
- </template>
- </el-table-column>
- <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/>
- </template>
- </el-table-column>
- <el-table-column label="状态" align="center" prop="status" width="100">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="创建者" align="center" prop="createBy" width="100" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="100">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-user"
- @click="handleReadUsers(scope.row)"
- v-hasPermi="['system:notice:list']"
- >阅读用户</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:notice:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:notice:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改公告对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="780px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="公告标题" prop="noticeTitle">
- <el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="公告类型" prop="noticeType">
- <el-select v-model="form.noticeType" placeholder="请选择公告类型">
- <el-option
- v-for="dict in dict.type.sys_notice_type"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="状态">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_notice_status"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="内容">
- <editor v-model="form.noticeContent" :min-height="192"/>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
-
- <notice-detail-view ref="noticeViewRef" />
- <read-users-dialog ref="readUsersRef" />
- </div>
-</template>
-
-<script>
-import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView"
-import ReadUsersDialog from "./ReadUsers"
-import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"
-
-export default {
- name: "Notice",
- components: { NoticeDetailView, ReadUsersDialog },
- dicts: ['sys_notice_status', 'sys_notice_type'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 公告表格数据
- noticeList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- noticeTitle: undefined,
- createBy: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- noticeTitle: [
- { required: true, message: "公告标题不能为空", trigger: "blur" }
- ],
- noticeType: [
- { required: true, message: "公告类型不能为空", trigger: "change" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询公告列表 */
- getList() {
- this.loading = true
- listNotice(this.queryParams).then(response => {
- this.noticeList = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- noticeId: undefined,
- noticeTitle: undefined,
- noticeType: undefined,
- noticeContent: undefined,
- status: "0"
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.noticeId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加公告"
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const noticeId = row.noticeId || this.ids
- getNotice(noticeId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改公告"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.noticeId != undefined) {
- updateNotice(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addNotice(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 查看公告详情 */
- handleViewData(row) {
- this.$refs.noticeViewRef.open(row)
- },
- /** 查看已读用户 */
- handleReadUsers(row) {
- this.$refs.readUsersRef.open(row)
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const noticeIds = row.noticeId || this.ids
- this.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
- return delNotice(noticeIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/operlog/index.vue b/ruoyi-ui/src/views/system/operlog/index.vue
deleted file mode 100644
index 24cea41..0000000
--- a/ruoyi-ui/src/views/system/operlog/index.vue
+++ /dev/null
@@ -1,279 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="操作地址" prop="operIp">
- <el-input
- v-model="queryParams.operIp"
- placeholder="请输入操作地址"
- clearable
- style="width: 240px;"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="系统模块" prop="title">
- <el-input
- v-model="queryParams.title"
- placeholder="请输入系统模块"
- clearable
- style="width: 240px;"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="操作人员" prop="operName">
- <el-input
- v-model="queryParams.operName"
- placeholder="请输入操作人员"
- clearable
- style="width: 240px;"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="类型" prop="businessType">
- <el-select
- v-model="queryParams.businessType"
- placeholder="操作类型"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_oper_type"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="操作状态"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_common_status"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="操作时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd HH:mm:ss"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :default-time="['00:00:00', '23:59:59']"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:operlog:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- @click="handleClean"
- v-hasPermi="['system:operlog:remove']"
- >清空</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:operlog:export']"
- >导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
- <el-table-column type="selection" width="50" align="center" />
- <el-table-column label="日志编号" align="center" prop="operId" />
- <el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
- <el-table-column label="操作类型" align="center" prop="businessType">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_oper_type" :value="scope.row.businessType"/>
- </template>
- </el-table-column>
- <el-table-column label="请求方式" align="center" prop="requestMethod" />
- <el-table-column label="操作人员" align="center" prop="operName" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']"/>
- <el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
- <el-table-column label="操作状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.operTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
- <template slot-scope="scope">
- <span>{{ scope.row.costTime }}毫秒</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-view"
- @click="handleDetail(scope.row,scope.index)"
- v-hasPermi="['system:operlog:query']"
- >详细</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <operlog-detail :visible.sync="detailVisible" :row="detailRow" />
- </div>
-</template>
-
-<script>
-import OperlogDetail from './detail'
-import { list, delOperlog, cleanOperlog } from "@/api/system/operlog"
-
-export default {
- name: "Operlog",
- components: { OperlogDetail },
- dicts: ['sys_oper_type', 'sys_common_status'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 表格数据
- list: [],
- // 是否显示弹出层
- detailVisible: false,
- detailRow: {},
- // 日期范围
- dateRange: [],
- // 默认排序
- defaultSort: { prop: "operTime", order: "descending" },
- // 表单参数
- form: {},
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- operIp: undefined,
- title: undefined,
- operName: undefined,
- businessType: undefined,
- status: undefined
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询登录日志 */
- getList() {
- this.loading = true
- list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {
- this.list = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- // 详细按钮操作
- handleDetail(row) {
- this.detailRow = row
- this.detailVisible = true
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.queryParams.pageNum = 1
- this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
- },
- /** 多选框选中数据 */
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.operId)
- this.multiple = !selection.length
- },
- /** 排序触发事件 */
- handleSortChange(column, prop, order) {
- this.queryParams.orderByColumn = column.prop
- this.queryParams.isAsc = column.order
- this.getList()
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const operIds = row.operId || this.ids
- this.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function() {
- return delOperlog(operIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 清空按钮操作 */
- handleClean() {
- this.$modal.confirm('是否确认清空所有操作日志数据项?').then(function() {
- return cleanOperlog()
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("清空成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/operlog/export', {
- ...this.queryParams
- }, `operlog_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
-
diff --git a/ruoyi-ui/src/views/system/post/index.vue b/ruoyi-ui/src/views/system/post/index.vue
deleted file mode 100644
index a9fa686..0000000
--- a/ruoyi-ui/src/views/system/post/index.vue
+++ /dev/null
@@ -1,309 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="岗位编码" prop="postCode">
- <el-input
- v-model="queryParams.postCode"
- placeholder="请输入岗位编码"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="岗位名称" prop="postName">
- <el-input
- v-model="queryParams.postName"
- placeholder="请输入岗位名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="岗位状态" clearable>
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:post:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:post:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:post:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:post:export']"
- >导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="岗位编号" align="center" prop="postId" />
- <el-table-column label="岗位编码" align="center" prop="postCode" />
- <el-table-column label="岗位名称" align="center" prop="postName" />
- <el-table-column label="岗位排序" align="center" prop="postSort" />
- <el-table-column label="状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:post:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:post:remove']"
- >删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改岗位对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-form-item label="岗位名称" prop="postName">
- <el-input v-model="form.postName" placeholder="请输入岗位名称" />
- </el-form-item>
- <el-form-item label="岗位编码" prop="postCode">
- <el-input v-model="form.postCode" placeholder="请输入编码名称" />
- </el-form-item>
- <el-form-item label="岗位顺序" prop="postSort">
- <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
- </el-form-item>
- <el-form-item label="岗位状态" prop="status">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="备注" prop="remark">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post"
-
-export default {
- name: "Post",
- dicts: ['sys_normal_disable'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 岗位表格数据
- postList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- postCode: undefined,
- postName: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- // 表单校验
- rules: {
- postName: [
- { required: true, message: "岗位名称不能为空", trigger: "blur" }
- ],
- postCode: [
- { required: true, message: "岗位编码不能为空", trigger: "blur" }
- ],
- postSort: [
- { required: true, message: "岗位顺序不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询岗位列表 */
- getList() {
- this.loading = true
- listPost(this.queryParams).then(response => {
- this.postList = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- postId: undefined,
- postCode: undefined,
- postName: undefined,
- postSort: 0,
- status: "0",
- remark: undefined
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.postId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.open = true
- this.title = "添加岗位"
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const postId = row.postId || this.ids
- getPost(postId).then(response => {
- this.form = response.data
- this.open = true
- this.title = "修改岗位"
- })
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.postId != undefined) {
- updatePost(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addPost(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const postIds = row.postId || this.ids
- this.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
- return delPost(postIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/post/export', {
- ...this.queryParams
- }, `post_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/role/authUser.vue b/ruoyi-ui/src/views/system/role/authUser.vue
deleted file mode 100644
index d4d44bb..0000000
--- a/ruoyi-ui/src/views/system/role/authUser.vue
+++ /dev/null
@@ -1,199 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
- <el-form-item label="用户名称" prop="userName">
- <el-input
- v-model="queryParams.userName"
- placeholder="请输入用户名称"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="手机号码" prop="phonenumber">
- <el-input
- v-model="queryParams.phonenumber"
- placeholder="请输入手机号码"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="openSelectUser"
- v-hasPermi="['system:role:add']"
- >添加用户</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-circle-close"
- size="mini"
- :disabled="multiple"
- @click="cancelAuthUserAll"
- v-hasPermi="['system:role:remove']"
- >批量取消授权</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-close"
- size="mini"
- @click="handleClose"
- >关闭</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
- <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
- <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
- <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
- <el-table-column label="状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-circle-close"
- @click="cancelAuthUser(scope.row)"
- v-hasPermi="['system:role:remove']"
- >取消授权</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- <select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" />
- </div>
-</template>
-
-<script>
-import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role"
-import selectUser from "./selectUser"
-
-export default {
- name: "AuthUser",
- dicts: ['sys_normal_disable'],
- components: { selectUser },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中用户组
- userIds: [],
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 用户表格数据
- userList: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- roleId: undefined,
- userName: undefined,
- phonenumber: undefined
- }
- }
- },
- created() {
- const roleId = this.$route.params && this.$route.params.roleId
- if (roleId) {
- this.queryParams.roleId = roleId
- this.getList()
- }
- },
- methods: {
- /** 查询授权用户列表 */
- getList() {
- this.loading = true
- allocatedUserList(this.queryParams).then(response => {
- this.userList = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- // 返回按钮
- handleClose() {
- const obj = { path: "/system/role" }
- this.$tab.closeOpenPage(obj)
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.userIds = selection.map(item => item.userId)
- this.multiple = !selection.length
- },
- /** 打开授权用户表弹窗 */
- openSelectUser() {
- this.$refs.select.show()
- },
- /** 取消授权按钮操作 */
- cancelAuthUser(row) {
- const roleId = this.queryParams.roleId
- this.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function() {
- return authUserCancel({ userId: row.userId, roleId: roleId })
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("取消授权成功")
- }).catch(() => {})
- },
- /** 批量取消授权按钮操作 */
- cancelAuthUserAll() {
- const roleId = this.queryParams.roleId
- const userIds = this.userIds.join(",")
- this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {
- return authUserCancelAll({ roleId: roleId, userIds: userIds })
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("取消授权成功")
- }).catch(() => {})
- }
- }
-}
-</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
deleted file mode 100644
index 1b50e66..0000000
--- a/ruoyi-ui/src/views/system/role/index.vue
+++ /dev/null
@@ -1,605 +0,0 @@
-<template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
- <el-form-item label="角色名称" prop="roleName">
- <el-input
- v-model="queryParams.roleName"
- placeholder="请输入角色名称"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="权限字符" prop="roleKey">
- <el-input
- v-model="queryParams.roleKey"
- placeholder="请输入权限字符"
- clearable
- style="width: 240px"
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select
- v-model="queryParams.status"
- placeholder="角色状态"
- clearable
- style="width: 240px"
- >
- <el-option
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.label"
- :value="dict.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="创建时间">
- <el-date-picker
- v-model="dateRange"
- style="width: 240px"
- value-format="yyyy-MM-dd"
- type="daterange"
- range-separator="-"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- ></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button
- type="primary"
- plain
- icon="el-icon-plus"
- size="mini"
- @click="handleAdd"
- v-hasPermi="['system:role:add']"
- >新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="success"
- plain
- icon="el-icon-edit"
- size="mini"
- :disabled="single"
- @click="handleUpdate"
- v-hasPermi="['system:role:edit']"
- >修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="danger"
- plain
- icon="el-icon-delete"
- size="mini"
- :disabled="multiple"
- @click="handleDelete"
- v-hasPermi="['system:role:remove']"
- >删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button
- type="warning"
- plain
- icon="el-icon-download"
- size="mini"
- @click="handleExport"
- v-hasPermi="['system:role:export']"
- >导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="角色编号" prop="roleId" width="120" />
- <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
- <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
- <el-table-column label="显示顺序" prop="roleSort" width="100" />
- <el-table-column label="状态" align="center" width="100">
- <template slot-scope="scope">
- <el-switch
- v-model="scope.row.status"
- active-value="0"
- inactive-value="1"
- @change="handleStatusChange(scope.row)"
- ></el-switch>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
- <template slot-scope="scope" v-if="scope.row.roleId !== 1">
- <el-button
- size="mini"
- type="text"
- icon="el-icon-edit"
- @click="handleUpdate(scope.row)"
- v-hasPermi="['system:role:edit']"
- >修改</el-button>
- <el-button
- size="mini"
- type="text"
- icon="el-icon-delete"
- @click="handleDelete(scope.row)"
- v-hasPermi="['system:role:remove']"
- >删除</el-button>
- <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:role:edit']">
- <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
- v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
- <el-dropdown-item command="handleAuthUser" icon="el-icon-user"
- v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
-
- <!-- 添加或修改角色配置对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="100px">
- <el-form-item label="角色名称" prop="roleName">
- <el-input v-model="form.roleName" placeholder="请输入角色名称" />
- </el-form-item>
- <el-form-item prop="roleKey">
- <span slot="label">
- <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- 权限字符
- </span>
- <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
- </el-form-item>
- <el-form-item label="角色顺序" prop="roleSort">
- <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
- </el-form-item>
- <el-form-item label="状态">
- <el-radio-group v-model="form.status">
- <el-radio
- v-for="dict in dict.type.sys_normal_disable"
- :key="dict.value"
- :label="dict.value"
- >{{dict.label}}</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="菜单权限">
- <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
- <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
- <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
- <el-tree
- class="tree-border"
- :data="menuOptions"
- show-checkbox
- ref="menu"
- node-key="id"
- :check-strictly="!form.menuCheckStrictly"
- empty-text="加载中,请稍候"
- :props="defaultProps"
- ></el-tree>
- </el-form-item>
- <el-form-item label="备注">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
-
- <!-- 分配角色数据权限对话框 -->
- <el-dialog :title="title" :visible.sync="openDataScope" width="500px" append-to-body>
- <el-form :model="form" label-width="80px">
- <el-form-item label="角色名称">
- <el-input v-model="form.roleName" :disabled="true" />
- </el-form-item>
- <el-form-item label="权限字符">
- <el-input v-model="form.roleKey" :disabled="true" />
- </el-form-item>
- <el-form-item label="权限范围">
- <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
- <el-option
- v-for="item in dataScopeOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- ></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="数据权限" v-show="form.dataScope == 2">
- <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
- <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
- <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
- <el-tree
- class="tree-border"
- :data="deptOptions"
- show-checkbox
- default-expand-all
- ref="dept"
- node-key="id"
- :check-strictly="!form.deptCheckStrictly"
- empty-text="加载中,请稍候"
- :props="defaultProps"
- ></el-tree>
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitDataScope">确 定</el-button>
- <el-button @click="cancelDataScope">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus, deptTreeSelect } from "@/api/system/role"
-import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu"
-
-export default {
- name: "Role",
- dicts: ['sys_normal_disable'],
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 角色表格数据
- roleList: [],
- // 弹出层标题
- title: "",
- // 是否显示弹出层
- open: false,
- // 是否显示弹出层(数据权限)
- openDataScope: false,
- menuExpand: false,
- menuNodeAll: false,
- deptExpand: true,
- deptNodeAll: false,
- // 日期范围
- dateRange: [],
- // 数据范围选项
- dataScopeOptions: [
- {
- value: "1",
- label: "全部数据权限"
- },
- {
- value: "2",
- label: "自定数据权限"
- },
- {
- value: "3",
- label: "本部门数据权限"
- },
- {
- value: "4",
- label: "本部门及以下数据权限"
- },
- {
- value: "5",
- label: "仅本人数据权限"
- }
- ],
- // 菜单列表
- menuOptions: [],
- // 部门列表
- deptOptions: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- roleName: undefined,
- roleKey: undefined,
- status: undefined
- },
- // 表单参数
- form: {},
- defaultProps: {
- children: "children",
- label: "label"
- },
- // 表单校验
- rules: {
- roleName: [
- { required: true, message: "角色名称不能为空", trigger: "blur" }
- ],
- roleKey: [
- { required: true, message: "权限字符不能为空", trigger: "blur" }
- ],
- roleSort: [
- { required: true, message: "角色顺序不能为空", trigger: "blur" }
- ]
- }
- }
- },
- created() {
- this.getList()
- },
- methods: {
- /** 查询角色列表 */
- getList() {
- this.loading = true
- listRole(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.roleList = response.rows
- this.total = response.total
- this.loading = false
- }
- )
- },
- /** 查询菜单树结构 */
- getMenuTreeselect() {
- menuTreeselect().then(response => {
- this.menuOptions = response.data
- })
- },
- // 所有菜单节点数据
- getMenuAllCheckedKeys() {
- // 目前被选中的菜单节点
- let checkedKeys = this.$refs.menu.getCheckedKeys()
- // 半选中的菜单节点
- let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys()
- checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
- return checkedKeys
- },
- // 所有部门节点数据
- getDeptAllCheckedKeys() {
- // 目前被选中的部门节点
- let checkedKeys = this.$refs.dept.getCheckedKeys()
- // 半选中的部门节点
- let halfCheckedKeys = this.$refs.dept.getHalfCheckedKeys()
- checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
- return checkedKeys
- },
- /** 根据角色ID查询菜单树结构 */
- getRoleMenuTreeselect(roleId) {
- return roleMenuTreeselect(roleId).then(response => {
- this.menuOptions = response.menus
- return response
- })
- },
- /** 根据角色ID查询部门树结构 */
- getDeptTree(roleId) {
- return deptTreeSelect(roleId).then(response => {
- this.deptOptions = response.depts
- return response
- })
- },
- // 角色状态修改
- handleStatusChange(row) {
- let text = row.status === "0" ? "启用" : "停用"
- this.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function() {
- return changeRoleStatus(row.roleId, row.status)
- }).then(() => {
- this.$modal.msgSuccess(text + "成功")
- }).catch(function() {
- row.status = row.status === "0" ? "1" : "0"
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 取消按钮(数据权限)
- cancelDataScope() {
- this.openDataScope = false
- this.reset()
- },
- // 表单重置
- reset() {
- if (this.$refs.menu != undefined) {
- this.$refs.menu.setCheckedKeys([])
- }
- this.menuExpand = false,
- this.menuNodeAll = false,
- this.deptExpand = true,
- this.deptNodeAll = false,
- this.form = {
- roleId: undefined,
- roleName: undefined,
- roleKey: undefined,
- roleSort: 0,
- status: "0",
- menuIds: [],
- deptIds: [],
- menuCheckStrictly: true,
- deptCheckStrictly: true,
- remark: undefined
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.roleId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- // 更多操作触发
- handleCommand(command, row) {
- switch (command) {
- case "handleDataScope":
- this.handleDataScope(row)
- break
- case "handleAuthUser":
- this.handleAuthUser(row)
- break
- default:
- break
- }
- },
- // 树权限(展开/折叠)
- handleCheckedTreeExpand(value, type) {
- if (type == 'menu') {
- let treeList = this.menuOptions
- for (let i = 0; i < treeList.length; i++) {
- this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value
- }
- } else if (type == 'dept') {
- let treeList = this.deptOptions
- for (let i = 0; i < treeList.length; i++) {
- this.$refs.dept.store.nodesMap[treeList[i].id].expanded = value
- }
- }
- },
- // 树权限(全选/全不选)
- handleCheckedTreeNodeAll(value, type) {
- if (type == 'menu') {
- this.$refs.menu.setCheckedNodes(value ? this.menuOptions: [])
- } else if (type == 'dept') {
- this.$refs.dept.setCheckedNodes(value ? this.deptOptions: [])
- }
- },
- // 树权限(父子联动)
- handleCheckedTreeConnect(value, type) {
- if (type == 'menu') {
- this.form.menuCheckStrictly = value ? true: false
- } else if (type == 'dept') {
- this.form.deptCheckStrictly = value ? true: false
- }
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- this.getMenuTreeselect()
- this.open = true
- this.title = "添加角色"
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const roleId = row.roleId || this.ids
- const roleMenu = this.getRoleMenuTreeselect(roleId)
- getRole(roleId).then(response => {
- this.form = response.data
- this.open = true
- this.$nextTick(() => {
- roleMenu.then(res => {
- let checkedKeys = res.checkedKeys
- checkedKeys.forEach((v) => {
- this.$nextTick(()=>{
- this.$refs.menu.setChecked(v, true ,false)
- })
- })
- })
- })
- })
- this.title = "修改角色"
- },
- /** 选择角色权限范围触发 */
- dataScopeSelectChange(value) {
- if(value !== '2') {
- this.$refs.dept.setCheckedKeys([])
- }
- },
- /** 分配数据权限操作 */
- handleDataScope(row) {
- this.reset()
- const deptTreeSelect = this.getDeptTree(row.roleId)
- getRole(row.roleId).then(response => {
- this.form = response.data
- this.openDataScope = true
- this.$nextTick(() => {
- deptTreeSelect.then(res => {
- this.$refs.dept.setCheckedKeys(res.checkedKeys)
- })
- })
- })
- this.title = "分配数据权限"
- },
- /** 分配用户操作 */
- handleAuthUser(row) {
- const roleId = row.roleId
- this.$router.push("/system/role-auth/user/" + roleId)
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.roleId != undefined) {
- this.form.menuIds = this.getMenuAllCheckedKeys()
- updateRole(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- this.form.menuIds = this.getMenuAllCheckedKeys()
- addRole(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 提交按钮(数据权限) */
- submitDataScope() {
- if (this.form.roleId != undefined) {
- this.form.deptIds = this.getDeptAllCheckedKeys()
- dataScope(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.openDataScope = false
- this.getList()
- })
- }
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const roleIds = row.roleId || this.ids
- this.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function() {
- return delRole(roleIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/role/export', {
- ...this.queryParams
- }, `role_${new Date().getTime()}.xlsx`)
- }
- }
-}
-</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/role/selectUser.vue b/ruoyi-ui/src/views/system/role/selectUser.vue
deleted file mode 100644
index b44880d..0000000
--- a/ruoyi-ui/src/views/system/role/selectUser.vue
+++ /dev/null
@@ -1,136 +0,0 @@
-<template>
- <!-- 授权用户 -->
- <el-dialog title="选择用户" :visible.sync="visible" width="800px" top="5vh" append-to-body>
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
- <el-form-item label="用户名称" prop="userName">
- <el-input
- v-model="queryParams.userName"
- placeholder="请输入用户名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="手机号码" prop="phonenumber">
- <el-input
- v-model="queryParams.phonenumber"
- placeholder="请输入手机号码"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- <el-row>
- <el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px">
- <el-table-column type="selection" width="55"></el-table-column>
- <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
- <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
- <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
- <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
- <el-table-column label="状态" align="center" prop="status">
- <template slot-scope="scope">
- <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- </el-table>
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- </el-row>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="handleSelectUser">确 定</el-button>
- <el-button @click="visible = false">取 消</el-button>
- </div>
- </el-dialog>
-</template>
-
-<script>
-import { unallocatedUserList, authUserSelectAll } from "@/api/system/role"
-export default {
- dicts: ['sys_normal_disable'],
- props: {
- // 角色编号
- roleId: {
- type: [Number, String]
- }
- },
- data() {
- return {
- // 遮罩层
- visible: false,
- // 选中数组值
- userIds: [],
- // 总条数
- total: 0,
- // 未授权用户数据
- userList: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- roleId: undefined,
- userName: undefined,
- phonenumber: undefined
- }
- }
- },
- methods: {
- // 显示弹框
- show() {
- this.queryParams.roleId = this.roleId
- this.getList()
- this.visible = true
- },
- clickRow(row) {
- this.$refs.table.toggleRowSelection(row)
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.userIds = selection.map(item => item.userId)
- },
- // 查询表数据
- getList() {
- unallocatedUserList(this.queryParams).then(res => {
- this.userList = res.rows
- this.total = res.total
- })
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 选择授权用户操作 */
- handleSelectUser() {
- const roleId = this.queryParams.roleId
- const userIds = this.userIds.join(",")
- if (userIds == "") {
- this.$modal.msgError("请选择要分配的用户")
- return
- }
- authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
- this.$modal.msgSuccess(res.msg)
- this.visible = false
- this.$emit("ok")
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/user/authRole.vue b/ruoyi-ui/src/views/system/user/authRole.vue
deleted file mode 100644
index de0807d..0000000
--- a/ruoyi-ui/src/views/system/user/authRole.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
- <div class="app-container">
- <h4 class="form-header h4">基本信息</h4>
- <el-form ref="form" :model="form" label-width="80px">
- <el-row>
- <el-col :span="8" :offset="2">
- <el-form-item label="用户昵称" prop="nickName">
- <el-input v-model="form.nickName" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="8" :offset="2">
- <el-form-item label="登录账号" prop="userName">
- <el-input v-model="form.userName" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
-
- <h4 class="form-header h4">角色信息</h4>
- <el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="table" @selection-change="handleSelectionChange" :data="roles.slice((pageNum-1)*pageSize,pageNum*pageSize)">
- <el-table-column label="序号" type="index" align="center">
- <template slot-scope="scope">
- <span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
- </template>
- </el-table-column>
- <el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55" />
- <el-table-column label="角色编号" align="center" prop="roleId" />
- <el-table-column label="角色名称" align="center" prop="roleName" />
- <el-table-column label="权限字符" align="center" prop="roleKey" />
- <el-table-column label="创建时间" align="center" prop="createTime" width="180">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- </el-table>
-
- <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
-
- <el-form label-width="100px">
- <el-form-item style="text-align: center;margin-left:-120px;margin-top:30px;">
- <el-button type="primary" @click="submitForm()">提交</el-button>
- <el-button @click="close()">返回</el-button>
- </el-form-item>
- </el-form>
- </div>
-</template>
-
-<script>
-import { getAuthRole, updateAuthRole } from "@/api/system/user"
-
-export default {
- name: "AuthRole",
- data() {
- return {
- // 遮罩层
- loading: true,
- // 分页信息
- total: 0,
- pageNum: 1,
- pageSize: 10,
- // 选中角色编号
- roleIds: [],
- // 角色信息
- roles: [],
- // 用户信息
- form: {}
- }
- },
- created() {
- const userId = this.$route.params && this.$route.params.userId
- if (userId) {
- this.loading = true
- getAuthRole(userId).then((response) => {
- this.form = response.user
- this.roles = response.roles
- this.total = this.roles.length
- this.$nextTick(() => {
- this.roles.forEach((row) => {
- if (row.flag) {
- this.$refs.table.toggleRowSelection(row)
- }
- })
- })
- this.loading = false
- })
- }
- },
- methods: {
- /** 单击选中行数据 */
- clickRow(row) {
- if (this.checkSelectable(row)) {
- this.$refs.table.toggleRowSelection(row)
- }
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.roleIds = selection.map((item) => item.roleId)
- },
- // 保存选中的数据编号
- getRowKey(row) {
- return row.roleId
- },
- // 检查角色状态
- checkSelectable(row) {
- return row.status === "0" ? true : false
- },
- /** 提交按钮 */
- submitForm() {
- const userId = this.form.userId
- const roleIds = this.roleIds.join(",")
- updateAuthRole({ userId: userId, roleIds: roleIds }).then(() => {
- this.$modal.msgSuccess("授权成功")
- this.close()
- })
- },
- /** 关闭按钮 */
- close() {
- const obj = { path: "/system/user" }
- this.$tab.closeOpenPage(obj)
- }
- }
-}
-</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
deleted file mode 100644
index 73f4b49..0000000
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ /dev/null
@@ -1,467 +0,0 @@
-<template>
- <div class="app-container tree-sidebar-manage-wrap">
- <tree-panel title="组织机构" :tree-data="deptOptions" search-placeholder="请输入部门名称" storage-key="dept-sidebar-width" :defaultExpandAll="true" @node-click="handleNodeClick" @refresh="getDeptTree" ref="deptTreeRef" />
- <div class="tree-sidebar-content">
- <div class="content-inner">
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="用户名称" prop="userName">
- <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
- </el-form-item>
- <el-form-item label="手机号码" prop="phonenumber">
- <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
- </el-form-item>
- <el-form-item label="状态" prop="status">
- <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
- <el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="创建时间">
- <el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
-
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
- </el-col>
- <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
- </el-row>
-
- <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="50" align="center" />
- <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
- <el-table-column label="用户名称" align="center" key="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true">
- <template slot-scope="scope">
- <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.userName }}</a>
- </template>
- </el-table-column>
- <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
- <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
- <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
- <el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
- <template slot-scope="scope">
- <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
- </template>
- </el-table-column>
- <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns.createTime.visible" width="160">
- <template slot-scope="scope">
- <span>{{ parseTime(scope.row.createTime) }}</span>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
- <template slot-scope="scope" v-if="scope.row.userId !== 1">
- <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button>
- <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button>
- <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
- <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
- <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
- </div>
- </div>
-
- <!-- 添加或修改用户配置对话框 -->
- <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="用户昵称" prop="nickName">
- <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="归属部门" prop="deptId">
- <treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="手机号码" prop="phonenumber">
- <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="邮箱" prop="email">
- <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
- <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" :rules="pwdValidator">
- <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="用户性别">
- <el-select v-model="form.sex" placeholder="请选择性别">
- <el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="状态">
- <el-radio-group v-model="form.status">
- <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="12">
- <el-form-item label="岗位">
- <el-select v-model="form.postIds" multiple placeholder="请选择岗位">
- <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="角色">
- <el-select v-model="form.roleIds" multiple placeholder="请选择角色">
- <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row>
- <el-col :span="24">
- <el-form-item label="备注">
- <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </el-dialog>
-
- <!-- 用户详情抽屉 -->
- <user-view-drawer ref="userViewRef" />
- <!-- 用户导入对话框 -->
- <excel-import-dialog ref="importUserRef" title="用户导入" action="/system/user/importData" template-action="/system/user/importTemplate" template-file-name="user_template" update-support-label="是否更新已经存在的用户数据" @success="getList" />
- </div>
-</template>
-
-<script>
-import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
-import Treeselect from "@riophae/vue-treeselect"
-import "@riophae/vue-treeselect/dist/vue-treeselect.css"
-import TreePanel from "@/components/TreePanel"
-import ExcelImportDialog from "@/components/ExcelImportDialog"
-import UserViewDrawer from "./view"
-import passwordRule from "@/utils/passwordRule"
-
-export default {
- name: "User",
- mixins: [passwordRule],
- dicts: ['sys_normal_disable', 'sys_user_sex'],
- components: { Treeselect, TreePanel, ExcelImportDialog, UserViewDrawer },
- data() {
- return {
- // 遮罩层
- loading: true,
- // 选中数组
- ids: [],
- // 非单个禁用
- single: true,
- // 非多个禁用
- multiple: true,
- // 显示搜索条件
- showSearch: true,
- // 总条数
- total: 0,
- // 用户表格数据
- userList: null,
- // 弹出层标题
- title: "",
- // 所有部门树选项
- deptOptions: undefined,
- // 过滤掉已禁用部门树选项
- enabledDeptOptions: undefined,
- // 是否显示弹出层
- open: false,
- // 默认密码
- initPassword: undefined,
- // 日期范围
- dateRange: [],
- // 岗位选项
- postOptions: [],
- // 角色选项
- roleOptions: [],
- // 表单参数
- form: {},
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- userName: undefined,
- phonenumber: undefined,
- status: undefined,
- deptId: undefined
- },
- // 列信息
- columns: {
- userId: { label: '用户编号', visible: true },
- userName: { label: '用户名称', visible: true },
- nickName: { label: '用户昵称', visible: true },
- deptName: { label: '部门', visible: true },
- phonenumber: { label: '手机号码', visible: true },
- status: { label: '状态', visible: true },
- createTime: { label: '创建时间', visible: true }
- },
- // 表单校验
- rules: {
- userName: [
- { required: true, message: "用户名称不能为空", trigger: "blur" },
- { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
- ],
- nickName: [
- { required: true, message: "用户昵称不能为空", trigger: "blur" }
- ],
- email: [
- {
- type: "email",
- message: "请输入正确的邮箱地址",
- trigger: ["blur", "change"]
- }
- ],
- phonenumber: [
- {
- pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
- message: "请输入正确的手机号码",
- trigger: "blur"
- }
- ]
- }
- }
- },
- created() {
- this.getList()
- this.getDeptTree()
- this.getConfigKey("sys.user.initPassword").then(response => {
- this.initPassword = response.msg
- })
- },
- methods: {
- /** 查询用户列表 */
- getList() {
- this.loading = true
- listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.userList = response.rows
- this.total = response.total
- this.loading = false
- })
- },
- /** 查询部门下拉树结构 */
- getDeptTree() {
- deptTreeSelect().then(response => {
- this.deptOptions = response.data
- this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
- })
- },
- // 过滤禁用的部门
- filterDisabledDept(deptList) {
- return deptList.filter(dept => {
- if (dept.disabled) {
- return false
- }
- if (dept.children && dept.children.length) {
- dept.children = this.filterDisabledDept(dept.children)
- }
- return true
- })
- },
- // 节点单击事件
- handleNodeClick(data) {
- this.queryParams.deptId = data.id
- this.handleQuery()
- },
- // 用户状态修改
- handleStatusChange(row) {
- let text = row.status === "0" ? "启用" : "停用"
- this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
- return changeUserStatus(row.userId, row.status)
- }).then(() => {
- this.$modal.msgSuccess(text + "成功")
- }).catch(function() {
- row.status = row.status === "0" ? "1" : "0"
- })
- },
- // 取消按钮
- cancel() {
- this.open = false
- this.reset()
- },
- // 表单重置
- reset() {
- this.form = {
- userId: undefined,
- deptId: undefined,
- userName: undefined,
- nickName: undefined,
- password: undefined,
- phonenumber: undefined,
- email: undefined,
- sex: undefined,
- status: "0",
- remark: undefined,
- postIds: [],
- roleIds: []
- }
- this.resetForm("form")
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.dateRange = []
- this.resetForm("queryForm")
- this.queryParams.deptId = undefined
- this.$refs.deptTreeRef.setCurrentKey(null)
- this.handleQuery()
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.ids = selection.map(item => item.userId)
- this.single = selection.length != 1
- this.multiple = !selection.length
- },
- // 更多操作触发
- handleCommand(command, row) {
- switch (command) {
- case "handleResetPwd":
- this.handleResetPwd(row)
- break
- case "handleAuthRole":
- this.handleAuthRole(row)
- break
- default:
- break
- }
- },
- /** 新增按钮操作 */
- handleAdd() {
- this.reset()
- getUser().then(response => {
- this.postOptions = response.posts
- this.roleOptions = response.roles
- this.open = true
- this.title = "添加用户"
- this.form.password = this.initPassword
- })
- },
- /** 修改按钮操作 */
- handleUpdate(row) {
- this.reset()
- const userId = row.userId || this.ids
- getUser(userId).then(response => {
- this.form = response.data
- this.postOptions = response.posts
- this.roleOptions = response.roles
- this.$set(this.form, "postIds", response.postIds)
- this.$set(this.form, "roleIds", response.roleIds)
- this.open = true
- this.title = "修改用户"
- this.form.password = ""
- })
- },
- /** 重置密码按钮操作 */
- handleResetPwd(row) {
- this.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- closeOnClickModal: false,
- inputValidator: this.pwdPromptValidator
- }).then(({ value }) => {
- resetUserPwd(row.userId, value).then(() => {
- this.$modal.msgSuccess("修改成功,新密码是:" + value)
- })
- }).catch(() => {})
- },
- /** 分配角色操作 */
- handleAuthRole(row) {
- const userId = row.userId
- this.$router.push("/system/user-auth/role/" + userId)
- },
- /** 提交按钮 */
- submitForm() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- if (this.form.userId != undefined) {
- updateUser(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.open = false
- this.getList()
- })
- } else {
- addUser(this.form).then(() => {
- this.$modal.msgSuccess("新增成功")
- this.open = false
- this.getList()
- })
- }
- }
- })
- },
- /** 删除按钮操作 */
- handleDelete(row) {
- const userIds = row.userId || this.ids
- this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
- return delUser(userIds)
- }).then(() => {
- this.getList()
- this.$modal.msgSuccess("删除成功")
- }).catch(() => {})
- },
- /** 导出按钮操作 */
- handleExport() {
- this.download('system/user/export', {
- ...this.queryParams
- }, `user_${new Date().getTime()}.xlsx`)
- },
- /** 详情按钮操作 */
- handleViewData(row) {
- this.$refs.userViewRef.open(row.userId)
- },
- /** 导入按钮操作 */
- handleImport() {
- this.$refs.importUserRef.open()
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
deleted file mode 100644
index 369e451..0000000
--- a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
+++ /dev/null
@@ -1,70 +0,0 @@
-<template>
- <el-form ref="form" :model="user" :rules="formRules" label-width="80px">
- <el-form-item label="旧密码" prop="oldPassword">
- <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
- </el-form-item>
- <el-form-item label="新密码" prop="newPassword" :rules="infoPwdValidator">
- <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password/>
- </el-form-item>
- <el-form-item label="确认密码" prop="confirmPassword">
- <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" size="mini" @click="submit">保存</el-button>
- <el-button type="danger" size="mini" @click="close">关闭</el-button>
- </el-form-item>
- </el-form>
-</template>
-
-<script>
-import { updateUserPwd } from "@/api/system/user"
-import passwordRule from "@/utils/passwordRule"
-
-export default {
- mixins: [passwordRule],
- data() {
- return {
- user: {
- oldPassword: undefined,
- newPassword: undefined,
- confirmPassword: undefined
- }
- }
- },
- computed: {
- formRules() {
- return {
- oldPassword: [
- { required: true, message: "旧密码不能为空", trigger: "blur" }
- ],
- confirmPassword: [
- { required: true, message: "确认密码不能为空", trigger: "blur" },
- {
- validator: (rule, value, callback) => {
- if (this.user.newPassword !== value) {
- callback(new Error("两次输入的密码不一致"))
- } else {
- callback()
- }
- }, trigger: "blur"
- }
- ]
- }
- }
- },
- methods: {
- submit() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- updateUserPwd(this.user.oldPassword, this.user.newPassword).then(() => {
- this.$modal.msgSuccess("修改成功")
- })
- }
- })
- },
- close() {
- this.$tab.closePage()
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
deleted file mode 100644
index 4c53614..0000000
--- a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
+++ /dev/null
@@ -1,184 +0,0 @@
-<template>
- <div>
- <div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
- <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
- <el-row>
- <el-col :xs="24" :md="12" :style="{height: '350px'}">
- <vue-cropper
- ref="cropper"
- :img="options.img"
- :info="true"
- :autoCrop="options.autoCrop"
- :autoCropWidth="options.autoCropWidth"
- :autoCropHeight="options.autoCropHeight"
- :fixedBox="options.fixedBox"
- :outputType="options.outputType"
- @realTime="realTime"
- v-if="visible"
- />
- </el-col>
- <el-col :xs="24" :md="12" :style="{height: '350px'}">
- <div class="avatar-upload-preview">
- <img :src="previews.url" :style="previews.img" />
- </div>
- </el-col>
- </el-row>
- <br />
- <el-row>
- <el-col :lg="2" :sm="3" :xs="3">
- <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
- <el-button size="small">
- 选择
- <i class="el-icon-upload el-icon--right"></i>
- </el-button>
- </el-upload>
- </el-col>
- <el-col :lg="{span: 1, offset: 2}" :sm="2" :xs="2">
- <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
- </el-col>
- <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
- <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
- </el-col>
- <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
- <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
- </el-col>
- <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
- <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
- </el-col>
- <el-col :lg="{span: 2, offset: 6}" :sm="2" :xs="2">
- <el-button type="primary" size="small" @click="uploadImg()">提 交</el-button>
- </el-col>
- </el-row>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import store from "@/store"
-import { VueCropper } from "vue-cropper"
-import { uploadAvatar } from "@/api/system/user"
-import { debounce } from '@/utils'
-
-export default {
- components: { VueCropper },
- data() {
- return {
- // 是否显示弹出层
- open: false,
- // 是否显示cropper
- visible: false,
- // 弹出层标题
- title: "修改头像",
- options: {
- img: store.getters.avatar, //裁剪图片的地址
- autoCrop: true, // 是否默认生成截图框
- autoCropWidth: 200, // 默认生成截图框宽度
- autoCropHeight: 200, // 默认生成截图框高度
- fixedBox: true, // 固定截图框大小 不允许改变
- outputType:"png", // 默认生成截图为PNG格式
- filename: 'avatar' // 文件名称
- },
- previews: {},
- resizeHandler: null
- }
- },
- methods: {
- // 编辑头像
- editCropper() {
- this.open = true
- },
- // 打开弹出层结束时的回调
- modalOpened() {
- this.visible = true
- if (!this.resizeHandler) {
- this.resizeHandler = debounce(() => {
- this.refresh()
- }, 100)
- }
- window.addEventListener("resize", this.resizeHandler)
- },
- // 刷新组件
- refresh() {
- this.$refs.cropper.refresh()
- },
- // 覆盖默认的上传行为
- requestUpload() {
- },
- // 向左旋转
- rotateLeft() {
- this.$refs.cropper.rotateLeft()
- },
- // 向右旋转
- rotateRight() {
- this.$refs.cropper.rotateRight()
- },
- // 图片缩放
- changeScale(num) {
- num = num || 1
- this.$refs.cropper.changeScale(num)
- },
- // 上传预处理
- beforeUpload(file) {
- if (file.type.indexOf("image/") == -1) {
- this.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。")
- } else {
- const reader = new FileReader()
- reader.readAsDataURL(file)
- reader.onload = () => {
- this.options.img = reader.result
- this.options.filename = file.name
- }
- }
- },
- // 上传图片
- uploadImg() {
- this.$refs.cropper.getCropBlob(data => {
- let formData = new FormData()
- formData.append("avatarfile", data, this.options.filename)
- uploadAvatar(formData).then(response => {
- this.open = false
- this.options.img = response.imgUrl
- store.commit('SET_AVATAR', this.options.img)
- this.$modal.msgSuccess("修改成功")
- this.visible = false
- })
- })
- },
- // 实时预览
- realTime(data) {
- this.previews = data
- },
- // 关闭窗口
- closeDialog() {
- this.options.img = store.getters.avatar
- this.visible = false
- window.removeEventListener("resize", this.resizeHandler)
- }
- }
-}
-</script>
-<style scoped lang="scss">
-.user-info-head {
- position: relative;
- display: inline-block;
- height: 120px;
-}
-
-.user-info-head:hover:after {
- content: '+';
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- color: #eee;
- background: rgba(0, 0, 0, 0.5);
- font-size: 24px;
- font-style: normal;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- cursor: pointer;
- line-height: 110px;
- border-radius: 50%;
-}
-</style>
diff --git a/ruoyi-ui/src/views/system/user/profile/userInfo.vue b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
deleted file mode 100644
index 5e66632..0000000
--- a/ruoyi-ui/src/views/system/user/profile/userInfo.vue
+++ /dev/null
@@ -1,88 +0,0 @@
-<template>
- <el-form ref="form" :model="form" :rules="rules" label-width="80px">
- <el-form-item label="用户昵称" prop="nickName">
- <el-input v-model="form.nickName" maxlength="30" />
- </el-form-item>
- <el-form-item label="手机号码" prop="phonenumber">
- <el-input v-model="form.phonenumber" maxlength="11" />
- </el-form-item>
- <el-form-item label="邮箱" prop="email">
- <el-input v-model="form.email" maxlength="50" />
- </el-form-item>
- <el-form-item label="性别">
- <el-radio-group v-model="form.sex">
- <el-radio label="0">男</el-radio>
- <el-radio label="1">女</el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" size="mini" @click="submit">保存</el-button>
- <el-button type="danger" size="mini" @click="close">关闭</el-button>
- </el-form-item>
- </el-form>
-</template>
-
-<script>
-import { updateUserProfile } from "@/api/system/user"
-
-export default {
- props: {
- user: {
- type: Object
- }
- },
- data() {
- return {
- form: {},
- // 表单校验
- rules: {
- nickName: [
- { required: true, message: "用户昵称不能为空", trigger: "blur" }
- ],
- email: [
- { required: true, message: "邮箱地址不能为空", trigger: "blur" },
- {
- type: "email",
- message: "请输入正确的邮箱地址",
- trigger: ["blur", "change"]
- }
- ],
- phonenumber: [
- { required: true, message: "手机号码不能为空", trigger: "blur" },
- {
- pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
- message: "请输入正确的手机号码",
- trigger: "blur"
- }
- ]
- }
- }
- },
- watch: {
- user: {
- handler(user) {
- if (user) {
- this.form = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex }
- }
- },
- immediate: true
- }
- },
- methods: {
- submit() {
- this.$refs["form"].validate(valid => {
- if (valid) {
- updateUserProfile(this.form).then(() => {
- this.$modal.msgSuccess("修改成功")
- this.user.phonenumber = this.form.phonenumber
- this.user.email = this.form.email
- })
- }
- })
- },
- close() {
- this.$tab.closePage()
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
deleted file mode 100644
index 144bf6f..0000000
--- a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
+++ /dev/null
@@ -1,106 +0,0 @@
-<template>
- <div>
- <el-dialog
- v-bind="$attrs"
- width="500px"
- :close-on-click-modal="false"
- :modal-append-to-body="false"
- v-on="$listeners"
- @open="onOpen"
- @close="onClose"
- >
- <el-row :gutter="15">
- <el-form
- ref="elForm"
- :model="formData"
- :rules="rules"
- size="medium"
- label-width="100px"
- >
- <el-col :span="24">
- <el-form-item label="生成类型" prop="type">
- <el-radio-group v-model="formData.type">
- <el-radio-button
- v-for="(item, index) in typeOptions"
- :key="index"
- :label="item.value"
- :disabled="item.disabled"
- >
- {{ item.label }}
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="showFileName" label="文件名" prop="fileName">
- <el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
- </el-form-item>
- </el-col>
- </el-form>
- </el-row>
-
- <div slot="footer">
- <el-button @click="close">
- 取消
- </el-button>
- <el-button type="primary" @click="handleConfirm">
- 确定
- </el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-<script>
-export default {
- inheritAttrs: false,
- props: ['showFileName'],
- data() {
- return {
- formData: {
- fileName: undefined,
- type: 'file'
- },
- rules: {
- fileName: [{
- required: true,
- message: '请输入文件名',
- trigger: 'blur'
- }],
- type: [{
- required: true,
- message: '生成类型不能为空',
- trigger: 'change'
- }]
- },
- typeOptions: [{
- label: '页面',
- value: 'file'
- }, {
- label: '弹窗',
- value: 'dialog'
- }]
- }
- },
- computed: {
- },
- watch: {},
- mounted() {},
- methods: {
- onOpen() {
- if (this.showFileName) {
- this.formData.fileName = `${+new Date()}.vue`
- }
- },
- onClose() {
- },
- close(e) {
- this.$emit('update:visible', false)
- },
- handleConfirm() {
- this.$refs.elForm.validate(valid => {
- if (!valid) return
- this.$emit('confirm', { ...this.formData })
- this.close()
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/build/DraggableItem.vue b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
deleted file mode 100644
index f669ac0..0000000
--- a/ruoyi-ui/src/views/tool/build/DraggableItem.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-<script>
-import draggable from 'vuedraggable'
-import render from '@/utils/generator/render'
-
-const components = {
- itemBtns(h, element, index, parent) {
- const { copyItem, deleteItem } = this.$listeners
- return [
- <span class="drawing-item-copy" title="复制" onClick={event => {
- copyItem(element, parent); event.stopPropagation()
- }}>
- <i class="el-icon-copy-document" />
- </span>,
- <span class="drawing-item-delete" title="删除" onClick={event => {
- deleteItem(index, parent); event.stopPropagation()
- }}>
- <i class="el-icon-delete" />
- </span>
- ]
- }
-}
-const layouts = {
- colFormItem(h, element, index, parent) {
- const { activeItem } = this.$listeners
- let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
- if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
- return (
- <el-col span={element.span} class={className}
- nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
- <el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
- label={element.label} required={element.required}>
- <render key={element.renderKey} conf={element} onInput={ event => {
- this.$set(element, 'defaultValue', event)
- }} />
- </el-form-item>
- {components.itemBtns.apply(this, arguments)}
- </el-col>
- )
- },
- rowFormItem(h, element, index, parent) {
- const { activeItem } = this.$listeners
- const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
- let child = renderChildren.apply(this, arguments)
- if (element.type === 'flex') {
- child = <el-row type={element.type} justify={element.justify} align={element.align}>
- {child}
- </el-row>
- }
- return (
- <el-col span={element.span}>
- <el-row gutter={element.gutter} class={className}
- nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
- <span class="component-name">{element.componentName}</span>
- <draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
- {child}
- </draggable>
- {components.itemBtns.apply(this, arguments)}
- </el-row>
- </el-col>
- )
- }
-}
-
-function renderChildren(h, element, index, parent) {
- if (!Array.isArray(element.children)) return null
- return element.children.map((el, i) => {
- const layout = layouts[el.layout]
- if (layout) {
- return layout.call(this, h, el, i, element.children)
- }
- return layoutIsNotFound()
- })
-}
-
-function layoutIsNotFound() {
- throw new Error(`没有与${this.element.layout}匹配的layout`)
-}
-
-export default {
- components: {
- render,
- draggable
- },
- props: [
- 'element',
- 'index',
- 'drawingList',
- 'activeId',
- 'formConf'
- ],
- render(h) {
- const layout = layouts[this.element.layout]
-
- if (layout) {
- return layout.call(this, h, this.element, this.index, this.drawingList)
- }
- return layoutIsNotFound()
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/build/IconsDialog.vue b/ruoyi-ui/src/views/tool/build/IconsDialog.vue
deleted file mode 100644
index 0d12778..0000000
--- a/ruoyi-ui/src/views/tool/build/IconsDialog.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<template>
- <div class="icon-dialog">
- <el-dialog
- v-bind="$attrs"
- width="980px"
- :modal-append-to-body="false"
- v-on="$listeners"
- @open="onOpen"
- @close="onClose"
- >
- <div slot="title">
- 选择图标
- <el-input
- v-model="key"
- size="mini"
- :style="{width: '260px'}"
- placeholder="请输入图标名称"
- prefix-icon="el-icon-search"
- clearable
- />
- </div>
- <ul class="icon-ul">
- <li
- v-for="icon in iconList"
- :key="icon"
- :class="active===icon?'active-item':''"
- @click="onSelect(icon)"
- >
- <i :class="icon" />
- <div>{{ icon }}</div>
- </li>
- </ul>
- </el-dialog>
- </div>
-</template>
-<script>
-import iconList from '@/utils/generator/icon.json'
-
-const originList = iconList.map(name => `el-icon-${name}`)
-
-export default {
- inheritAttrs: false,
- props: ['current'],
- data() {
- return {
- iconList: originList,
- active: null,
- key: ''
- }
- },
- watch: {
- key(val) {
- if (val) {
- this.iconList = originList.filter(name => name.indexOf(val) > -1)
- } else {
- this.iconList = originList
- }
- }
- },
- methods: {
- onOpen() {
- this.active = this.current
- this.key = ''
- },
- onClose() {},
- onSelect(icon) {
- this.active = icon
- this.$emit('select', icon)
- this.$emit('update:visible', false)
- }
- }
-}
-</script>
-<style lang="scss" scoped>
-.icon-ul {
- margin: 0;
- padding: 0;
- font-size: 0;
- li {
- list-style-type: none;
- text-align: center;
- font-size: 14px;
- display: inline-block;
- width: 16.66%;
- box-sizing: border-box;
- height: 108px;
- padding: 15px 6px 6px 6px;
- cursor: pointer;
- overflow: hidden;
- &:hover {
- background: #f2f2f2;
- }
- &.active-item{
- background: #e1f3fb;
- color: #7a6df0
- }
- > i {
- font-size: 30px;
- line-height: 50px;
- }
- }
-}
-.icon-dialog {
- ::v-deep .el-dialog {
- border-radius: 8px;
- margin-bottom: 0;
- margin-top: 4vh !important;
- display: flex;
- flex-direction: column;
- max-height: 92vh;
- overflow: hidden;
- box-sizing: border-box;
- .el-dialog__header {
- padding-top: 14px;
- }
- .el-dialog__body {
- margin: 0 20px 20px 20px;
- padding: 0;
- overflow: auto;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/views/tool/build/RightPanel.vue b/ruoyi-ui/src/views/tool/build/RightPanel.vue
deleted file mode 100644
index 863d74c..0000000
--- a/ruoyi-ui/src/views/tool/build/RightPanel.vue
+++ /dev/null
@@ -1,946 +0,0 @@
-<template>
- <div class="right-board">
- <el-tabs v-model="currentTab" class="center-tabs">
- <el-tab-pane label="组件属性" name="field" />
- <el-tab-pane label="表单属性" name="form" />
- </el-tabs>
- <div class="field-box">
- <a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
- <i class="el-icon-link" />
- </a>
- <el-scrollbar class="right-scrollbar">
- <!-- 组件属性 -->
- <el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
- <el-form-item v-if="activeData.changeTag" label="组件类型">
- <el-select
- v-model="activeData.tagIcon"
- placeholder="请选择组件类型"
- :style="{width: '100%'}"
- @change="tagChange"
- >
- <el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
- <el-option
- v-for="item in group.options"
- :key="item.label"
- :label="item.label"
- :value="item.tagIcon"
- >
- <svg-icon class="node-icon" :icon-class="item.tagIcon" />
- <span> {{ item.label }}</span>
- </el-option>
- </el-option-group>
- </el-select>
- </el-form-item>
- <el-form-item v-if="activeData.vModel!==undefined" label="字段名">
- <el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
- </el-form-item>
- <el-form-item v-if="activeData.componentName!==undefined" label="组件名">
- {{ activeData.componentName }}
- </el-form-item>
- <el-form-item v-if="activeData.label!==undefined" label="标题">
- <el-input v-model="activeData.label" placeholder="请输入标题" />
- </el-form-item>
- <el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
- <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
- </el-form-item>
- <el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
- <el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
- </el-form-item>
- <el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
- <el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
- </el-form-item>
- <el-form-item v-if="activeData.span!==undefined" label="表单栅格">
- <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
- </el-form-item>
- <el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔">
- <el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
- </el-form-item>
- <el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式">
- <el-radio-group v-model="activeData.type">
- <el-radio-button label="default" />
- <el-radio-button label="flex" />
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="水平排列">
- <el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{width: '100%'}">
- <el-option
- v-for="(item, index) in justifyOptions"
- :key="index"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="垂直排列">
- <el-radio-group v-model="activeData.align">
- <el-radio-button label="top" />
- <el-radio-button label="middle" />
- <el-radio-button label="bottom" />
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度">
- <el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
- </el-form-item>
- <el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
- <el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
- </el-form-item>
- <el-form-item v-if="activeData.vModel!==undefined" label="默认值">
- <el-input
- :value="setDefaultValue(activeData.defaultValue)"
- placeholder="请输入默认值"
- @input="onDefaultValueInput"
- />
- </el-form-item>
- <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选">
- <el-input-number
- :value="activeData.min"
- :min="0"
- placeholder="至少应选"
- @input="$set(activeData, 'min', $event?$event:undefined)"
- />
- </el-form-item>
- <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选">
- <el-input-number
- :value="activeData.max"
- :min="0"
- placeholder="最多可选"
- @input="$set(activeData, 'max', $event?$event:undefined)"
- />
- </el-form-item>
- <el-form-item v-if="activeData.prepend!==undefined" label="前缀">
- <el-input v-model="activeData.prepend" placeholder="请输入前缀" />
- </el-form-item>
- <el-form-item v-if="activeData.append!==undefined" label="后缀">
- <el-input v-model="activeData.append" placeholder="请输入后缀" />
- </el-form-item>
- <el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
- <el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
- <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')">
- 选择
- </el-button>
- </el-input>
- </el-form-item>
- <el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
- <el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
- <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')">
- 选择
- </el-button>
- </el-input>
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
- <el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
- </el-form-item>
- <el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
- <el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
- </el-form-item>
- <el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
- <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
- </el-form-item>
- <el-form-item v-if="activeData.min !== undefined" label="最小值">
- <el-input-number v-model="activeData.min" placeholder="最小值" />
- </el-form-item>
- <el-form-item v-if="activeData.max !== undefined" label="最大值">
- <el-input-number v-model="activeData.max" placeholder="最大值" />
- </el-form-item>
- <el-form-item v-if="activeData.step !== undefined" label="步长">
- <el-input-number v-model="activeData.step" placeholder="步数" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
- <el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
- <el-radio-group v-model="activeData['controls-position']">
- <el-radio-button label="">
- 默认
- </el-radio-button>
- <el-radio-button label="right">
- 右侧
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
- <el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
- <template slot="append">
- 个字符
- </template>
- </el-input>
- </el-form-item>
- <el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
- <el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
- </el-form-item>
- <el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
- <el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
- </el-form-item>
- <el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
- <el-input
- :value="setDefaultValue(activeData['active-value'])"
- placeholder="请输入开启值"
- @input="onSwitchValueInput($event, 'active-value')"
- />
- </el-form-item>
- <el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
- <el-input
- :value="setDefaultValue(activeData['inactive-value'])"
- placeholder="请输入关闭值"
- @input="onSwitchValueInput($event, 'inactive-value')"
- />
- </el-form-item>
- <el-form-item
- v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
- label="时间类型"
- >
- <el-select
- v-model="activeData.type"
- placeholder="请选择时间类型"
- :style="{ width: '100%' }"
- @change="dateTypeChange"
- >
- <el-option
- v-for="(item, index) in dateOptions"
- :key="index"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item v-if="activeData.name !== undefined" label="文件字段名">
- <el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
- </el-form-item>
- <el-form-item v-if="activeData.accept !== undefined" label="文件类型">
- <el-select
- v-model="activeData.accept"
- placeholder="请选择文件类型"
- :style="{ width: '100%' }"
- clearable
- >
- <el-option label="图片" value="image/*" />
- <el-option label="视频" value="video/*" />
- <el-option label="音频" value="audio/*" />
- <el-option label="excel" value=".xls,.xlsx" />
- <el-option label="word" value=".doc,.docx" />
- <el-option label="pdf" value=".pdf" />
- <el-option label="txt" value=".txt" />
- </el-select>
- </el-form-item>
- <el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
- <el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
- <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
- <el-option label="KB" value="KB" />
- <el-option label="MB" value="MB" />
- <el-option label="GB" value="GB" />
- </el-select>
- </el-input>
- </el-form-item>
- <el-form-item v-if="activeData.action !== undefined" label="上传地址">
- <el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
- </el-form-item>
- <el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
- <el-radio-group v-model="activeData['list-type']" size="small">
- <el-radio-button label="text">
- text
- </el-radio-button>
- <el-radio-button label="picture">
- picture
- </el-radio-button>
- <el-radio-button label="picture-card">
- picture-card
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item
- v-if="activeData.buttonText !== undefined"
- v-show="'picture-card' !== activeData['list-type']"
- label="按钮文字"
- >
- <el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
- </el-form-item>
- <el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
- <el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
- </el-form-item>
- <el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
- <el-input
- v-model="activeData['picker-options'].selectableRange"
- placeholder="请输入时间段"
- />
- </el-form-item>
- <el-form-item v-if="activeData.format !== undefined" label="时间格式">
- <el-input
- :value="activeData.format"
- placeholder="请输入时间格式"
- @input="setTimeValue($event)"
- />
- </el-form-item>
- <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
- <el-divider>选项</el-divider>
- <draggable
- :list="activeData.options"
- :animation="340"
- group="selectItem"
- handle=".option-drag"
- >
- <div v-for="(item, index) in activeData.options" :key="index" class="select-item">
- <div class="select-line-icon option-drag">
- <i class="el-icon-s-operation" />
- </div>
- <el-input v-model="item.label" placeholder="选项名" size="small" />
- <el-input
- placeholder="选项值"
- size="small"
- :value="item.value"
- @input="setOptionValue(item, $event)"
- />
- <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
- <i class="el-icon-remove-outline" />
- </div>
- </div>
- </draggable>
- <div style="margin-left: 20px;">
- <el-button
- style="padding-bottom: 0"
- icon="el-icon-circle-plus-outline"
- type="text"
- @click="addSelectItem"
- >
- 添加选项
- </el-button>
- </div>
- <el-divider />
- </template>
-
- <template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
- <el-divider>选项</el-divider>
- <el-form-item label="数据类型">
- <el-radio-group v-model="activeData.dataType" size="small">
- <el-radio-button label="dynamic">
- 动态数据
- </el-radio-button>
- <el-radio-button label="static">
- 静态数据
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
-
- <template v-if="activeData.dataType === 'dynamic'">
- <el-form-item label="标签键名">
- <el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
- </el-form-item>
- <el-form-item label="值键名">
- <el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
- </el-form-item>
- <el-form-item label="子级键名">
- <el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
- </el-form-item>
- </template>
-
- <el-tree
- v-if="activeData.dataType === 'static'"
- draggable
- :data="activeData.options"
- node-key="id"
- :expand-on-click-node="false"
- :render-content="renderContent"
- />
- <div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
- <el-button
- style="padding-bottom: 0"
- icon="el-icon-circle-plus-outline"
- type="text"
- @click="addTreeItem"
- >
- 添加父级
- </el-button>
- </div>
- <el-divider />
- </template>
-
- <el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
- <el-radio-group v-model="activeData.optionType">
- <el-radio-button label="default">
- 默认
- </el-radio-button>
- <el-radio-button label="button">
- 按钮
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
- <el-color-picker v-model="activeData['active-color']" />
- </el-form-item>
- <el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
- <el-color-picker v-model="activeData['inactive-color']" />
- </el-form-item>
-
- <el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
- <el-switch v-model="activeData['allow-half']" />
- </el-form-item>
- <el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
- <el-switch v-model="activeData['show-text']" @change="rateTextChange" />
- </el-form-item>
- <el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
- <el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
- </el-form-item>
- <el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
- <el-switch v-model="activeData['show-stops']" />
- </el-form-item>
- <el-form-item v-if="activeData.range !== undefined" label="范围选择">
- <el-switch v-model="activeData.range" @change="rangeChange" />
- </el-form-item>
- <el-form-item
- v-if="activeData.border !== undefined && activeData.optionType === 'default'"
- label="是否带边框"
- >
- <el-switch v-model="activeData.border" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
- <el-select
- v-model="activeData['color-format']"
- placeholder="请选择颜色格式"
- :style="{ width: '100%' }"
- @change="colorFormatChange"
- >
- <el-option
- v-for="(item, index) in colorFormatOptions"
- :key="index"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item
- v-if="activeData.size !== undefined &&
- (activeData.optionType === 'button' ||
- activeData.border ||
- activeData.tag === 'el-color-picker')"
- label="选项尺寸"
- >
- <el-radio-group v-model="activeData.size">
- <el-radio-button label="medium">
- 中等
- </el-radio-button>
- <el-radio-button label="small">
- 较小
- </el-radio-button>
- <el-radio-button label="mini">
- 迷你
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
- <el-switch v-model="activeData['show-word-limit']" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
- <el-switch v-model="activeData['step-strictly']" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
- <el-switch v-model="activeData.props.props.multiple" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
- <el-switch v-model="activeData['show-all-levels']" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
- <el-switch v-model="activeData.filterable" />
- </el-form-item>
- <el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
- <el-switch v-model="activeData.clearable" />
- </el-form-item>
- <el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
- <el-switch v-model="activeData.showTip" />
- </el-form-item>
- <el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
- <el-switch v-model="activeData.multiple" />
- </el-form-item>
- <el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
- <el-switch v-model="activeData['auto-upload']" />
- </el-form-item>
- <el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
- <el-switch v-model="activeData.readonly" />
- </el-form-item>
- <el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
- <el-switch v-model="activeData.disabled" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
- <el-switch v-model="activeData.filterable" />
- </el-form-item>
- <el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
- <el-switch v-model="activeData.multiple" @change="multipleChange" />
- </el-form-item>
- <el-form-item v-if="activeData.required !== undefined" label="是否必填">
- <el-switch v-model="activeData.required" />
- </el-form-item>
-
- <template v-if="activeData.layoutTree">
- <el-divider>布局结构树</el-divider>
- <el-tree
- :data="[activeData]"
- :props="layoutTreeProps"
- node-key="renderKey"
- default-expand-all
- draggable
- >
- <span slot-scope="{ node, data }">
- <span class="node-label">
- <svg-icon class="node-icon" :icon-class="data.tagIcon" />
- {{ node.label }}
- </span>
- </span>
- </el-tree>
- </template>
-
- <template v-if="activeData.layout === 'colFormItem' && activeData.tag !== 'el-button'">
- <el-divider>正则校验</el-divider>
- <div
- v-for="(item, index) in activeData.regList"
- :key="index"
- class="reg-item"
- >
- <span class="close-btn" @click="activeData.regList.splice(index, 1)">
- <i class="el-icon-close" />
- </span>
- <el-form-item label="表达式">
- <el-input v-model="item.pattern" placeholder="请输入正则" />
- </el-form-item>
- <el-form-item label="错误提示" style="margin-bottom:0">
- <el-input v-model="item.message" placeholder="请输入错误提示" />
- </el-form-item>
- </div>
- <div style="margin-left: 20px">
- <el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
- 添加规则
- </el-button>
- </div>
- </template>
- </el-form>
- <!-- 表单属性 -->
- <el-form v-show="currentTab === 'form'" size="small" label-width="90px">
- <el-form-item label="表单名">
- <el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
- </el-form-item>
- <el-form-item label="表单模型">
- <el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
- </el-form-item>
- <el-form-item label="校验模型">
- <el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
- </el-form-item>
- <el-form-item label="表单尺寸">
- <el-radio-group v-model="formConf.size">
- <el-radio-button label="medium">
- 中等
- </el-radio-button>
- <el-radio-button label="small">
- 较小
- </el-radio-button>
- <el-radio-button label="mini">
- 迷你
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="标签对齐">
- <el-radio-group v-model="formConf.labelPosition">
- <el-radio-button label="left">
- 左对齐
- </el-radio-button>
- <el-radio-button label="right">
- 右对齐
- </el-radio-button>
- <el-radio-button label="top">
- 顶部对齐
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="标签宽度">
- <el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
- </el-form-item>
- <el-form-item label="栅格间隔">
- <el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
- </el-form-item>
- <el-form-item label="禁用表单">
- <el-switch v-model="formConf.disabled" />
- </el-form-item>
- <el-form-item label="表单按钮">
- <el-switch v-model="formConf.formBtns" />
- </el-form-item>
- <el-form-item label="显示未选中组件边框">
- <el-switch v-model="formConf.unFocusedComponentBorder" />
- </el-form-item>
- </el-form>
- </el-scrollbar>
- </div>
-
- <treeNode-dialog :visible.sync="dialogVisible" title="添加选项" @commit="addNode" />
- <icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
- </div>
-</template>
-
-<script>
-import { isArray } from 'util'
-import draggable from 'vuedraggable'
-import TreeNodeDialog from './TreeNodeDialog'
-import { isNumberStr } from '@/utils/index'
-import IconsDialog from './IconsDialog'
-import {
- inputComponents,
- selectComponents,
- layoutComponents
-} from '@/utils/generator/config'
-
-const dateTimeFormat = {
- date: 'yyyy-MM-dd',
- week: 'yyyy 第 WW 周',
- month: 'yyyy-MM',
- year: 'yyyy',
- datetime: 'yyyy-MM-dd HH:mm:ss',
- daterange: 'yyyy-MM-dd',
- monthrange: 'yyyy-MM',
- datetimerange: 'yyyy-MM-dd HH:mm:ss'
-}
-
-export default {
- components: {
- draggable,
- TreeNodeDialog,
- IconsDialog
- },
- props: ['showField', 'activeData', 'formConf'],
- data() {
- return {
- currentTab: 'field',
- currentNode: null,
- dialogVisible: false,
- iconsVisible: false,
- currentIconModel: null,
- dateTypeOptions: [
- {
- label: '日(date)',
- value: 'date'
- },
- {
- label: '周(week)',
- value: 'week'
- },
- {
- label: '月(month)',
- value: 'month'
- },
- {
- label: '年(year)',
- value: 'year'
- },
- {
- label: '日期时间(datetime)',
- value: 'datetime'
- }
- ],
- dateRangeTypeOptions: [
- {
- label: '日期范围(daterange)',
- value: 'daterange'
- },
- {
- label: '月范围(monthrange)',
- value: 'monthrange'
- },
- {
- label: '日期时间范围(datetimerange)',
- value: 'datetimerange'
- }
- ],
- colorFormatOptions: [
- {
- label: 'hex',
- value: 'hex'
- },
- {
- label: 'rgb',
- value: 'rgb'
- },
- {
- label: 'rgba',
- value: 'rgba'
- },
- {
- label: 'hsv',
- value: 'hsv'
- },
- {
- label: 'hsl',
- value: 'hsl'
- }
- ],
- justifyOptions: [
- {
- label: 'start',
- value: 'start'
- },
- {
- label: 'end',
- value: 'end'
- },
- {
- label: 'center',
- value: 'center'
- },
- {
- label: 'space-around',
- value: 'space-around'
- },
- {
- label: 'space-between',
- value: 'space-between'
- }
- ],
- layoutTreeProps: {
- label(data, node) {
- return data.componentName || `${data.label}: ${data.vModel}`
- }
- }
- }
- },
- computed: {
- documentLink() {
- return (
- this.activeData.document
- || 'https://element.eleme.cn/#/zh-CN/component/installation'
- )
- },
- dateOptions() {
- if (
- this.activeData.type !== undefined
- && this.activeData.tag === 'el-date-picker'
- ) {
- if (this.activeData['start-placeholder'] === undefined) {
- return this.dateTypeOptions
- }
- return this.dateRangeTypeOptions
- }
- return []
- },
- tagList() {
- return [
- {
- label: '输入型组件',
- options: inputComponents
- },
- {
- label: '选择型组件',
- options: selectComponents
- }
- ]
- }
- },
- methods: {
- addReg() {
- this.activeData.regList.push({
- pattern: '',
- message: ''
- })
- },
- addSelectItem() {
- this.activeData.options.push({
- label: '',
- value: ''
- })
- },
- addTreeItem() {
- ++this.idGlobal
- this.dialogVisible = true
- this.currentNode = this.activeData.options
- },
- renderContent(h, { node, data, store }) {
- return (
- <div class="custom-tree-node">
- <span>{node.label}</span>
- <span class="node-operation">
- <i on-click={() => this.append(data)}
- class="el-icon-plus"
- title="添加"
- ></i>
- <i on-click={() => this.remove(node, data)}
- class="el-icon-delete"
- title="删除"
- ></i>
- </span>
- </div>
- )
- },
- append(data) {
- if (!data.children) {
- this.$set(data, 'children', [])
- }
- this.dialogVisible = true
- this.currentNode = data.children
- },
- remove(node, data) {
- const { parent } = node
- const children = parent.data.children || parent.data
- const index = children.findIndex(d => d.id === data.id)
- children.splice(index, 1)
- },
- addNode(data) {
- this.currentNode.push(data)
- },
- setOptionValue(item, val) {
- item.value = isNumberStr(val) ? +val : val
- },
- setDefaultValue(val) {
- if (Array.isArray(val)) {
- return val.join(',')
- }
- if (['string', 'number'].indexOf(val) > -1) {
- return val
- }
- if (typeof val === 'boolean') {
- return `${val}`
- }
- return val
- },
- onDefaultValueInput(str) {
- if (isArray(this.activeData.defaultValue)) {
- // 数组
- this.$set(
- this.activeData,
- 'defaultValue',
- str.split(',').map(val => (isNumberStr(val) ? +val : val))
- )
- } else if (['true', 'false'].indexOf(str) > -1) {
- // 布尔
- this.$set(this.activeData, 'defaultValue', JSON.parse(str))
- } else {
- // 字符串和数字
- this.$set(
- this.activeData,
- 'defaultValue',
- isNumberStr(str) ? +str : str
- )
- }
- },
- onSwitchValueInput(val, name) {
- if (['true', 'false'].indexOf(val) > -1) {
- this.$set(this.activeData, name, JSON.parse(val))
- } else {
- this.$set(this.activeData, name, isNumberStr(val) ? +val : val)
- }
- },
- setTimeValue(val, type) {
- const valueFormat = type === 'week' ? dateTimeFormat.date : val
- this.$set(this.activeData, 'defaultValue', null)
- this.$set(this.activeData, 'value-format', valueFormat)
- this.$set(this.activeData, 'format', val)
- },
- spanChange(val) {
- this.formConf.span = val
- },
- multipleChange(val) {
- this.$set(this.activeData, 'defaultValue', val ? [] : '')
- },
- dateTypeChange(val) {
- this.setTimeValue(dateTimeFormat[val], val)
- },
- rangeChange(val) {
- this.$set(
- this.activeData,
- 'defaultValue',
- val ? [this.activeData.min, this.activeData.max] : this.activeData.min
- )
- },
- rateTextChange(val) {
- if (val) this.activeData['show-score'] = false
- },
- rateScoreChange(val) {
- if (val) this.activeData['show-text'] = false
- },
- colorFormatChange(val) {
- this.activeData.defaultValue = null
- this.activeData['show-alpha'] = val.indexOf('a') > -1
- this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
- },
- openIconsDialog(model) {
- this.iconsVisible = true
- this.currentIconModel = model
- },
- setIcon(val) {
- this.activeData[this.currentIconModel] = val
- },
- tagChange(tagIcon) {
- let target = inputComponents.find(item => item.tagIcon === tagIcon)
- if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
- this.$emit('tag-change', target)
- }
- }
-}
-</script>
-
-<style lang="scss" scoped>
-.right-board {
- width: 350px;
- position: absolute;
- right: 0;
- top: 0;
- padding-top: 3px;
- .field-box {
- position: relative;
- height: calc(100vh - 42px);
- box-sizing: border-box;
- overflow: hidden;
- }
- .el-scrollbar {
- height: 100%;
- }
-}
-.select-item {
- display: flex;
- border: 1px dashed #fff;
- box-sizing: border-box;
- & .close-btn {
- cursor: pointer;
- color: #f56c6c;
- }
- & .el-input + .el-input {
- margin-left: 4px;
- }
-}
-.select-item + .select-item {
- margin-top: 4px;
-}
-.select-item.sortable-chosen {
- border: 1px dashed #409eff;
-}
-.select-line-icon {
- line-height: 32px;
- font-size: 22px;
- padding: 0 4px;
- color: #777;
-}
-.option-drag {
- cursor: move;
-}
-.time-range {
- .el-date-editor {
- width: 227px;
- }
- ::v-deep .el-icon-time {
- display: none;
- }
-}
-.document-link {
- position: absolute;
- display: block;
- width: 26px;
- height: 26px;
- top: 0;
- left: 0;
- cursor: pointer;
- background: #409eff;
- z-index: 1;
- border-radius: 0 0 6px 0;
- text-align: center;
- line-height: 26px;
- color: #fff;
- font-size: 18px;
-}
-.node-label{
- font-size: 14px;
-}
-.node-icon{
- color: #bebfc3;
-}
-</style>
diff --git a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
deleted file mode 100644
index 2f27324..0000000
--- a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
+++ /dev/null
@@ -1,148 +0,0 @@
-<template>
- <div>
- <el-dialog
- v-bind="$attrs"
- :close-on-click-modal="false"
- :modal-append-to-body="false"
- v-on="$listeners"
- @open="onOpen"
- @close="onClose"
- >
- <el-row :gutter="0">
- <el-form
- ref="elForm"
- :model="formData"
- :rules="rules"
- size="small"
- label-width="100px"
- >
- <el-col :span="24">
- <el-form-item
- label="选项名"
- prop="label"
- >
- <el-input
- v-model="formData.label"
- placeholder="请输入选项名"
- clearable
- />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item
- label="选项值"
- prop="value"
- >
- <el-input
- v-model="formData.value"
- placeholder="请输入选项值"
- clearable
- >
- <el-select
- slot="append"
- v-model="dataType"
- :style="{width: '100px'}"
- >
- <el-option
- v-for="(item, index) in dataTypeOptions"
- :key="index"
- :label="item.label"
- :value="item.value"
- :disabled="item.disabled"
- />
- </el-select>
- </el-input>
- </el-form-item>
- </el-col>
- </el-form>
- </el-row>
- <div slot="footer">
- <el-button
- type="primary"
- @click="handleConfirm"
- >
- 确定
- </el-button>
- <el-button @click="close">
- 取消
- </el-button>
- </div>
- </el-dialog>
- </div>
-</template>
-<script>
-import { isNumberStr } from '@/utils/index'
-
-export default {
- components: {},
- inheritAttrs: false,
- props: [],
- data() {
- return {
- id: 100,
- formData: {
- label: undefined,
- value: undefined
- },
- rules: {
- label: [
- {
- required: true,
- message: '请输入选项名',
- trigger: 'blur'
- }
- ],
- value: [
- {
- required: true,
- message: '请输入选项值',
- trigger: 'blur'
- }
- ]
- },
- dataType: 'string',
- dataTypeOptions: [
- {
- label: '字符串',
- value: 'string'
- },
- {
- label: '数字',
- value: 'number'
- }
- ]
- }
- },
- computed: {},
- watch: {
- 'formData.value': function (val) {
- this.dataType = isNumberStr(val) ? 'number' : 'string'
- }
- },
- created() {},
- mounted() {},
- methods: {
- onOpen() {
- this.formData = {
- label: undefined,
- value: undefined
- }
- },
- onClose() {},
- close() {
- this.$emit('update:visible', false)
- },
- handleConfirm() {
- this.$refs.elForm.validate(valid => {
- if (!valid) return
- if (this.dataType === 'number') {
- this.formData.value = parseFloat(this.formData.value)
- }
- this.formData.id = this.id++
- this.$emit('commit', this.formData)
- this.close()
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue
deleted file mode 100644
index 26c7eec..0000000
--- a/ruoyi-ui/src/views/tool/build/index.vue
+++ /dev/null
@@ -1,775 +0,0 @@
-<template>
- <div class="container">
- <div class="left-board">
- <div class="logo-wrapper">
- <div class="logo">
- <img :src="logo" alt="logo"> Form Generator
- </div>
- </div>
- <el-scrollbar class="left-scrollbar">
- <div class="components-list">
- <div class="components-title">
- <svg-icon icon-class="component" />输入型组件
- </div>
- <draggable
- class="components-draggable"
- :list="inputComponents"
- :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
- :clone="cloneComponent"
- draggable=".components-item"
- :sort="false"
- @end="onEnd"
- >
- <div
- v-for="(element, index) in inputComponents" :key="index" class="components-item"
- @click="addComponent(element)"
- >
- <div class="components-body">
- <svg-icon :icon-class="element.tagIcon" />
- {{ element.label }}
- </div>
- </div>
- </draggable>
- <div class="components-title">
- <svg-icon icon-class="component" />选择型组件
- </div>
- <draggable
- class="components-draggable"
- :list="selectComponents"
- :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
- :clone="cloneComponent"
- draggable=".components-item"
- :sort="false"
- @end="onEnd"
- >
- <div
- v-for="(element, index) in selectComponents"
- :key="index"
- class="components-item"
- @click="addComponent(element)"
- >
- <div class="components-body">
- <svg-icon :icon-class="element.tagIcon" />
- {{ element.label }}
- </div>
- </div>
- </draggable>
- <div class="components-title">
- <svg-icon icon-class="component" /> 布局型组件
- </div>
- <draggable
- class="components-draggable" :list="layoutComponents"
- :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
- draggable=".components-item" :sort="false" @end="onEnd"
- >
- <div
- v-for="(element, index) in layoutComponents" :key="index" class="components-item"
- @click="addComponent(element)"
- >
- <div class="components-body">
- <svg-icon :icon-class="element.tagIcon" />
- {{ element.label }}
- </div>
- </div>
- </draggable>
- </div>
- </el-scrollbar>
- </div>
-
- <div class="center-board">
- <div class="action-bar">
- <el-button icon="el-icon-download" type="text" @click="download">
- 导出vue文件
- </el-button>
- <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
- 复制代码
- </el-button>
- <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
- 清空
- </el-button>
- </div>
- <el-scrollbar class="center-scrollbar">
- <el-row class="center-board-row" :gutter="formConf.gutter">
- <el-form
- :size="formConf.size"
- :label-position="formConf.labelPosition"
- :disabled="formConf.disabled"
- :label-width="formConf.labelWidth + 'px'"
- >
- <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
- <draggable-item
- v-for="(element, index) in drawingList"
- :key="element.renderKey"
- :drawing-list="drawingList"
- :element="element"
- :index="index"
- :active-id="activeId"
- :form-conf="formConf"
- @activeItem="activeFormItem"
- @copyItem="drawingItemCopy"
- @deleteItem="drawingItemDelete"
- />
- </draggable>
- <div v-show="!drawingList.length" class="empty-info">
- 从左侧拖入或点选组件进行表单设计
- </div>
- </el-form>
- </el-row>
- </el-scrollbar>
- </div>
-
- <right-panel
- :active-data="activeData"
- :form-conf="formConf"
- :show-field="!!drawingList.length"
- @tag-change="tagChange"
- />
-
- <code-type-dialog
- :visible.sync="dialogVisible"
- title="选择生成类型"
- :show-file-name="showFileName"
- @confirm="generate"
- />
- <input id="copyNode" type="hidden">
- </div>
-</template>
-
-<script>
-import draggable from 'vuedraggable'
-import beautifier from 'js-beautify'
-import ClipboardJS from 'clipboard'
-import render from '@/utils/generator/render'
-import RightPanel from './RightPanel'
-import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'
-import { beautifierConf, titleCase } from '@/utils/index'
-import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
-import { makeUpJs } from '@/utils/generator/js'
-import { makeUpCss } from '@/utils/generator/css'
-import { drawingDefaultValue, initDrawingDefaultValue, cleanDrawingDefaultValue } from '@/utils/generator/drawingDefault'
-import logo from '@/assets/logo/logo.png'
-import CodeTypeDialog from './CodeTypeDialog'
-import DraggableItem from './DraggableItem'
-
-let oldActiveId
-let tempActiveData
-let clipboard = null
-
-export default {
- components: {
- draggable,
- render,
- RightPanel,
- CodeTypeDialog,
- DraggableItem
- },
- data() {
- return {
- logo,
- idGlobal: 100,
- formConf,
- inputComponents,
- selectComponents,
- layoutComponents,
- labelWidth: 100,
- drawingList: drawingDefaultValue,
- drawingData: {},
- activeId: drawingDefaultValue[0].formId,
- drawerVisible: false,
- formData: {},
- dialogVisible: false,
- generateConf: null,
- showFileName: false,
- activeData: drawingDefaultValue[0]
- }
- },
- beforeCreate() {
- initDrawingDefaultValue()
- },
- created() {
- // 防止 firefox 下 拖拽 会新打卡一个选项卡
- document.body.ondrop = event => {
- event.preventDefault()
- event.stopPropagation()
- }
- },
- watch: {
- 'activeData.label': function (val, oldVal) {
- if (
- this.activeData.placeholder === undefined
- || !this.activeData.tag
- || oldActiveId !== this.activeId
- ) {
- return
- }
- this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
- },
- activeId: {
- handler(val) {
- oldActiveId = val
- },
- immediate: true
- }
- },
- mounted() {
- clipboard = new ClipboardJS('#copyNode', {
- text: trigger => {
- const codeStr = this.generateCode()
- this.$notify({
- title: '成功',
- message: '代码已复制到剪切板,可粘贴。',
- type: 'success'
- })
- return codeStr
- }
- })
- clipboard.on('error', e => {
- this.$message.error('代码复制失败')
- })
- },
- beforeDestroy() {
- clipboard.destroy()
- },
- methods: {
- activeFormItem(element) {
- this.activeData = element
- this.activeId = element.formId
- },
- onEnd(obj, a) {
- if (obj.from !== obj.to) {
- this.activeData = tempActiveData
- this.activeId = this.idGlobal
- }
- },
- addComponent(item) {
- const clone = this.cloneComponent(item)
- this.drawingList.push(clone)
- this.activeFormItem(clone)
- },
- cloneComponent(origin) {
- const clone = JSON.parse(JSON.stringify(origin))
- clone.formId = ++this.idGlobal
- clone.span = formConf.span
- clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
- if (!clone.layout) clone.layout = 'colFormItem'
- if (clone.layout === 'colFormItem') {
- clone.vModel = `field${this.idGlobal}`
- clone.placeholder !== undefined && (clone.placeholder += clone.label)
- tempActiveData = clone
- } else if (clone.layout === 'rowFormItem') {
- delete clone.label
- clone.componentName = `row${this.idGlobal}`
- clone.gutter = this.formConf.gutter
- tempActiveData = clone
- }
- return tempActiveData
- },
- AssembleFormData() {
- this.formData = {
- fields: JSON.parse(JSON.stringify(this.drawingList)),
- ...this.formConf
- }
- },
- generate(data) {
- const func = this[`exec${titleCase(this.operationType)}`]
- this.generateConf = data
- func && func(data)
- },
- execRun(data) {
- this.AssembleFormData()
- this.drawerVisible = true
- },
- execDownload(data) {
- const codeStr = this.generateCode()
- const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
- this.$download.saveAs(blob, data.fileName)
- },
- execCopy(data) {
- document.getElementById('copyNode').click()
- },
- empty() {
- this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
- () => {
- this.drawingList = []
- cleanDrawingDefaultValue()
- }
- )
- },
- drawingItemCopy(item, parent) {
- let clone = JSON.parse(JSON.stringify(item))
- clone = this.createIdAndKey(clone)
- parent.push(clone)
- this.activeFormItem(clone)
- },
- createIdAndKey(item) {
- item.formId = ++this.idGlobal
- item.renderKey = +new Date()
- if (item.layout === 'colFormItem') {
- item.vModel = `field${this.idGlobal}`
- } else if (item.layout === 'rowFormItem') {
- item.componentName = `row${this.idGlobal}`
- }
- if (Array.isArray(item.children)) {
- item.children = item.children.map(childItem => this.createIdAndKey(childItem))
- }
- return item
- },
- drawingItemDelete(index, parent) {
- parent.splice(index, 1)
- this.$nextTick(() => {
- const len = this.drawingList.length
- if (len) {
- this.activeFormItem(this.drawingList[len - 1])
- }
- })
- },
- generateCode() {
- const { type } = this.generateConf
- this.AssembleFormData()
- const script = vueScript(makeUpJs(this.formData, type))
- const html = vueTemplate(makeUpHtml(this.formData, type))
- const css = cssStyle(makeUpCss(this.formData))
- return beautifier.html(html + script + css, beautifierConf.html)
- },
- download() {
- this.dialogVisible = true
- this.showFileName = true
- this.operationType = 'download'
- },
- run() {
- this.dialogVisible = true
- this.showFileName = false
- this.operationType = 'run'
- },
- copy() {
- this.dialogVisible = true
- this.showFileName = false
- this.operationType = 'copy'
- },
- tagChange(newTag) {
- newTag = this.cloneComponent(newTag)
- newTag.vModel = this.activeData.vModel
- newTag.formId = this.activeId
- newTag.span = this.activeData.span
- delete this.activeData.tag
- delete this.activeData.tagIcon
- delete this.activeData.document
- Object.keys(newTag).forEach(key => {
- if (this.activeData[key] !== undefined
- && typeof this.activeData[key] === typeof newTag[key]) {
- newTag[key] = this.activeData[key]
- }
- })
- this.activeData = newTag
- this.updateDrawingList(newTag, this.drawingList)
- },
- updateDrawingList(newTag, list) {
- const index = list.findIndex(item => item.formId === this.activeId)
- if (index > -1) {
- list.splice(index, 1, newTag)
- } else {
- list.forEach(item => {
- if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
- })
- }
- }
- }
-}
-</script>
-
-<style lang='scss'>
-.editor-tabs{
- background: #121315;
- .el-tabs__header{
- margin: 0;
- border-bottom-color: #121315;
- .el-tabs__nav{
- border-color: #121315;
- }
- }
- .el-tabs__item{
- height: 32px;
- line-height: 32px;
- color: #888a8e;
- border-left: 1px solid #121315 !important;
- background: #363636;
- margin-right: 5px;
- user-select: none;
- }
- .el-tabs__item.is-active{
- background: #1e1e1e;
- border-bottom-color: #1e1e1e!important;
- color: #fff;
- }
- .el-icon-edit{
- color: #f1fa8c;
- }
- .el-icon-document{
- color: #a95812;
- }
-}
-
-// home
-.right-scrollbar {
- .el-scrollbar__view {
- padding: 12px 18px 15px 15px;
- }
-}
-.left-scrollbar .el-scrollbar__wrap {
- box-sizing: border-box;
- overflow-x: hidden !important;
- margin-bottom: 0 !important;
-}
-.center-tabs{
- .el-tabs__header{
- margin-bottom: 0!important;
- }
- .el-tabs__item{
- width: 50%;
- text-align: center;
- }
- .el-tabs__nav{
- width: 100%;
- }
-}
-.reg-item{
- padding: 12px 6px;
- background: #f8f8f8;
- position: relative;
- border-radius: 4px;
- .close-btn{
- position: absolute;
- right: -6px;
- top: -6px;
- display: block;
- width: 16px;
- height: 16px;
- line-height: 16px;
- background: rgba(0, 0, 0, 0.2);
- border-radius: 50%;
- color: #fff;
- text-align: center;
- z-index: 1;
- cursor: pointer;
- font-size: 12px;
- &:hover{
- background: rgba(210, 23, 23, 0.5)
- }
- }
- & + .reg-item{
- margin-top: 18px;
- }
-}
-.action-bar{
- & .el-button+.el-button {
- margin-left: 15px;
- }
- & i {
- font-size: 20px;
- vertical-align: middle;
- position: relative;
- top: -1px;
- }
-}
-
-.custom-tree-node{
- width: 100%;
- font-size: 14px;
- .node-operation{
- float: right;
- }
- i[class*="el-icon"] + i[class*="el-icon"]{
- margin-left: 6px;
- }
- .el-icon-plus{
- color: #409EFF;
- }
- .el-icon-delete{
- color: #157a0c;
- }
-}
-
-.left-scrollbar .el-scrollbar__view{
- overflow-x: hidden;
-}
-
-.el-rate{
- display: inline-block;
- vertical-align: text-top;
-}
-.el-upload__tip{
- line-height: 1.2;
-}
-
-$selectedColor: #f6f7ff;
-$lighterBlue: #409EFF;
-
-.container {
- position: relative;
- width: 100%;
- height: 100%;
-}
-
-.components-list {
- padding: 8px;
- box-sizing: border-box;
- height: 100%;
- .components-item {
- display: inline-block;
- width: 48%;
- margin: 1%;
- transition: transform 0ms !important;
- }
-}
-.components-draggable{
- padding-bottom: 20px;
-}
-.components-title{
- font-size: 14px;
- color: #222;
- margin: 6px 2px;
- .svg-icon{
- color: #666;
- font-size: 18px;
- }
-}
-
-.components-body {
- padding: 8px 10px;
- background: $selectedColor;
- font-size: 12px;
- cursor: move;
- border: 1px dashed $selectedColor;
- border-radius: 3px;
- .svg-icon{
- color: #777;
- font-size: 15px;
- }
- &:hover {
- border: 1px dashed #787be8;
- color: #787be8;
- .svg-icon {
- color: #787be8;
- }
- }
-}
-
-.left-board {
- width: 260px;
- position: absolute;
- left: 0;
- top: 0;
- height: 100vh;
-}
-.left-scrollbar{
- height: calc(100vh - 42px);
- overflow: hidden;
-}
-.center-scrollbar {
- height: calc(100vh - 42px);
- overflow: hidden;
- border-left: 1px solid #f1e8e8;
- border-right: 1px solid #f1e8e8;
- box-sizing: border-box;
-}
-.center-board {
- height: 100vh;
- width: auto;
- margin: 0 350px 0 260px;
- box-sizing: border-box;
-}
-.empty-info{
- position: absolute;
- top: 46%;
- left: 0;
- right: 0;
- text-align: center;
- font-size: 18px;
- color: #ccb1ea;
- letter-spacing: 4px;
-}
-.action-bar{
- position: relative;
- height: 42px;
- text-align: right;
- padding: 0 15px;
- box-sizing: border-box;;
- border: 1px solid #f1e8e8;
- border-top: none;
- border-left: none;
- .delete-btn{
- color: #F56C6C;
- }
-}
-.logo-wrapper{
- position: relative;
- height: 42px;
- background: #fff;
- border-bottom: 1px solid #f1e8e8;
- box-sizing: border-box;
-}
-.logo{
- position: absolute;
- left: 12px;
- top: 6px;
- line-height: 30px;
- color: #00afff;
- font-weight: 600;
- font-size: 17px;
- white-space: nowrap;
- > img{
- width: 30px;
- height: 30px;
- vertical-align: top;
- }
- .github{
- display: inline-block;
- vertical-align: sub;
- margin-left: 15px;
- > img{
- height: 22px;
- }
- }
-}
-
-.center-board-row {
- padding: 12px 12px 15px 12px;
- box-sizing: border-box;
- & > .el-form {
- // 69 = 12+15+42
- height: calc(100vh - 69px);
- }
-}
-.drawing-board {
- height: 100%;
- position: relative;
- .components-body {
- padding: 0;
- margin: 0;
- font-size: 0;
- }
- .sortable-ghost {
- position: relative;
- display: block;
- overflow: hidden;
- &::before {
- content: " ";
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- height: 3px;
- background: rgb(89, 89, 223);
- z-index: 2;
- }
- }
- .components-item.sortable-ghost {
- width: 100%;
- height: 60px;
- background-color: $selectedColor;
- }
- .active-from-item {
- & > .el-form-item{
- background: $selectedColor;
- border-radius: 6px;
- }
- & > .drawing-item-copy, & > .drawing-item-delete{
- display: initial;
- }
- & > .component-name{
- color: $lighterBlue;
- }
- }
- .el-form-item{
- margin-bottom: 15px;
- }
-}
-.drawing-item{
- position: relative;
- cursor: move;
- &.unfocus-bordered:not(.activeFromItem) > div:first-child {
- border: 1px dashed #ccc;
- }
- .el-form-item{
- padding: 12px 10px;
- }
-}
-.drawing-row-item{
- position: relative;
- cursor: move;
- box-sizing: border-box;
- border: 1px dashed #ccc;
- border-radius: 3px;
- padding: 0 2px;
- margin-bottom: 15px;
- .drawing-row-item {
- margin-bottom: 2px;
- }
- .el-col{
- margin-top: 22px;
- }
- .el-form-item{
- margin-bottom: 0;
- }
- .drag-wrapper{
- min-height: 80px;
- }
- &.active-from-item{
- border: 1px dashed $lighterBlue;
- }
- .component-name{
- position: absolute;
- top: 0;
- left: 0;
- font-size: 12px;
- color: #bbb;
- display: inline-block;
- padding: 0 6px;
- }
-}
-.drawing-item, .drawing-row-item{
- &:hover {
- & > .el-form-item{
- background: $selectedColor;
- border-radius: 6px;
- }
- & > .drawing-item-copy, & > .drawing-item-delete{
- display: initial;
- }
- }
- & > .drawing-item-copy, & > .drawing-item-delete{
- display: none;
- position: absolute;
- top: -10px;
- width: 22px;
- height: 22px;
- line-height: 22px;
- text-align: center;
- border-radius: 50%;
- font-size: 12px;
- border: 1px solid;
- cursor: pointer;
- z-index: 1;
- }
- & > .drawing-item-copy{
- right: 56px;
- border-color: $lighterBlue;
- color: $lighterBlue;
- background: #fff;
- &:hover{
- background: $lighterBlue;
- color: #fff;
- }
- }
- & > .drawing-item-delete{
- right: 24px;
- border-color: #F56C6C;
- color: #F56C6C;
- background: #fff;
- &:hover{
- background: #F56C6C;
- color: #fff;
- }
- }
-}
-</style>
diff --git a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
deleted file mode 100644
index d086a65..0000000
--- a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
+++ /dev/null
@@ -1,60 +0,0 @@
-<template>
- <el-form ref="basicInfoForm" :model="info" :rules="rules" label-width="150px">
- <el-row>
- <el-col :span="12">
- <el-form-item label="表名称" prop="tableName">
- <el-input placeholder="请输入仓库名称" v-model="info.tableName" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="表描述" prop="tableComment">
- <el-input placeholder="请输入" v-model="info.tableComment" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="实体类名称" prop="className">
- <el-input placeholder="请输入" v-model="info.className" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="作者" prop="functionAuthor">
- <el-input placeholder="请输入" v-model="info.functionAuthor" />
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="备注" prop="remark">
- <el-input type="textarea" :rows="3" v-model="info.remark"></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
-</template>
-
-<script>
-export default {
- props: {
- info: {
- type: Object,
- default: null
- }
- },
- data() {
- return {
- rules: {
- tableName: [
- { required: true, message: "请输入表名称", trigger: "blur" }
- ],
- tableComment: [
- { required: true, message: "请输入表描述", trigger: "blur" }
- ],
- className: [
- { required: true, message: "请输入实体类名称", trigger: "blur" }
- ],
- functionAuthor: [
- { required: true, message: "请输入作者", trigger: "blur" }
- ]
- }
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/gen/editTable.vue b/ruoyi-ui/src/views/tool/gen/editTable.vue
deleted file mode 100644
index 07d4cf8..0000000
--- a/ruoyi-ui/src/views/tool/gen/editTable.vue
+++ /dev/null
@@ -1,230 +0,0 @@
-<template>
- <el-card>
- <el-tabs v-model="activeName">
- <el-tab-pane label="基本信息" name="basic">
- <basic-info-form ref="basicInfo" :info="info" />
- </el-tab-pane>
- <el-tab-pane label="字段信息" name="columnInfo">
- <el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
- <el-table-column label="序号" type="index" min-width="5%" class-name="allowDrag"/>
- <el-table-column label="字段列名" prop="columnName" min-width="10%" :show-overflow-tooltip="true" class-name="allowDrag"/>
- <el-table-column label="字段描述" min-width="10%">
- <template slot-scope="scope">
- <el-input v-model="scope.row.columnComment"></el-input>
- </template>
- </el-table-column>
- <el-table-column
- label="物理类型"
- prop="columnType"
- min-width="10%"
- :show-overflow-tooltip="true"
- />
- <el-table-column label="Java类型" min-width="11%">
- <template slot-scope="scope">
- <el-select v-model="scope.row.javaType">
- <el-option label="Long" value="Long" />
- <el-option label="String" value="String" />
- <el-option label="Integer" value="Integer" />
- <el-option label="Double" value="Double" />
- <el-option label="BigDecimal" value="BigDecimal" />
- <el-option label="Date" value="Date" />
- <el-option label="Boolean" value="Boolean" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="java属性" min-width="10%">
- <template slot-scope="scope">
- <el-input v-model="scope.row.javaField"></el-input>
- </template>
- </el-table-column>
-
- <el-table-column label="插入" min-width="5%">
- <template slot-scope="scope">
- <el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="编辑" min-width="5%">
- <template slot-scope="scope">
- <el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="列表" min-width="5%">
- <template slot-scope="scope">
- <el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="查询" min-width="5%">
- <template slot-scope="scope">
- <el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="查询方式" min-width="10%">
- <template slot-scope="scope">
- <el-select v-model="scope.row.queryType">
- <el-option label="=" value="EQ" />
- <el-option label="!=" value="NE" />
- <el-option label=">" value="GT" />
- <el-option label=">=" value="GTE" />
- <el-option label="<" value="LT" />
- <el-option label="<=" value="LTE" />
- <el-option label="LIKE" value="LIKE" />
- <el-option label="BETWEEN" value="BETWEEN" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="必填" min-width="5%">
- <template slot-scope="scope">
- <el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
- </template>
- </el-table-column>
- <el-table-column label="显示类型" min-width="12%">
- <template slot-scope="scope">
- <el-select v-model="scope.row.htmlType">
- <el-option label="文本框" value="input" />
- <el-option label="文本域" value="textarea" />
- <el-option label="下拉框" value="select" />
- <el-option label="单选框" value="radio" />
- <el-option label="复选框" value="checkbox" />
- <el-option label="日期控件" value="datetime" />
- <el-option label="图片上传" value="imageUpload" />
- <el-option label="文件上传" value="fileUpload" />
- <el-option label="富文本控件" value="editor" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="字典类型" min-width="12%">
- <template slot-scope="scope">
- <el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
- <el-option
- v-for="dict in dictOptions"
- :key="dict.dictType"
- :label="dict.dictName"
- :value="dict.dictType">
- <span style="float: left">{{ dict.dictName }}</span>
- <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
- </el-option>
- </el-select>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="生成信息" name="genInfo">
- <gen-info-form ref="genInfo" :info="info" :tables="tables" :menus="menus"/>
- </el-tab-pane>
- </el-tabs>
- <el-form label-width="100px">
- <el-form-item style="text-align: center;margin-left:-100px;margin-top:10px;">
- <el-button type="primary" @click="submitForm()">提交</el-button>
- <el-button @click="close()">返回</el-button>
- </el-form-item>
- </el-form>
- </el-card>
-</template>
-
-<script>
-import { getGenTable, updateGenTable } from "@/api/tool/gen"
-import { optionselect as getDictOptionselect } from "@/api/system/dict/type"
-import { listMenu as getMenuTreeselect } from "@/api/system/menu"
-import basicInfoForm from "./basicInfoForm"
-import genInfoForm from "./genInfoForm"
-import Sortable from 'sortablejs'
-
-export default {
- name: "GenEdit",
- components: {
- basicInfoForm,
- genInfoForm
- },
- data() {
- return {
- // 选中选项卡的 name
- activeName: "columnInfo",
- // 表格的高度
- tableHeight: document.documentElement.scrollHeight - 245 + "px",
- // 表信息
- tables: [],
- // 表列信息
- columns: [],
- // 字典信息
- dictOptions: [],
- // 菜单信息
- menus: [],
- // 表详细信息
- info: {}
- }
- },
- created() {
- const tableId = this.$route.params && this.$route.params.tableId
- if (tableId) {
- // 获取表详细信息
- getGenTable(tableId).then(res => {
- this.columns = res.data.rows
- this.info = res.data.info
- this.tables = res.data.tables
- })
- /** 查询字典下拉列表 */
- getDictOptionselect().then(response => {
- this.dictOptions = response.data
- })
- /** 查询菜单下拉列表 */
- getMenuTreeselect().then(response => {
- this.menus = this.handleTree(response.data, "menuId")
- })
- }
- },
- methods: {
- /** 提交按钮 */
- submitForm() {
- const basicForm = this.$refs.basicInfo.$refs.basicInfoForm
- const genForm = this.$refs.genInfo.$refs.genInfoForm
- Promise.all([basicForm, genForm].map(this.getFormPromise)).then(res => {
- const validateResult = res.every(item => !!item)
- if (validateResult) {
- const genTable = Object.assign({}, basicForm.model, genForm.model)
- genTable.columns = this.columns
- genTable.params = {
- genView: genTable.view ? '1' : '0',
- treeCode: genTable.treeCode,
- treeName: genTable.treeName,
- treeParentCode: genTable.treeParentCode,
- parentMenuId: genTable.parentMenuId
- }
- updateGenTable(genTable).then(res => {
- this.$modal.msgSuccess(res.msg)
- if (res.code === 200) {
- this.close()
- }
- })
- } else {
- this.$modal.msgError("表单校验未通过,请重新检查提交内容")
- }
- })
- },
- getFormPromise(form) {
- return new Promise(resolve => {
- form.validate(res => {
- resolve(res)
- })
- })
- },
- /** 关闭按钮 */
- close() {
- const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } }
- this.$tab.closeOpenPage(obj)
- }
- },
- mounted() {
- const el = this.$refs.dragTable.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0]
- const sortable = Sortable.create(el, {
- handle: ".allowDrag",
- onEnd: evt => {
- const targetRow = this.columns.splice(evt.oldIndex, 1)[0]
- this.columns.splice(evt.newIndex, 0, targetRow)
- for (let index in this.columns) {
- this.columns[index].sort = parseInt(index) + 1
- }
- }
- })
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
deleted file mode 100644
index 3c3015f..0000000
--- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
+++ /dev/null
@@ -1,336 +0,0 @@
-<template>
- <el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
- <el-row>
- <el-col :span="12">
- <el-form-item prop="tplCategory">
- <span slot="label">生成模板</span>
- <el-select v-model="info.tplCategory" @change="tplSelectChange">
- <el-option label="单表(增删改查)" value="crud" />
- <el-option label="树表(增删改查)" value="tree" />
- <el-option label="主子表(增删改查)" value="sub" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item prop="tplWebType">
- <span slot="label">前端类型</span>
- <el-select v-model="info.tplWebType">
- <el-option label="Vue2 Element UI 模版" value="element-ui" />
- <el-option label="Vue3 Element Plus 模版" value="element-plus" />
- <el-option label="Vue3 Element Plus TypeScript 模版" value="element-plus-typescript" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item prop="packageName">
- <span slot="label">
- 生成包路径
- <el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="info.packageName" />
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="moduleName">
- <span slot="label">
- 生成模块名
- <el-tooltip content="可理解为子系统名,例如 system" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="info.moduleName" />
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="businessName">
- <span slot="label">
- 生成业务名
- <el-tooltip content="可理解为功能英文名,例如 user" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="info.businessName" />
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="functionName">
- <span slot="label">
- 生成功能名
- <el-tooltip content="用作类描述,例如 用户" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="info.functionName" />
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="formColNum">
- <span slot="label">
- 表单布局
- <el-tooltip content="选择表单的栅格布局方式" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.formColNum">
- <el-option label="单列" :value="1" />
- <el-option label="双列" :value="2" />
- <el-option label="三列" :value="3" />
- </el-select>
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="genView">
- <span slot="label">扩展功能</span>
- <el-checkbox v-model="info.view">生成详情页</el-checkbox>
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item prop="genType">
- <span slot="label">
- 生成代码方式
- <el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
- <el-radio v-model="info.genType" label="1">自定义路径</el-radio>
- </el-form-item>
- </el-col>
-
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 上级菜单
- <el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <treeselect
- :append-to-body="true"
- v-model="info.parentMenuId"
- :options="menus"
- :normalizer="normalizer"
- :show-count="true"
- placeholder="请选择系统菜单"
- />
- </el-form-item>
- </el-col>
-
- <el-col :span="24" v-if="info.genType == '1'">
- <el-form-item prop="genPath">
- <span slot="label">
- 自定义路径
- <el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-input v-model="info.genPath">
- <el-dropdown slot="append">
- <el-button type="primary">
- 最近路径快速选择
- <i class="el-icon-arrow-down el-icon--right"></i>
- </el-button>
- <el-dropdown-menu slot="dropdown">
- <el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
- </el-dropdown-menu>
- </el-dropdown>
- </el-input>
- </el-form-item>
- </el-col>
- </el-row>
-
- <el-row v-show="info.tplCategory == 'tree'">
- <h4 class="form-header">其他信息</h4>
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 树编码字段
- <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.treeCode" placeholder="请选择">
- <el-option
- v-for="(column, index) in info.columns"
- :key="index"
- :label="column.columnName + ':' + column.columnComment"
- :value="column.columnName"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 树父编码字段
- <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.treeParentCode" placeholder="请选择">
- <el-option
- v-for="(column, index) in info.columns"
- :key="index"
- :label="column.columnName + ':' + column.columnComment"
- :value="column.columnName"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 树名称字段
- <el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.treeName" placeholder="请选择">
- <el-option
- v-for="(column, index) in info.columns"
- :key="index"
- :label="column.columnName + ':' + column.columnComment"
- :value="column.columnName"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row v-show="info.tplCategory == 'sub'">
- <h4 class="form-header">关联信息</h4>
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 关联子表的表名
- <el-tooltip content="关联子表的表名, 如:sys_user" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
- <el-option
- v-for="(table, index) in tables"
- :key="index"
- :label="table.tableName + ':' + table.tableComment"
- :value="table.tableName"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item>
- <span slot="label">
- 子表关联的外键名
- <el-tooltip content="子表关联的外键名, 如:user_id" placement="top">
- <i class="el-icon-question"></i>
- </el-tooltip>
- </span>
- <el-select v-model="info.subTableFkName" placeholder="请选择">
- <el-option
- v-for="(column, index) in subColumns"
- :key="index"
- :label="column.columnName + ':' + column.columnComment"
- :value="column.columnName"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
-</template>
-
-<script>
-import Treeselect from "@riophae/vue-treeselect"
-import "@riophae/vue-treeselect/dist/vue-treeselect.css"
-
-export default {
- components: { Treeselect },
- props: {
- info: {
- type: Object,
- default: null
- },
- tables: {
- type: Array,
- default: null
- },
- menus: {
- type: Array,
- default: []
- }
- },
- data() {
- return {
- subColumns: [],
- rules: {
- tplCategory: [
- { required: true, message: "请选择生成模板", trigger: "blur" }
- ],
- packageName: [
- { required: true, message: "请输入生成包路径", trigger: "blur" }
- ],
- moduleName: [
- { required: true, message: "请输入生成模块名", trigger: "blur" }
- ],
- businessName: [
- { required: true, message: "请输入生成业务名", trigger: "blur" }
- ],
- functionName: [
- { required: true, message: "请输入生成功能名", trigger: "blur" }
- ]
- }
- }
- },
- watch: {
- 'info.subTableName': function(val) {
- this.setSubTableColumns(val)
- },
- 'info.tplWebType': function(val) {
- if (val === '') {
- this.info.tplWebType = "element-ui"
- }
- }
- },
- methods: {
- /** 转换菜单数据结构 */
- normalizer(node) {
- if (node.children && !node.children.length) {
- delete node.children
- }
- return {
- id: node.menuId,
- label: node.menuName,
- children: node.children
- }
- },
- /** 选择子表名触发 */
- subSelectChange(value) {
- this.info.subTableFkName = ''
- },
- /** 选择生成模板触发 */
- tplSelectChange(value) {
- if(value !== 'sub') {
- this.info.subTableName = ''
- this.info.subTableFkName = ''
- }
- },
- /** 设置关联外键 */
- setSubTableColumns(value) {
- for (var item in this.tables) {
- const name = this.tables[item].tableName
- if (value === name) {
- this.subColumns = this.tables[item].columns
- break
- }
- }
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/src/views/tool/gen/importTable.vue b/ruoyi-ui/src/views/tool/gen/importTable.vue
deleted file mode 100644
index 89ff6ee..0000000
--- a/ruoyi-ui/src/views/tool/gen/importTable.vue
+++ /dev/null
@@ -1,120 +0,0 @@
-<template>
- <!-- 导入表 -->
- <el-dialog title="导入表" :visible.sync="visible" width="800px" top="5vh" append-to-body>
- <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
- <el-form-item label="表名称" prop="tableName">
- <el-input
- v-model="queryParams.tableName"
- placeholder="请输入表名称"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item label="表描述" prop="tableComment">
- <el-input
- v-model="queryParams.tableComment"
- placeholder="请输入表描述"
- clearable
- @keyup.enter.native="handleQuery"
- />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
- <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- <el-row>
- <el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
- <el-table-column type="selection" width="55"></el-table-column>
- <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
- <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
- <el-table-column prop="createTime" label="创建时间"></el-table-column>
- <el-table-column prop="updateTime" label="更新时间"></el-table-column>
- </el-table>
- <pagination
- v-show="total>0"
- :total="total"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getList"
- />
- </el-row>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="handleImportTable">确 定</el-button>
- <el-button @click="visible = false">取 消</el-button>
- </div>
- </el-dialog>
-</template>
-
-<script>
-import { listDbTable, importTable } from "@/api/tool/gen"
-export default {
- data() {
- return {
- // 遮罩层
- visible: false,
- // 选中数组值
- tables: [],
- // 总条数
- total: 0,
- // 表数据
- dbTableList: [],
- // 查询参数
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- tableName: undefined,
- tableComment: undefined
- }
- }
- },
- methods: {
- // 显示弹框
- show() {
- this.getList()
- this.visible = true
- },
- clickRow(row) {
- this.$refs.table.toggleRowSelection(row)
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.tables = selection.map(item => item.tableName)
- },
- // 查询表数据
- getList() {
- listDbTable(this.queryParams).then(res => {
- if (res.code === 200) {
- this.dbTableList = res.rows
- this.total = res.total
- }
- })
- },
- /** 搜索按钮操作 */
- handleQuery() {
- this.queryParams.pageNum = 1
- this.getList()
- },
- /** 重置按钮操作 */
- resetQuery() {
- this.resetForm("queryForm")
- this.handleQuery()
- },
- /** 导入按钮操作 */
- handleImportTable() {
- const tableNames = this.tables.join(",")
- if (tableNames == "") {
- this.$modal.msgError("请选择要导入的表")
- return
- }
- importTable({ tables: tableNames, tplWebType: 'element-ui' }).then(res => {
- this.$modal.msgSuccess(res.msg)
- if (res.code === 200) {
- this.visible = false
- this.$emit("ok")
- }
- })
- }
- }
-}
-</script>
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
deleted file mode 100644
index eb404f1..0000000
--- a/ruoyi-ui/vue.config.js
+++ /dev/null
@@ -1,129 +0,0 @@
-'use strict'
-const path = require('path')
-
-function resolve(dir) {
- return path.join(__dirname, dir)
-}
-
-const CompressionPlugin = require('compression-webpack-plugin')
-
-const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
-
-const port = process.env.port || process.env.npm_config_port || 80 // 端口
-
-// vue.config.js 配置说明
-//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
-// 这里只列一部分,具体配置参考文档
-module.exports = {
- // 部署生产环境和开发环境下的URL。
- // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
- // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
- publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
- // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
- outputDir: 'dist',
- // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
- assetsDir: 'static',
- // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
- productionSourceMap: false,
- transpileDependencies: ['quill'],
- // webpack-dev-server 相关配置
- devServer: {
- host: '0.0.0.0',
- port: port,
- open: true,
- proxy: {
- // detail: https://cli.vuejs.org/config/#devserver-proxy
- [process.env.VUE_APP_BASE_API]: {
- target: `http://localhost:18080`,
- changeOrigin: true,
- pathRewrite: {
- ['^' + process.env.VUE_APP_BASE_API]: ''
- }
- }
- },
- disableHostCheck: true
- },
- css: {
- loaderOptions: {
- sass: {
- sassOptions: { outputStyle: "expanded" }
- }
- }
- },
- configureWebpack: {
- name: name,
- resolve: {
- alias: {
- '@': resolve('src')
- }
- },
- plugins: [
- // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
- new CompressionPlugin({
- cache: false, // 不启用文件缓存
- test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式
- filename: '[path][base].gz[query]', // 压缩后的文件名
- algorithm: 'gzip', // 使用gzip压缩
- minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩
- deleteOriginalAssets: false // 压缩后删除原文件
- })
- ],
- },
- chainWebpack(config) {
- config.plugins.delete('preload') // TODO: need test
- config.plugins.delete('prefetch') // TODO: need test
-
- // set svg-sprite-loader
- config.module
- .rule('svg')
- .exclude.add(resolve('src/assets/icons'))
- .end()
- config.module
- .rule('icons')
- .test(/\.svg$/)
- .include.add(resolve('src/assets/icons'))
- .end()
- .use('svg-sprite-loader')
- .loader('svg-sprite-loader')
- .options({
- symbolId: 'icon-[name]'
- })
- .end()
-
- config.when(process.env.NODE_ENV !== 'development', config => {
- config
- .plugin('ScriptExtHtmlWebpackPlugin')
- .after('html')
- .use('script-ext-html-webpack-plugin', [{
- // `runtime` must same as runtimeChunk name. default is `runtime`
- inline: /runtime\..*\.js$/
- }])
- .end()
-
- config.optimization.splitChunks({
- chunks: 'all',
- cacheGroups: {
- libs: {
- name: 'chunk-libs',
- test: /[\\/]node_modules[\\/]/,
- priority: 10,
- chunks: 'initial' // only package third parties that are initially dependent
- },
- elementUI: {
- name: 'chunk-elementUI', // split elementUI into a single package
- test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
- priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
- },
- commons: {
- name: 'chunk-commons',
- test: resolve('src/components'), // can customize your rules
- minChunks: 3, // minimum common number
- priority: 5,
- reuseExistingChunk: true
- }
- }
- })
- config.optimization.runtimeChunk('single')
- })
- }
-}
diff --git a/ruoyi-visual/ruoyi-monitor/pom.xml b/ruoyi-visual/ruoyi-monitor/pom.xml
deleted file mode 100644
index 6d5283d..0000000
--- a/ruoyi-visual/ruoyi-monitor/pom.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>com.ruoyi</groupId>
- <artifactId>ruoyi-visual</artifactId>
- <version>3.6.8</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>ruoyi-visual-monitor</artifactId>
-
- <description>
- ruoyi-visual-monitor监控中心
- </description>
-
- <dependencies>
-
- <!-- SpringBoot Admin -->
- <dependency>
- <groupId>de.codecentric</groupId>
- <artifactId>spring-boot-admin-starter-server</artifactId>
- <version>${spring-boot-admin.version}</version>
- </dependency>
-
- <!-- SpringCloud Alibaba Nacos -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
- </dependency>
-
- <!-- SpringCloud Alibaba Nacos Config -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
- </dependency>
-
- <!-- SpringCloud Alibaba Sentinel -->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
-
- <!-- SpringBoot Web -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-webmvc</artifactId>
- </dependency>
-
- <!-- Spring Security -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- </dependencies>
-
- <build>
- <finalName>${project.artifactId}</finalName>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>repackage</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
-</project>
\ No newline at end of file
diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java
deleted file mode 100644
index 73628b3..0000000
--- a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/RuoYiMonitorApplication.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.ruoyi.modules.monitor;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import de.codecentric.boot.admin.server.config.EnableAdminServer;
-
-/**
- * 监控中心
- *
- * @author ruoyi
- */
-@EnableAdminServer
-@SpringBootApplication
-public class RuoYiMonitorApplication
-{
- public static void main(String[] args)
- {
- SpringApplication.run(RuoYiMonitorApplication.class, args);
- System.out.println("(♥◠‿◠)ノ゙ 监控中心启动成功 ლ(´ڡ`ლ)゙ \n" +
- " .-------. ____ __ \n" +
- " | _ _ \\ \\ \\ / / \n" +
- " | ( ' ) | \\ _. / ' \n" +
- " |(_ o _) / _( )_ .' \n" +
- " | (_,_).' __ ___(_ o _)' \n" +
- " | |\\ \\ | || |(_,_)' \n" +
- " | | \\ `' /| `-' / \n" +
- " | | \\ / \\ / \n" +
- " ''-' `'-' `-..-' ");
- }
-}
diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java b/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java
deleted file mode 100644
index 5ac13f7..0000000
--- a/ruoyi-visual/ruoyi-monitor/src/main/java/com/ruoyi/modules/monitor/config/WebSecurityConfigurer.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.ruoyi.modules.monitor.config;
-
-import de.codecentric.boot.admin.server.config.AdminServerProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.Customizer;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
-import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
-import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
-
-/**
- * 监控权限配置
- *
- * @author ruoyi
- */
-@EnableWebSecurity
-@Configuration
-public class WebSecurityConfigurer
-{
- private final String adminContextPath;
-
- public WebSecurityConfigurer(AdminServerProperties adminServerProperties)
- {
- this.adminContextPath = adminServerProperties.getContextPath();
- }
-
- @Bean
- public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
- {
- SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
- successHandler.setTargetUrlParameter("redirectTo");
- successHandler.setDefaultTargetUrl(adminContextPath + "/");
-
- return httpSecurity.headers((header) -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
- .authorizeHttpRequests(
- (authorize) -> authorize
- .requestMatchers(adminContextPath + "/assets/**",
- adminContextPath + "/login",
- adminContextPath + "/actuator/**",
- adminContextPath + "/instances/**")
- .permitAll()
- .anyRequest()
- .authenticated())
- .formLogin((formLogin) -> formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler))
- .logout((logout) -> logout.logoutUrl(adminContextPath + "/logout"))
- .httpBasic(Customizer.withDefaults())
- .csrf(AbstractHttpConfigurer::disable)
- .build();
- }
-}
diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt b/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt
deleted file mode 100644
index c0fbab1..0000000
--- a/ruoyi-visual/ruoyi-monitor/src/main/resources/banner.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Spring Boot Version: ${spring-boot.version}
-Spring Application Name: ${spring.application.name}
- _ _ _
- (_) (_)| |
- _ __ _ _ ___ _ _ _ ______ _ __ ___ ___ _ __ _ | |_ ___ _ __
-| '__|| | | | / _ \ | | | || ||______|| '_ ` _ \ / _ \ | '_ \ | || __| / _ \ | '__|
-| | | |_| || (_) || |_| || | | | | | | || (_) || | | || || |_ | (_) || |
-|_| \__,_| \___/ \__, ||_| |_| |_| |_| \___/ |_| |_||_| \__| \___/ |_|
- __/ |
- |___/
\ No newline at end of file
diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml b/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml
deleted file mode 100644
index a281d33..0000000
--- a/ruoyi-visual/ruoyi-monitor/src/main/resources/bootstrap.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# Tomcat
-server:
- port: 9100
-
-# Spring
-spring:
- application:
- # 应用名称
- name: ruoyi-monitor
- profiles:
- # 环境配置
- active: dev
- cloud:
- nacos:
- discovery:
- # 服务注册地址
- server-addr: 127.0.0.1:8848
- config:
- # 配置中心地址
- server-addr: 127.0.0.1:8848
- config:
- # 配置文件格式
- file-extension: yml
- import:
- - nacos:application-${spring.profiles.active}.${spring.config.file-extension}
- - nacos:${spring.application.name}-${spring.profiles.active}.${spring.config.file-extension}
diff --git a/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml b/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml
deleted file mode 100644
index ab95c68..0000000
--- a/ruoyi-visual/ruoyi-monitor/src/main/resources/logback.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration scan="true" scanPeriod="60 seconds" debug="false">
- <!-- 日志存放路径 -->
- <property name="log.path" value="logs/ruoyi-visual-monitor" />
- <!-- 日志输出格式 -->
- <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
-
- <!-- 控制台输出 -->
- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- </appender>
-
- <!-- 系统日志输出 -->
- <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/info.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>INFO</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>${log.path}/error.log</file>
- <!-- 循环政策:基于时间创建日志文件 -->
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 日志文件名格式 -->
- <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 日志最大的历史 60天 -->
- <maxHistory>60</maxHistory>
- </rollingPolicy>
- <encoder>
- <pattern>${log.pattern}</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <!-- 过滤的级别 -->
- <level>ERROR</level>
- <!-- 匹配时的操作:接收(记录) -->
- <onMatch>ACCEPT</onMatch>
- <!-- 不匹配时的操作:拒绝(不记录) -->
- <onMismatch>DENY</onMismatch>
- </filter>
- </appender>
-
- <!-- 系统模块日志级别控制 -->
- <logger name="com.ruoyi" level="info" />
- <!-- Spring日志级别控制 -->
- <logger name="org.springframework" level="warn" />
-
- <root level="info">
- <appender-ref ref="console" />
- </root>
-
- <!--系统操作日志-->
- <root level="info">
- <appender-ref ref="file_info" />
- <appender-ref ref="file_error" />
- </root>
-</configuration>
\ No newline at end of file
diff --git a/sgd-gateway/src/main/resources/banner.txt b/sgd-gateway/src/main/resources/banner.txt
new file mode 100644
index 0000000..ceced29
--- /dev/null
+++ b/sgd-gateway/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ _
+ (_) | |
+ _ __ _ _ ___ _ _ _ ______ __ _ __ _ | |_ ___ __ __ __ _ _ _
+| '__|| | | | / _ \ | | | || ||______| / _` | / _` || __| / _ \\ \ /\ / / / _` || | | |
+| | | |_| || (_) || |_| || | | (_| || (_| || |_ | __/ \ V V / | (_| || |_| |
+|_| \__,_| \___/ \__, ||_| \__, | \__,_| \__| \___| \_/\_/ \__,_| \__, |
+ __/ | __/ | __/ |
+ |___/ |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-gateway/src/main/resources/logback.xml b/sgd-gateway/src/main/resources/logback.xml
similarity index 100%
rename from ruoyi-gateway/src/main/resources/logback.xml
rename to sgd-gateway/src/main/resources/logback.xml
diff --git a/sgd-modules/sgd-file/src/main/resources/banner.txt b/sgd-modules/sgd-file/src/main/resources/banner.txt
new file mode 100644
index 0000000..27cacb9
--- /dev/null
+++ b/sgd-modules/sgd-file/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ __ _ _
+ (_) / _|(_)| |
+ _ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
+| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
+| | | |_| || (_) || |_| || | | | | || || __/
+|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
+ __/ |
+ |___/
\ No newline at end of file
diff --git a/sgd-modules/sgd-file/src/main/resources/logback.xml b/sgd-modules/sgd-file/src/main/resources/logback.xml
new file mode 100644
index 0000000..ed6c17d
--- /dev/null
+++ b/sgd-modules/sgd-file/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 日志存放路径 -->
+ <property name="log.path" value="logs/ruoyi-file" />
+ <!-- 日志输出格式 -->
+ <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+ <!-- 控制台输出 -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ </appender>
+
+ <!-- 系统日志输出 -->
+ <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/info.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>INFO</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/error.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>ERROR</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 系统模块日志级别控制 -->
+ <logger name="com.ruoyi" level="info" />
+ <!-- Spring日志级别控制 -->
+ <logger name="org.springframework" level="warn" />
+
+ <root level="info">
+ <appender-ref ref="console" />
+ </root>
+
+ <!--系统操作日志-->
+ <root level="info">
+ <appender-ref ref="file_info" />
+ <appender-ref ref="file_error" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/sgd-modules/sgd-gen/src/main/resources/banner.txt b/sgd-modules/sgd-gen/src/main/resources/banner.txt
new file mode 100644
index 0000000..05f528c
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _
+ (_)
+ _ __ _ _ ___ _ _ _ ______ __ _ ___ _ __
+| '__|| | | | / _ \ | | | || ||______| / _` | / _ \| '_ \
+| | | |_| || (_) || |_| || | | (_| || __/| | | |
+|_| \__,_| \___/ \__, ||_| \__, | \___||_| |_|
+ __/ | __/ |
+ |___/ |___/
\ No newline at end of file
diff --git a/sgd-modules/sgd-gen/src/main/resources/logback.xml b/sgd-modules/sgd-gen/src/main/resources/logback.xml
new file mode 100644
index 0000000..c301bb4
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 日志存放路径 -->
+ <property name="log.path" value="logs/ruoyi-gen" />
+ <!-- 日志输出格式 -->
+ <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+ <!-- 控制台输出 -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ </appender>
+
+ <!-- 系统日志输出 -->
+ <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/info.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>INFO</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/error.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>ERROR</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 系统模块日志级别控制 -->
+ <logger name="com.ruoyi" level="info" />
+ <!-- Spring日志级别控制 -->
+ <logger name="org.springframework" level="warn" />
+
+ <root level="info">
+ <appender-ref ref="console" />
+ </root>
+
+ <!--系统操作日志-->
+ <root level="info">
+ <appender-ref ref="file_info" />
+ <appender-ref ref="file_error" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/java/controller.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 0000000..ab9831c
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,115 @@
+package ${packageName}.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.log.annotation.Log;
+import com.ruoyi.common.log.enums.BusinessType;
+import com.sgd.common.security.annotation.RequiresPermissions;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+import com.ruoyi.common.core.web.controller.BaseController;
+import com.ruoyi.common.core.web.domain.AjaxResult;
+import com.ruoyi.common.core.utils.poi.ExcelUtil;
+#if($table.crud || $table.sub)
+import com.ruoyi.common.core.web.page.TableDataInfo;
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}Controller
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RestController
+@RequestMapping("/${businessName}")
+public class ${ClassName}Controller extends BaseController
+{
+ @Autowired
+ private I${ClassName}Service ${className}Service;
+
+ /**
+ * 查询${functionName}列表
+ */
+ @RequiresPermissions("${permissionPrefix}:list")
+ @GetMapping("/list")
+#if($table.crud || $table.sub)
+ public TableDataInfo list(${ClassName} ${className})
+ {
+ startPage();
+ List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+ return getDataTable(list);
+ }
+#elseif($table.tree)
+ public AjaxResult list(${ClassName} ${className})
+ {
+ List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+ return success(list);
+ }
+#end
+
+ /**
+ * 导出${functionName}列表
+ */
+ @RequiresPermissions("${permissionPrefix}:export")
+ @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, ${ClassName} ${className})
+ {
+ List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+ ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
+ util.exportExcel(response, list, "${functionName}数据");
+ }
+
+ /**
+ * 获取${functionName}详细信息
+ */
+ @RequiresPermissions("${permissionPrefix}:query")
+ @GetMapping(value = "/{${pkColumn.javaField}}")
+ public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
+ {
+ return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
+ }
+
+ /**
+ * 新增${functionName}
+ */
+ @RequiresPermissions("${permissionPrefix}:add")
+ @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody ${ClassName} ${className})
+ {
+ return toAjax(${className}Service.insert${ClassName}(${className}));
+ }
+
+ /**
+ * 修改${functionName}
+ */
+ @RequiresPermissions("${permissionPrefix}:edit")
+ @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody ${ClassName} ${className})
+ {
+ return toAjax(${className}Service.update${ClassName}(${className}));
+ }
+
+ /**
+ * 删除${functionName}
+ */
+ @RequiresPermissions("${permissionPrefix}:remove")
+ @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{${pkColumn.javaField}s}")
+ public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
+ {
+ return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
+ }
+}
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/java/domain.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/domain.java.vm
new file mode 100644
index 0000000..1142830
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/java/domain.java.vm
@@ -0,0 +1,105 @@
+package ${packageName}.domain;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.core.annotation.Excel;
+#if($table.crud || $table.sub)
+import com.ruoyi.common.core.web.domain.BaseEntity;
+#elseif($table.tree)
+import com.ruoyi.common.core.web.domain.TreeEntity;
+#end
+
+/**
+ * ${functionName}对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($table.crud || $table.sub)
+#set($Entity="BaseEntity")
+#elseif($table.tree)
+#set($Entity="TreeEntity")
+#end
+public class ${ClassName} extends ${Entity}
+{
+ private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+ /** $column.columnComment */
+#if($column.list)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($parentheseIndex != -1)
+ @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+#elseif($column.javaType == 'Date')
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
+#else
+ @Excel(name = "${comment}")
+#end
+#end
+ private $column.javaType $column.javaField;
+
+#end
+#end
+#if($table.sub)
+ /** $table.subTable.functionName信息 */
+ private List<${subClassName}> ${subclassName}List;
+
+#end
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+ public void set${AttrName}($column.javaType $column.javaField)
+ {
+ this.$column.javaField = $column.javaField;
+ }
+
+ public $column.javaType get${AttrName}()
+ {
+ return $column.javaField;
+ }
+
+#end
+#end
+#if($table.sub)
+ public List<${subClassName}> get${subClassName}List()
+ {
+ return ${subclassName}List;
+ }
+
+ public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
+ {
+ this.${subclassName}List = ${subclassName}List;
+ }
+
+#end
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+#foreach ($column in $columns)
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+ .append("${column.javaField}", get${AttrName}())
+#end
+#if($table.sub)
+ .append("${subclassName}List", get${subClassName}List())
+#end
+ .toString();
+ }
+}
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/java/mapper.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 0000000..7e7d7c2
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,91 @@
+package ${packageName}.mapper;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+#if($table.sub)
+import ${packageName}.domain.${subClassName};
+#end
+
+/**
+ * ${functionName}Mapper接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper
+{
+ /**
+ * 查询${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return ${functionName}
+ */
+ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+ /**
+ * 查询${functionName}列表
+ *
+ * @param ${className} ${functionName}
+ * @return ${functionName}集合
+ */
+ public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+ /**
+ * 新增${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int insert${ClassName}(${ClassName} ${className});
+
+ /**
+ * 修改${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int update${ClassName}(${ClassName} ${className});
+
+ /**
+ * 删除${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+ /**
+ * 批量删除${functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+#if($table.sub)
+
+ /**
+ * 批量删除${subTable.functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+
+ /**
+ * 批量新增${subTable.functionName}
+ *
+ * @param ${subclassName}List ${subTable.functionName}列表
+ * @return 结果
+ */
+ public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
+
+
+ /**
+ * 通过${functionName}主键删除${subTable.functionName}信息
+ *
+ * @param ${pkColumn.javaField} ${functionName}ID
+ * @return 结果
+ */
+ public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
+#end
+}
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/java/service.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..264882b
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,61 @@
+package ${packageName}.service;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+
+/**
+ * ${functionName}Service接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service
+{
+ /**
+ * 查询${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return ${functionName}
+ */
+ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+ /**
+ * 查询${functionName}列表
+ *
+ * @param ${className} ${functionName}
+ * @return ${functionName}集合
+ */
+ public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+ /**
+ * 新增${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int insert${ClassName}(${ClassName} ${className});
+
+ /**
+ * 修改${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int update${ClassName}(${ClassName} ${className});
+
+ /**
+ * 批量删除${functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+
+ /**
+ * 删除${functionName}信息
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+}
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/java/serviceImpl.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..d590b92
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,169 @@
+package ${packageName}.service.impl;
+
+import java.util.List;
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
+import com.ruoyi.common.core.utils.DateUtils;
+#break
+#end
+#end
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+#if($table.sub)
+import java.util.ArrayList;
+import com.ruoyi.common.core.utils.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
+import ${packageName}.domain.${subClassName};
+#end
+import ${packageName}.mapper.${ClassName}Mapper;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+
+/**
+ * ${functionName}Service业务层处理
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service
+{
+ @Autowired
+ private ${ClassName}Mapper ${className}Mapper;
+
+ /**
+ * 查询${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return ${functionName}
+ */
+ @Override
+ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+ {
+ return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+ }
+
+ /**
+ * 查询${functionName}列表
+ *
+ * @param ${className} ${functionName}
+ * @return ${functionName}
+ */
+ @Override
+ public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
+ {
+ return ${className}Mapper.select${ClassName}List(${className});
+ }
+
+ /**
+ * 新增${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int insert${ClassName}(${ClassName} ${className})
+ {
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime')
+ ${className}.setCreateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+ int rows = ${className}Mapper.insert${ClassName}(${className});
+ insert${subClassName}(${className});
+ return rows;
+#else
+ return ${className}Mapper.insert${ClassName}(${className});
+#end
+ }
+
+ /**
+ * 修改${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int update${ClassName}(${ClassName} ${className})
+ {
+#foreach ($column in $columns)
+#if($column.javaField == 'updateTime')
+ ${className}.setUpdateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
+ insert${subClassName}(${className});
+#end
+ return ${className}Mapper.update${ClassName}(${className});
+ }
+
+ /**
+ * 批量删除${functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
+ {
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
+#end
+ return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
+ }
+
+ /**
+ * 删除${functionName}信息
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+ {
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
+#end
+ return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+ }
+#if($table.sub)
+
+ /**
+ * 新增${subTable.functionName}信息
+ *
+ * @param ${className} ${functionName}对象
+ */
+ public void insert${subClassName}(${ClassName} ${className})
+ {
+ List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
+ ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
+ if (StringUtils.isNotNull(${subclassName}List))
+ {
+ List<${subClassName}> list = new ArrayList<${subClassName}>();
+ for (${subClassName} ${subclassName} : ${subclassName}List)
+ {
+ ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
+ list.add(${subclassName});
+ }
+ if (list.size() > 0)
+ {
+ ${className}Mapper.batch${subClassName}(list);
+ }
+ }
+ }
+#end
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm b/sgd-modules/sgd-gen/src/main/resources/vm/java/sub-domain.java.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/sub-domain.java.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/java/sub-domain.java.vm
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/js/api.js.vm b/sgd-modules/sgd-gen/src/main/resources/vm/js/api.js.vm
new file mode 100644
index 0000000..9295524
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/js/api.js.vm
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询${functionName}列表
+export function list${BusinessName}(query) {
+ return request({
+ url: '/${moduleName}/${businessName}/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询${functionName}详细
+export function get${BusinessName}(${pkColumn.javaField}) {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'get'
+ })
+}
+
+// 新增${functionName}
+export function add${BusinessName}(data) {
+ return request({
+ url: '/${moduleName}/${businessName}',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改${functionName}
+export function update${BusinessName}(data) {
+ return request({
+ url: '/${moduleName}/${businessName}',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除${functionName}
+export function del${BusinessName}(${pkColumn.javaField}) {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'delete'
+ })
+}
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/sql/sql.vm b/sgd-modules/sgd-gen/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 0000000..0575583
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/sql/sql.vm
@@ -0,0 +1,22 @@
+-- 菜单 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
+
+-- 按钮父菜单ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, '');
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm b/sgd-modules/sgd-gen/src/main/resources/vm/ts/api.ts.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/ts/api.ts.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/index.ts.vm b/sgd-modules/sgd-gen/src/main/resources/vm/ts/index.ts.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/index.ts.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/ts/index.ts.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/type.ts.vm b/sgd-modules/sgd-gen/src/main/resources/vm/ts/type.ts.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/type.ts.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/ts/type.ts.vm
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/vue/index-tree.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 0000000..7a2d0e9
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +1,565 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-input
+ v-model="queryParams.${column.javaField}"
+ placeholder="请输入${comment}"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+ <el-option
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+ <el-option label="请选择字典生成" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-date-picker clearable
+ v-model="queryParams.${column.javaField}"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="选择${comment}">
+ </el-date-picker>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ <el-form-item label="${comment}">
+ <el-date-picker
+ v-model="daterange${AttrName}"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+#end
+#end
+#end
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['${permissionPrefix}:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="info"
+ plain
+ icon="el-icon-sort"
+ size="mini"
+ @click="toggleExpandAll"
+ >展开/折叠</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table
+ v-if="refreshTable"
+ v-loading="loading"
+ :data="${businessName}List"
+ row-key="${treeCode}"
+ :default-expand-all="isExpandAll"
+ :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+ >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+ <template slot-scope="scope">
+ <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+ <el-table-column label="${comment}" align="center" prop="${javaField}">
+ <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+ <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+ <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+ <el-table-column label="${comment}" prop="${javaField}" />
+#else
+ <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+#if($genView)
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleViewData(scope.row)"
+ v-hasPermi="['${permissionPrefix}:query']"
+ >详情</el-button>
+#end
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['${permissionPrefix}:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-plus"
+ @click="handleAdd(scope.row)"
+ v-hasPermi="['${permissionPrefix}:add']"
+ >新增</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['${permissionPrefix}:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+#if($genView)
+ <!-- ${functionName}详情抽屉 -->
+ <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
+ <!-- 添加或修改${functionName}对话框 -->
+#if($table.formColNum == 2)
+#set($dialogWidth = "800px")
+#elseif($table.formColNum == 3)
+#set($dialogWidth = "1100px")
+#else
+#set($dialogWidth = "500px")
+#end
+ <el-dialog :title="title" :visible.sync="open" width="${dialogWidth}" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-row>
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${treeParentCode}">
+ <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="请选择${comment}" />
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "input")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "imageUpload")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <image-upload v-model="form.${field}"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "fileUpload")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <file-upload v-model="form.${field}"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "editor")
+ <el-col :span="24">
+ <el-form-item label="${comment}">
+ <editor v-model="form.${field}" :min-height="192"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "select" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="请选择${comment}">
+ <el-option
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :value="parseInt(dict.value)"
+#else
+ :value="dict.value"
+#end
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "select" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="请选择${comment}">
+ <el-option label="请选择字典生成" value="" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.value">
+ {{dict.label}}
+ </el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "checkbox" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox>请选择字典生成</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :label="parseInt(dict.value)"
+#else
+ :label="dict.value"
+#end
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "radio" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio label="1">请选择字典生成</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "datetime")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-date-picker clearable
+ v-model="form.${field}"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="选择${comment}">
+ </el-date-picker>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "textarea")
+ <el-col :span="24">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+ </el-form-item>
+ </el-col>
+#end
+#end
+#end
+#end
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+
+export default {
+ name: "${BusinessName}",
+#if(${dicts} != '')
+ dicts: [${dicts}],
+#end
+ components: {
+#if($genView)
+ ${BusinessName}ViewDrawer,
+#end
+ Treeselect
+ },
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 显示搜索条件
+ showSearch: true,
+ // ${functionName}表格数据
+ ${businessName}List: [],
+ // ${functionName}树选项
+ ${businessName}Options: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 是否展开,默认全部展开
+ isExpandAll: true,
+ // 重新渲染表格状态
+ refreshTable: true,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ // $comment时间范围
+ daterange${AttrName}: [],
+#end
+#end
+ // 查询参数
+ queryParams: {
+#foreach ($column in $columns)
+#if($column.query)
+ $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+ $column.javaField: [
+ { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+ ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询${functionName}列表 */
+ getList() {
+ this.loading = true
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ this.queryParams.params = {}
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+ this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
+ this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
+ }
+#end
+#end
+ list${BusinessName}(this.queryParams).then(response => {
+ this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
+ this.loading = false
+ })
+ },
+ /** 转换${functionName}数据结构 */
+ normalizer(node) {
+ if (node.children && !node.children.length) {
+ delete node.children
+ }
+ return {
+ id: node.${treeCode},
+ label: node.${treeName},
+ children: node.children
+ }
+ },
+ /** 查询${functionName}下拉树结构 */
+ getTreeselect() {
+ list${BusinessName}().then(response => {
+ this.${businessName}Options = []
+ const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
+ data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
+ this.${businessName}Options.push(data)
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+ $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ this.daterange${AttrName} = []
+#end
+#end
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd(row) {
+ this.reset()
+ this.getTreeselect()
+ if (row != null && row.${treeCode}) {
+ this.form.${treeParentCode} = row.${treeCode}
+ } else {
+ this.form.${treeParentCode} = 0
+ }
+ this.open = true
+ this.title = "添加${functionName}"
+ },
+ /** 展开/折叠操作 */
+ toggleExpandAll() {
+ this.refreshTable = false
+ this.isExpandAll = !this.isExpandAll
+ this.$nextTick(() => {
+ this.refreshTable = true
+ })
+ },
+#if($genView)
+ /** 详情按钮操作 */
+ handleViewData(row) {
+ this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+ },
+#end
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ this.getTreeselect()
+ if (row != null) {
+ this.form.${treeParentCode} = row.${treeParentCode}
+ }
+ get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+ this.form = response.data
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ this.form.$column.javaField = this.form.${column.javaField}.split(",")
+#end
+#end
+ this.open = true
+ this.title = "修改${functionName}"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.#[[$]]#refs["form"].validate(valid => {
+ if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ this.form.$column.javaField = this.form.${column.javaField}.join(",")
+#end
+#end
+ if (this.form.${pkColumn.javaField} != null) {
+ update${BusinessName}(this.form).then(response => {
+ this.#[[$modal]]#.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ add${BusinessName}(this.form).then(response => {
+ this.#[[$modal]]#.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
+ return del${BusinessName}(row.${pkColumn.javaField})
+ }).then(() => {
+ this.getList()
+ this.#[[$modal]]#.msgSuccess("删除成功")
+ }).catch(() => {})
+ }
+ }
+}
+</script>
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/vue/index.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 0000000..876dae3
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +1,660 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-input
+ v-model="queryParams.${column.javaField}"
+ placeholder="请输入${comment}"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+ <el-option
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+ <el-option label="请选择字典生成" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-date-picker clearable
+ v-model="queryParams.${column.javaField}"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="请选择${comment}">
+ </el-date-picker>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ <el-form-item label="${comment}">
+ <el-date-picker
+ v-model="daterange${AttrName}"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+#end
+#end
+#end
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['${permissionPrefix}:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['${permissionPrefix}:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['${permissionPrefix}:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['${permissionPrefix}:export']"
+ >导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+ <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#elseif($column.list && $column.htmlType == "datetime")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+ <template slot-scope="scope">
+ <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+ <el-table-column label="${comment}" align="center" prop="${javaField}">
+ <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+ <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+ <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $javaField)
+ <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+#if($genView)
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleViewData(scope.row)"
+ v-hasPermi="['${permissionPrefix}:query']"
+ >详情</el-button>
+#end
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['${permissionPrefix}:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['${permissionPrefix}:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+#if($genView)
+ <!-- ${functionName}详情抽屉 -->
+ <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
+ <!-- 添加或修改${functionName}对话框 -->
+#if($table.formColNum == 2)
+#set($dialogWidth = "800px")
+#elseif($table.formColNum == 3)
+#set($dialogWidth = "1100px")
+#else
+#set($dialogWidth = "500px")
+#end
+ <el-dialog :title="title" :visible.sync="open" width="${dialogWidth}" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-row>
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "imageUpload")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <image-upload v-model="form.${field}"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "fileUpload")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <file-upload v-model="form.${field}"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "editor")
+ <el-col :span="24">
+ <el-form-item label="${comment}">
+ <editor v-model="form.${field}" :min-height="192"/>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "select" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="请选择${comment}">
+ <el-option
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :value="parseInt(dict.value)"
+#else
+ :value="dict.value"
+#end
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "select" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="请选择${comment}">
+ <el-option label="请选择字典生成" value="" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+ :label="dict.value">
+ {{dict.label}}
+ </el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "checkbox" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox>请选择字典生成</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio
+ v-for="dict in dict.type.${dictType}"
+ :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :label="parseInt(dict.value)"
+#else
+ :label="dict.value"
+#end
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "radio" && $dictType)
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio label="1">请选择字典生成</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "datetime")
+ <el-col :span="${colSpan}">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-date-picker clearable
+ v-model="form.${field}"
+ type="date"
+ value-format="yyyy-MM-dd"
+ placeholder="请选择${comment}">
+ </el-date-picker>
+ </el-form-item>
+ </el-col>
+#elseif($column.htmlType == "textarea")
+ <el-col :span="24">
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+ </el-form-item>
+ </el-col>
+#end
+#end
+#end
+#end
+ </el-row>
+#if($table.sub)
+ <el-divider content-position="center">${subTable.functionName}信息</el-divider>
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
+ </el-col>
+ </el-row>
+ <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
+ <el-table-column type="selection" width="50" align="center" />
+ <el-table-column label="序号" align="center" prop="index" width="50"/>
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && $column.htmlType == "input")
+ <el-table-column label="$comment" prop="${javaField}" width="150">
+ <template slot-scope="scope">
+ <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+ <el-table-column label="$comment" prop="${javaField}" width="240">
+ <template slot-scope="scope">
+ <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
+ </template>
+ </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+ <el-table-column label="$comment" prop="${javaField}" width="150">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+ <el-option
+ v-for="dict in dict.type.$column.dictType"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ ></el-option>
+ </el-select>
+ </template>
+ </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+ <el-table-column label="$comment" prop="${javaField}" width="150">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+ <el-option label="请选择字典生成" value="" />
+ </el-select>
+ </template>
+ </el-table-column>
+#end
+#end
+ </el-table>
+#end
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
+
+export default {
+ name: "${BusinessName}",
+#if($genView)
+ components: { ${BusinessName}ViewDrawer },
+#end
+#if(${dicts} != '')
+ dicts: [${dicts}],
+#end
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+#if($table.sub)
+ // 子表选中数据
+ checked${subClassName}: [],
+#end
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // ${functionName}表格数据
+ ${businessName}List: [],
+#if($table.sub)
+ // ${subTable.functionName}表格数据
+ ${subclassName}List: [],
+#end
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ // $comment时间范围
+ daterange${AttrName}: [],
+#end
+#end
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+#foreach ($column in $columns)
+#if($column.query)
+ $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+ $column.javaField: [
+ { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+ ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询${functionName}列表 */
+ getList() {
+ this.loading = true
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ this.queryParams.params = {}
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+ this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
+ this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
+ }
+#end
+#end
+ list${BusinessName}(this.queryParams).then(response => {
+ this.${businessName}List = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+ $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+ }
+#if($table.sub)
+ this.${subclassName}List = []
+#end
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ this.daterange${AttrName} = []
+#end
+#end
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.${pkColumn.javaField})
+ this.single = selection.length !== 1
+ this.multiple = !selection.length
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加${functionName}"
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
+ get${BusinessName}(${pkColumn.javaField}).then(response => {
+ this.form = response.data
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ this.form.$column.javaField = this.form.${column.javaField}.split(",")
+#end
+#end
+#if($table.sub)
+ this.${subclassName}List = response.data.${subclassName}List
+#end
+ this.open = true
+ this.title = "修改${functionName}"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.#[[$]]#refs["form"].validate(valid => {
+ if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ this.form.$column.javaField = this.form.${column.javaField}.join(",")
+#end
+#end
+#if($table.sub)
+ this.form.${subclassName}List = this.${subclassName}List
+#end
+ if (this.form.${pkColumn.javaField} != null) {
+ update${BusinessName}(this.form).then(response => {
+ this.#[[$modal]]#.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ add${BusinessName}(this.form).then(response => {
+ this.#[[$modal]]#.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
+ this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
+ return del${BusinessName}(${pkColumn.javaField}s)
+ }).then(() => {
+ this.getList()
+ this.#[[$modal]]#.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+#if($table.sub)
+ /** ${subTable.functionName}序号 */
+ row${subClassName}Index({ row, rowIndex }) {
+ row.index = rowIndex + 1
+ },
+ /** ${subTable.functionName}添加按钮操作 */
+ handleAdd${subClassName}() {
+ let obj = {}
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+ obj.$column.javaField = ""
+#end
+#end
+ this.${subclassName}List.push(obj)
+ },
+ /** ${subTable.functionName}删除按钮操作 */
+ handleDelete${subClassName}() {
+ if (this.checked${subClassName}.length == 0) {
+ this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
+ } else {
+ const ${subclassName}List = this.${subclassName}List
+ const checked${subClassName} = this.checked${subClassName}
+ this.${subclassName}List = ${subclassName}List.filter(function(item) {
+ return checked${subClassName}.indexOf(item.index) == -1
+ })
+ }
+ },
+ /** 复选框选中数据 */
+ handle${subClassName}SelectionChange(selection) {
+ this.checked${subClassName} = selection.map(item => item.index)
+ },
+#end
+#if($genView)
+ /** 详情按钮操作 */
+ handleViewData(row) {
+ this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+ },
+#end
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('${moduleName}/${businessName}/export', {
+ ...this.queryParams
+ }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+ }
+ }
+}
+</script>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/index.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/view.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/view.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/view.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3/view.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/index.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/view.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/view.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/view.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/v3ts/view.vue.vm
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/view.vue.vm b/sgd-modules/sgd-gen/src/main/resources/vm/vue/view.vue.vm
similarity index 100%
rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/view.vue.vm
rename to sgd-modules/sgd-gen/src/main/resources/vm/vue/view.vue.vm
diff --git a/sgd-modules/sgd-gen/src/main/resources/vm/xml/mapper.xml.vm b/sgd-modules/sgd-gen/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 0000000..456755b
--- /dev/null
+++ b/sgd-modules/sgd-gen/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
+
+ <resultMap type="${ClassName}" id="${ClassName}Result">
+#foreach ($column in $columns)
+ <result property="${column.javaField}" column="${column.columnName}" />
+#end
+ </resultMap>
+#if($table.sub)
+
+ <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
+ <collection property="${subclassName}List" ofType="${subClassName}" column="${pkColumn.columnName}" select="select${subClassName}List" />
+ </resultMap>
+
+ <resultMap type="${subClassName}" id="${subClassName}Result">
+#foreach ($column in $subTable.columns)
+ <result property="${column.javaField}" column="${column.columnName}" />
+#end
+ </resultMap>
+#end
+
+ <sql id="select${ClassName}Vo">
+ select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
+ </sql>
+
+ <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
+ <include refid="select${ClassName}Vo"/>
+ <where>
+#foreach($column in $columns)
+#set($queryType=$column.queryType)
+#set($javaField=$column.javaField)
+#set($javaType=$column.javaType)
+#set($columnName=$column.columnName)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#if($column.query)
+#if($column.queryType == "EQ")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if>
+#elseif($queryType == "NE")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if>
+#elseif($queryType == "GT")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName > #{$javaField}</if>
+#elseif($queryType == "GTE")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName >= #{$javaField}</if>
+#elseif($queryType == "LT")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName < #{$javaField}</if>
+#elseif($queryType == "LTE")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName <= #{$javaField}</if>
+#elseif($queryType == "LIKE")
+ <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if>
+#elseif($queryType == "BETWEEN")
+ <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>
+#end
+#end
+#end
+ </where>
+ </select>
+
+ <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
+#if($table.crud || $table.tree)
+ <include refid="select${ClassName}Vo"/>
+ where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+#elseif($table.sub)
+ select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end
+ from ${tableName}
+ where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+#end
+ </select>
+#if($table.sub)
+
+ <select id="select${subClassName}List" resultMap="${subClassName}Result">
+ select#foreach ($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end
+ from ${subTableName}
+ where ${subTableFkName} = #{${subTableFkName}}
+ </select>
+#end
+
+ <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
+ insert into ${tableName}
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+ <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if>
+#end
+#end
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+ <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if>
+#end
+#end
+ </trim>
+ </insert>
+
+ <update id="update${ClassName}" parameterType="${ClassName}">
+ update ${tableName}
+ <trim prefix="SET" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName)
+ <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if>
+#end
+#end
+ </trim>
+ where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+ </update>
+
+ <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
+ delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+ </delete>
+
+ <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
+ delete from ${tableName} where ${pkColumn.columnName} in
+ <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
+ #{${pkColumn.javaField}}
+ </foreach>
+ </delete>
+#if($table.sub)
+
+ <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
+ delete from ${subTableName} where ${subTableFkName} in
+ <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
+ #{${subTableFkclassName}}
+ </foreach>
+ </delete>
+
+ <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}">
+ delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
+ </delete>
+
+ <insert id="batch${subClassName}">
+ insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
+ <foreach item="item" index="index" collection="list" separator=",">
+ (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
+ </foreach>
+ </insert>
+#end
+</mapper>
\ No newline at end of file
diff --git a/sgd-modules/sgd-job/src/main/resources/banner.txt b/sgd-modules/sgd-job/src/main/resources/banner.txt
new file mode 100644
index 0000000..0b9cd42
--- /dev/null
+++ b/sgd-modules/sgd-job/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ _ _
+ (_) (_) | |
+ _ __ _ _ ___ _ _ _ ______ _ ___ | |__
+| '__|| | | | / _ \ | | | || ||______| | | / _ \ | '_ \
+| | | |_| || (_) || |_| || | | || (_) || |_) |
+|_| \__,_| \___/ \__, ||_| | | \___/ |_.__/
+ __/ | _/ |
+ |___/ |__/
\ No newline at end of file
diff --git a/sgd-modules/sgd-job/src/main/resources/logback.xml b/sgd-modules/sgd-job/src/main/resources/logback.xml
new file mode 100644
index 0000000..44e4ff2
--- /dev/null
+++ b/sgd-modules/sgd-job/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 日志存放路径 -->
+ <property name="log.path" value="logs/ruoyi-job" />
+ <!-- 日志输出格式 -->
+ <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+ <!-- 控制台输出 -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ </appender>
+
+ <!-- 系统日志输出 -->
+ <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/info.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>INFO</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/error.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>ERROR</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 系统模块日志级别控制 -->
+ <logger name="com.ruoyi" level="info" />
+ <!-- Spring日志级别控制 -->
+ <logger name="org.springframework" level="warn" />
+
+ <root level="info">
+ <appender-ref ref="console" />
+ </root>
+
+ <!--系统操作日志-->
+ <root level="info">
+ <appender-ref ref="file_info" />
+ <appender-ref ref="file_error" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/sgd-modules/sgd-system/src/main/resources/banner.txt b/sgd-modules/sgd-system/src/main/resources/banner.txt
new file mode 100644
index 0000000..fbd45f5
--- /dev/null
+++ b/sgd-modules/sgd-system/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ _
+ (_) | |
+ _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___
+| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \
+| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | |
+|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_|
+ __/ | __/ |
+ |___/ |___/
\ No newline at end of file
diff --git a/sgd-modules/sgd-system/src/main/resources/logback.xml b/sgd-modules/sgd-system/src/main/resources/logback.xml
new file mode 100644
index 0000000..0154e28
--- /dev/null
+++ b/sgd-modules/sgd-system/src/main/resources/logback.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 日志存放路径 -->
+ <property name="log.path" value="logs/ruoyi-system" />
+ <!-- 日志输出格式 -->
+ <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+ <!-- 控制台输出 -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ </appender>
+
+ <!-- 系统日志输出 -->
+ <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/info.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>INFO</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${log.path}/error.log</file>
+ <!-- 循环政策:基于时间创建日志文件 -->
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <!-- 日志文件名格式 -->
+ <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
+ <!-- 日志最大的历史 60天 -->
+ <maxHistory>60</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>${log.pattern}</pattern>
+ </encoder>
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
+ <!-- 过滤的级别 -->
+ <level>ERROR</level>
+ <!-- 匹配时的操作:接收(记录) -->
+ <onMatch>ACCEPT</onMatch>
+ <!-- 不匹配时的操作:拒绝(不记录) -->
+ <onMismatch>DENY</onMismatch>
+ </filter>
+ </appender>
+
+ <!-- 系统模块日志级别控制 -->
+ <logger name="com.ruoyi" level="info" />
+ <!-- Spring日志级别控制 -->
+ <logger name="org.springframework" level="warn" />
+
+ <root level="info">
+ <appender-ref ref="console" />
+ </root>
+
+ <!--系统操作日志-->
+ <root level="info">
+ <appender-ref ref="file_info" />
+ <appender-ref ref="file_error" />
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/sgd-ui/.editorconfig b/sgd-ui/.editorconfig
new file mode 100644
index 0000000..7034f9b
--- /dev/null
+++ b/sgd-ui/.editorconfig
@@ -0,0 +1,22 @@
+# 告诉EditorConfig插件,这是根文件,不用继续往上查找
+root = true
+
+# 匹配全部文件
+[*]
+# 设置字符集
+charset = utf-8
+# 缩进风格,可选space、tab
+indent_style = space
+# 缩进的空格数
+indent_size = 2
+# 结尾换行符,可选lf、cr、crlf
+end_of_line = lf
+# 在文件结尾插入新行
+insert_final_newline = true
+# 删除一行中的前后空格
+trim_trailing_whitespace = true
+
+# 匹配md结尾的文件
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/sgd-ui/.env.development b/sgd-ui/.env.development
new file mode 100644
index 0000000..302ecd1
--- /dev/null
+++ b/sgd-ui/.env.development
@@ -0,0 +1,11 @@
+# 页面标题
+VUE_APP_TITLE = 若依管理系统
+
+# 开发环境配置
+ENV = 'development'
+
+# 若依管理系统/开发环境
+VUE_APP_BASE_API = '/dev-api'
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/sgd-ui/.env.production b/sgd-ui/.env.production
new file mode 100644
index 0000000..b4893b0
--- /dev/null
+++ b/sgd-ui/.env.production
@@ -0,0 +1,8 @@
+# 页面标题
+VUE_APP_TITLE = 若依管理系统
+
+# 生产环境配置
+ENV = 'production'
+
+# 若依管理系统/生产环境
+VUE_APP_BASE_API = '/prod-api'
diff --git a/sgd-ui/.env.staging b/sgd-ui/.env.staging
new file mode 100644
index 0000000..209b64e
--- /dev/null
+++ b/sgd-ui/.env.staging
@@ -0,0 +1,12 @@
+# 页面标题
+VUE_APP_TITLE = 若依管理系统
+
+BABEL_ENV = production
+
+NODE_ENV = production
+
+# 测试环境配置
+ENV = 'staging'
+
+# 若依管理系统/测试环境
+VUE_APP_BASE_API = '/stage-api'
diff --git a/sgd-ui/.gitignore b/sgd-ui/.gitignore
new file mode 100644
index 0000000..78a752d
--- /dev/null
+++ b/sgd-ui/.gitignore
@@ -0,0 +1,23 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
diff --git a/sgd-ui/README.md b/sgd-ui/README.md
new file mode 100644
index 0000000..00c0ab8
--- /dev/null
+++ b/sgd-ui/README.md
@@ -0,0 +1,30 @@
+## 开发
+
+```bash
+# 克隆项目
+git clone https://gitee.com/y_project/RuoYi-Vue
+
+# 进入项目目录
+cd ruoyi-ui
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npmmirror.com
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 http://localhost:80
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+```
\ No newline at end of file
diff --git a/sgd-ui/babel.config.js b/sgd-ui/babel.config.js
new file mode 100644
index 0000000..c8267b2
--- /dev/null
+++ b/sgd-ui/babel.config.js
@@ -0,0 +1,13 @@
+module.exports = {
+ presets: [
+ // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+ '@vue/cli-plugin-babel/preset'
+ ],
+ 'env': {
+ 'development': {
+ // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+ // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+ 'plugins': ['dynamic-import-node']
+ }
+ }
+}
\ No newline at end of file
diff --git a/sgd-ui/bin/build.bat b/sgd-ui/bin/build.bat
new file mode 100644
index 0000000..dda590d
--- /dev/null
+++ b/sgd-ui/bin/build.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [��Ϣ] ���Web���̣�����dist�ļ���
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run build:prod
+
+pause
\ No newline at end of file
diff --git a/sgd-ui/bin/package.bat b/sgd-ui/bin/package.bat
new file mode 100644
index 0000000..0e5bc0f
--- /dev/null
+++ b/sgd-ui/bin/package.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [��Ϣ] ��װWeb���̣�����node_modules�ļ���
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npmmirror.com
+
+pause
\ No newline at end of file
diff --git a/sgd-ui/bin/run-web.bat b/sgd-ui/bin/run-web.bat
new file mode 100644
index 0000000..d30deae
--- /dev/null
+++ b/sgd-ui/bin/run-web.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ�� Vue CLI �������� Web ���̡�
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
+pause
\ No newline at end of file
diff --git a/sgd-ui/build/index.js b/sgd-ui/build/index.js
new file mode 100644
index 0000000..0c57de2
--- /dev/null
+++ b/sgd-ui/build/index.js
@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+ const report = rawArgv.includes('--report')
+
+ run(`vue-cli-service build ${args}`)
+
+ const port = 9526
+ const publicPath = config.publicPath
+
+ var connect = require('connect')
+ var serveStatic = require('serve-static')
+ const app = connect()
+
+ app.use(
+ publicPath,
+ serveStatic('./dist', {
+ index: ['index.html', '/']
+ })
+ )
+
+ app.listen(port, function () {
+ console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
+ if (report) {
+ console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
+ }
+
+ })
+} else {
+ run(`vue-cli-service build ${args}`)
+}
diff --git a/sgd-ui/package.json b/sgd-ui/package.json
new file mode 100644
index 0000000..6847c76
--- /dev/null
+++ b/sgd-ui/package.json
@@ -0,0 +1,71 @@
+{
+ "name": "ruoyi",
+ "version": "3.6.8",
+ "description": "若依管理系统",
+ "author": "若依",
+ "license": "MIT",
+ "scripts": {
+ "dev": "vue-cli-service serve",
+ "build:prod": "vue-cli-service build",
+ "build:stage": "vue-cli-service build --mode staging",
+ "preview": "node build/index.js --preview"
+ },
+ "keywords": [
+ "vue",
+ "admin",
+ "dashboard",
+ "element-ui",
+ "boilerplate",
+ "admin-template",
+ "management-system"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://gitee.com/y_project/RuoYi-Cloud.git"
+ },
+ "dependencies": {
+ "@riophae/vue-treeselect": "0.4.0",
+ "axios": "0.30.3",
+ "clipboard": "2.0.8",
+ "core-js": "3.37.1",
+ "echarts": "5.4.0",
+ "element-ui": "2.15.14",
+ "file-saver": "2.0.5",
+ "fuse.js": "6.4.3",
+ "highlight.js": "9.18.5",
+ "js-beautify": "1.13.0",
+ "js-cookie": "3.0.1",
+ "jsencrypt": "3.0.0-rc.1",
+ "nprogress": "0.2.0",
+ "quill": "2.0.2",
+ "screenfull": "5.0.2",
+ "sortablejs": "1.10.2",
+ "vue": "2.6.12",
+ "vue-count-to": "1.0.13",
+ "vue-cropper": "0.5.5",
+ "vue-router": "3.4.9",
+ "vuedraggable": "2.24.3",
+ "vuex": "3.6.0"
+ },
+ "devDependencies": {
+ "@vue/cli-plugin-babel": "4.4.6",
+ "@vue/cli-service": "4.4.6",
+ "babel-plugin-dynamic-import-node": "2.3.3",
+ "chalk": "4.1.0",
+ "compression-webpack-plugin": "6.1.2",
+ "connect": "3.6.6",
+ "sass": "1.32.13",
+ "sass-loader": "10.1.1",
+ "script-ext-html-webpack-plugin": "2.1.5",
+ "svg-sprite-loader": "5.1.1",
+ "vue-template-compiler": "2.6.12"
+ },
+ "engines": {
+ "node": ">=8.9",
+ "npm": ">= 3.0.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/ruoyi-ui/public/favicon.ico b/sgd-ui/public/favicon.ico
similarity index 100%
rename from ruoyi-ui/public/favicon.ico
rename to sgd-ui/public/favicon.ico
Binary files differ
diff --git a/sgd-ui/public/html/ie.html b/sgd-ui/public/html/ie.html
new file mode 100644
index 0000000..052ffcd
--- /dev/null
+++ b/sgd-ui/public/html/ie.html
@@ -0,0 +1,46 @@
+
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+ <meta charset="UTF-8" />
+ <title>请升级您的浏览器</title>
+ <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
+ <meta name="renderer" content="webkit">
+ <base target="_blank" />
+ <style type="text/css">
+ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}
+ a{text-decoration:none;color:#0072c6;}a:hover{text-decoration:none;color:#004d8c;}
+ body{width:960px;margin:0 auto;padding:10px;font-size:14px;line-height:24px;color:#454545;font-family:'Microsoft YaHei UI','Microsoft YaHei',DengXian,SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif;overflow-y:scroll}
+ h1{font-size:40px;line-height:80px;font-weight:100;margin-bottom:10px;}
+ h2{font-size:20px;line-height:25px;font-weight:100;margin:10px 0;}
+ em{color:red}
+ p{margin-bottom:10px;}
+ hr{margin:20px 0;border:0;border-top:1px solid #dadada}
+ span{display:block;font-size:12px;line-height:12px;}
+ .clean{clear:both;}
+ .browser{padding:10px 10px;}
+ .browser li{width:auto;padding:0 80px;margin-top:30px;height:34px;line-height:22px;float:left;list-style:none;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAADMCAYAAAAWCXEwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAC7ESURBVHja5Lx5dFRV1rBfgHwYRQQVtB26ZWhtabtfeUGxGxFbUGZF8RMHGkVbRkekVYiKisicVhE0gEwBokgDAhEMMSSQkAECwcxkrlRSqVTqJqnxzs/vj5t7qUyAvr9e37fWV2vtleSm6p6n9t5nn733OVU2RaUaEP5PiqJSbeMXPBTA5/Xhzk9Vnd9vo3HFx21E2LYJX9IRgh6npvyCe9uaqS4K4C3IpXHFx9S99CTuJ8Z0KLVjRlA7ZgTuJ8ZgXxmJL+kIlwAkXBQk6HFq9pWRVA8fSvXwodYgdS892a6EA1UNvouqwXdR99KTeAtyfz2IL+kI1cOHYh9wqwVwKWJqpXbMCOv19gG3Imzb1JF2OgZxfr/NukH4jcNVfyEAE8IU+4BbKet1PfaVke3BtA/i/H6b8aIBt7a4mWmaC0nr55vmqRp8F5V33Mm5LhHtwbQF8SUdsSDCb1I1+K42g1xIWgOYYh9wK+e6RCBs29QxSIWus37aJM51iWjx4so77mwD1d5AHQ1eecedlN9yuyVlva6nrNf14Q7cEmRn4W7u3T2E9ME3UX7L7W1uZg5Weced1s3sA2613ql5LXzQjuRclwjcT4wxTXQeRHC7GLdnHPeensiCVwa3e0PznZk3EbZtwluQa0kofz8NcVNxr++Ce30XnNuv61Bcu7viXt8Fvyu7JYipjfGHxzD+8Bh2j+7fAiZcC+Y0zPDIbCyD6DyV6DyVeDcIQR2C39J4oieNJ3oSOnkVcnZ35Ozu6MVdDHF0N6S4C43OqJYg/0ydzb27hzDx0FjuPT2R+asfa6OVsl7X40s6QoWus/CQk6fWZPHChhxe3lbMCxtyrN9TyxSQSwidvMoC0XK6tRGybPjSRmOuNUKVo4Zxe8YxIu4+Jh4ay/jDY7j39MQWWjnXJYLGFR9Toes8tSaLiavTrIHDxfxfapkCwW8hy9YuhCmhk1fR1FRnaCS1NM4yy8RDYy2tjIkZRXq/HtYsCnqc2sJDTkYsTrU00J6YkEJQR7M/eEGY0MmrcOenqjZA2JmyzTJLuJiOe65LBHUvPUmGR2bE4lQmrk7jqTVZHcrE1WkMWpRIdJ4KnpUXBCHLRl3e16EWIOEaMU00/vAY9na/gsYVH/NdgYe+8w9bMBeSQYsSWXjICcFvL2ga+dhlFwcJ10rjio/ZklprgbSWiavTWvzdd/5hXt5W/OtATC201sq9u4eQ+PVijmSW0nf+YQYtSmTQosR2gUYsTmXQokT6zj9saeRCpmkJ0hxD2gOZeGgsI+Lu45+ps7FXlFmDmDDtSd/5h+k7/zCpZQpa9cwOQciyIR+77LyzFhXlMyZmFOP2jLP8orVWRsTdR2ppHFtSa+k6ZZM1WHvSdcomwyxySceayO4OWTY88TdirygzUkWf18eL2//RQiutYcwYE/Q4tagDOUQ8uo6uUzbRZ3qMJV2nbCLi0XU8tSbrolNXzu6OfOyylgEN4NOkaO5acw/j9ozr0ET37h5imehIZimPL91rAfSZHsOQBfuISS7E7vaTETeX0MmrOoQInbwK+dhlNKWsahni0zPSuGvNPW1M1BrI1NrOwt0WkCn2ijJSS+MYt2ccuQk3oxd36RCi8URPY+HLT1VbgGiSzPsx71laCddMe2Yygf6ZOtuScXvG0XfJn/n8YL+LQnjibyQ34WZ8Xl/bfKSoKL+FVi4EYwKZcu/uIQzaPoExMaPQcrq1ADFX33AI1+6u1OV9HVI6ShU/TYqm75I/dwjTHtDEQ2MZt2ccg7ZPaGGScIDWEBlxc42UoSMQ00StYdoDCgcbtH0Cbx+8p40ZTIBwiFM7RmB3+y+exZvT2YRpDdR6ZoVrw1xRWwN44m/Euf06A6Ki7NLrmnDNmH7TEdSg7RP4/GA/yLK1GdwEKNzSk1M7RlDlqPl1JefOlG2MXTGmXaAxMaMsB/XE34h4tH+7ANlrB7T2iV8OAlDlqOH9mPcsIBPKlF3R16Ad7GwlxoVberYAKCrKv1ghfmkg5sPldLIzZVsLqLErxpC9doAlp3aMICNurlGyVpRdSAu/HqS1Q58rd1JUlI87P1UtKsrHXlGG3e1HCOoov+x2wiX3RxT+o49L1IgutXxVUCfDIxNfLraQDI+M3e3/NdCXbhohqBNfLrIsVzZqmoT6dmXG0SBLTrmJLxd/CVRLECXcDGFaSC1TmHE0yKg4B0P2uxiy38WoOAePHaptAfHYoVqG7HcxcGc5o+IcfFfgsbQUPoYoSa213BbE78oGucTSwpJTbobFFjNgbQHdvi6g8/Z6Om+vZ8h+VxsQE7T/97UMWFvA+Og0UvIryfDIZBQ4CeXvt8a5IAhAY/RImlJWUaHrPHaolhuXFXHN+8e58qNcbomq5P6t3xG973WePLzPgnnsUG0LiP7f1zJwZzk3LisyctfSOFxOJ4lfLzYToQubxu/KpmpWBFWzInguOokrP8ql7/zDRMxLpFfUabasHwlZNnITbmbgznI6b6+3Bu7/fa2lrW5fF9Ar6jQD1hYwLLaYx5fupdi+EiGok748koa4qa010xKkKWUV2UM7kd6vB7tH9yfpnUFkLzQiZOGWnmgHO9N4oie9ok5bA4YPbkqvqNNc8/5xIuYl8tSaLOLLRXambENXF+PxNJD0ziAanVHhYaEliH1lJD/1iqD0qSsIzu2M/N550TZ3QjvYmS3rR1qDtwdhgpgwnabGMj46zRjQsxJdXYw7P1X1pY0GuaRjkMKxPah5qxuV8y6nct7l1LzVDfdyo6miHexM+ou9mblwKfdv/Y77t37HNe8fbwMQDhIxL5FOU2PZklqLJjUYdU7wWxBuN+ricBAF0KQG6pcNovZpw0fCQao/MEBcu7tSOLYHjnu7EZzbmeDczqyfNokrP8ptMXi4XDnzAJ0n72TIgn1oUoMB4VlpgIjj24I0payi9KkrqHj+Ssth2wM5c38f8p68D2nbHKRtc3h86d42A/eZHsOVMw9Y0nXKJmxDvyS1NA70z8Gz0qh5hNvbzpr6ZYMofzyiBUwLkOVdjfR/eVcao0dSl/d1aHx0GhHzEi0TXDnzAJ2mxtJpaixdp2yypM/0GLrcs5D3Y94ztNDsK7qjuxmzDBBz2rYGqZoVQc1b3dr4yfppk+g8eWeLd91aAxGPrqPbyKV0G7mUiEfXMWdz+nmQ0Jsgn1AbT/SkMXrkeZC6vK9DpU9d0S5I5bzLqf6gq6UV7WBn5q9+zDJBuEQ8us4SE6LLPQvpcs9CjmSW4ndlo1XPNBxWLiE34WbSX+wNapEBEsrfT/njERSO7WGBmDA1b3Wj9KkrSO/Xg1WjBjJl/CT+8sQ8a0BT/eGDhwN0uWchXe94ia07YkE+oSLc3gxyQt2yfiSrRg0E+YRqgRSO7UHh2B4UT7ragqmcdznFk67mp14ROO7txpTxk7AN/bLFgN1GLsU29EvrejiACdG59xQjKgu3GzVP9UwIvcmCVwYb102NmBHVBDFNVDUrgjP39yF98E0E5xox5Dcj5lsDhwOYQObg4dK59xR2RV8D4njEo/0NIEd3dkVfgy9t9HkfMTWSO6pXG63kjupF8aSrqXj+SoJzO1M573KmjJ/Eb0bM5y9PzGPBK4Mp3GKUEFvWj+Q3I+a3AOjcewp/eWKesUQ0T1mz2att7oSU9+F5EE2SqXvpSbKHdrIGNmHCoapmRVgh33LezZ3QNncyloGDnVnwyuA2IFvWj0Q+dplREzu6Wy0r9/KubVvg9pWRpPfrwZn7+1haMSHCxdSM/J4RWWufjiC9Xw/m9PgtN9w0uo1JbrhpNI0njAXTrAIbT/TEvb4LjdEj2641vqQjpPfrQfrgm1qYKHxKlz51BbmjerFj4G2WtAYwtWDKglcGG2ZoXrldu43AWDUrAmnbnLaRVZMayHvyPn7qZThoa38pfeoKap+OIDi3M6tGDeSGm0a3GTT82g03jeaGm0bj3H4d8rHLrN0I93LDpDsG3kb68si2a425hfZTrwjSB9/UBiZcM+YM6ghoyvhJpL/Ym+yFhknc67tYQVF+z3gjc3r8Fuf32zpOFTMeHXpRGDNfMYF2j+7PqlEDWTVqIOkv9rZ8SNvcCff6LlTOu9yK1Okv9mZOj9+S8ehQNKmBDhs17vxU9adeES1gwoHKH49oFyhcwhfKynmXWzOu4vkryR7aieyhnQjl7+84QzNNJGzbxN7uV1gw7WmntYZaLw2mmNdrn44ge2gnztzfx9od7zBnDa9t0pdHtgsTDhRustaaCndwEyLj0aG481PVS9r3FSUJj6eBrConMZHvnodpntrh2gkHCgcLl/TBN7G3+xXGLMlIo0LXjU7ixeoaUZIQ3C7OlTtJya8kJvJddgy8DctvWgGFaylcHPd2Y2/3K5jT47esGjWQrTtiyapy4nI6jUrvUmpfUytFRfmkZ6SxdUcs66dNYsfA2ywNtQBrJeb/dgy8jZjId/kx4YgF4fP6Ln1L3uyhhWvnSGYpOw6lEBP5LuunTWLDAw+x4YGHrAi74YGHWD9tEuunTSIm8l227ohtAyBK0i8/pNDagTVJxuf1YXf7OVfuJKvKMF16RhrpGWkcySwlJb+SrCqn1awRgjqaJP9nO0b/Zxo1v+ahS0ZqKJ9QCX5rJMyhN42aRj6h/udB5BKjiAp+i64uNrJ2M0Vs3rUiy4aU92G42X49iCYZDZjUMoX4ctFIcILfGgVU6E0LwEyCxKP98aWNxpc2GvFof+RjlyHlfdjxWnOxh93tJya5kIWHnDx2qJbnopP4NCmaYvtKC0LL6WYkQps70RA3laaUVbjzU1V7RRn2ijK8BbkWUJsM7VIAog7k8MyuPKtD1AJA/9zQQpYN9/oubFk/kpkLl7J4a0KbtrdZa/vSRrfMWS8GcSSzlGd25TH5VIjptTpR9T5SS+OMsrHZD3RHd7SDnTm1YwSzY2KsTtL46DSei07iSGZpm/tKeR8a5gnf0+vI8zfE5zAstpjptTrvifBJeeZ5LTQDkGXDtbsr0fte59mjDmaWaUyv1ZlZpvH3XJlRcQ6Grj5OTHJhy/t7VhrpwMVAog7kMCrOwcs+nZWaccak2L7S0oLpC6d2jGDJiUyWN8E6FVZqsLwJ5ruwYO5O9jFoUSIb4nPOT+/gtxf3kZjkQobFFreAaHRGGZoQbm+hhWd25fHsUQevHilgbo7bAmoNM2S/i6Grj3Mks9Tolcgn1Hb39MzHuXInw9edZrJd4z3xPISuLrYgCrf0ZOuOWKLzVFLLFDIKmlfr5EJmHMxhfoWvDczkUyELxl5RduFUUZNkIvdm8+BpkZd9eocQPyYc6XDnocpRQ+TebObmuFmptdTK5FMhBqwt4K1vMi4cWTMKnIyKczDZrvFJeWaHEBdrbVc5aphxMIflTR1rJaPA2TFI1IEc7k72tZwdYRCLtyZc6h4MMcmF7WrlwRSRAWsLiNyb3T6Iz+vjmV15jIpztIHwxN/I7JgY4svFS47CHk9DG62Y5hm4s5zx0Wntb0CnlikMiy3m06ToFpFSO9iZnSnbeGZXHkcyS8kocF6SHMksZc7m9AuaJyW/si3IltRaZsfEGNM09KZVs2bEzWV5EyzLlXn1SEG7MuNgTruy5JS73dlzd7IvPMi1BIlJLmRnyjbLJFawar7ZHi5NdrSS9jRyd7KPXlGnzQDXyjSlcYY2mk1SuKUnS05kslI7f9M9/HKgdaoh74nn/cR02NV7M9t2A9A/t/qf2uZOvB/zHvNdxk3Mm0bV+36VzK8wxHTWVutPmEbkE6q1hjQ3/yefCvGeeB7k1SPGlLsUeeubDOtnezJnczpvfZPBuXJnGEjzAqSri9FyulG4pSf3b/3OCvErNQNmxsEczpU70ST5kuWXJc9yiZXemQ3du5N9TK/VedmnW1qZm+M+v3r+gpTS42nA42nA5XRa4vE0hFd8zSDBb63cInvtAAYtSuTuZB+T7ZoFYy7tz+zK6+igQZtHRoGTyL3ZLab4M7vyGB+dxpAF+1i8NaEliLmWyNndsa+MZPi60/T/vpaJhTKT7ZqllZWaoZW3vsnA42m4IMS5cifPRScxN8fNeyK87NOZXqszsdDITa55/3i4dgVb0OPUTG2IR/vjzk9Vt6Qau5R3J/uYWCi3MJEJM2dzOkcyS80Q3WKrPia50IIIX2cmnwrxYIpIr6jTPBed1Mo0apFgpv0NcVMR3C5ESWLO5nS6fV3Ag6fFdmHmV/iYcTCHyL3ZRB3IsSRybzbP7MpjfoWvXYj+39cyZME+c7aEgTQ36smy0RA31dostrv9DF193IIJ9xcTxgSam+O2xAQwg9fMMo2JhTIPnjYgBi1KbC+RPq8REyR8iT9X7rRgWptpvssYLBwqHGB6rc7fc2ULYsh+F4MWJbLjUErH09c8ytcaxNTMCxtyGLC2oIUDT6/VO5TJdkMLJsTAneUMWpTYNotvE0eaj3rKxy6zun2t69mdKdt4fOley4lN35ls11pIOIC51D8XnWQu9xcGUQCteibyscuM5n31TKNqD5fm1H9DfA7PRScxdPVxhsUWMyy22Dq4MGS/i2GxxQxfd9oC2HEopb1WVcdtCU2Sqcv7OmTWpGbRLOV9SCh/P0GPUwvPvDIKnMQkFxK5N5s5m9N5LjqJ56KTeOubDFbvzSQlv7LN1P5FxzZ8Xp918v8SWk5WsWStLbr0a5oLHRdY/+GjPP8vtq7+0yCiJOHz+hDcLlxOJ2bzxeV0Irhdlk/9x0B8Xh9VjhoEt6s5rZTaFU1qQHC7qHLU/PpZ05EGqhw1uJxO0CVESSIlv5KoAznM2ZxufTJgzuZ0og7kkJJfaR1mcjmdVDlqflkc6ahSs1eUWdMzJrmQQYsSrYMJNy4raiHmYQWzD2IC2SvKLpa/dAzi8/qsc6cZBU6GLNjHlTMPcEtUJVMSdd45qRGdp7KxDOvDPu+c1JhxNMgtUZVcOfMAQxbss0K7vaLsQqbq+GCtCbEhPodOU2O58qNcZhwNsrMK4t0Xlp1VMONokCs/yqXT1FgrE7sATPvbJK0hblxWxDsnNWugvc7zcqFry3JlbomqbANzSdskpk9kFDjpOmWTpQnzne6sMgbbWWWYY8kpN0tOuYnOU1v8z9TcOyc1blxWRNcpmwwz6dLFjxr7vD5rY+eO13YSMS+Rh/co1iAby4wBluXKLDnl5rsCD1lVxk7FdwUelpxysyxXbvHcjWUwYb9CxLxE7nhtp7X10spELUHMMiHqQA6dJ+9k8KYaJh1u6ZRLTrnZklrb+hS3lURtSa1lySm39fyNZTAlUWfwpho6T95p1rqtS5LzICapJsmWNkbEBpiSqLMs1/gY3DsntfAuT4tDlkrYtci92bxzUmNjmaG9KYk6I2IDbbTStsBqjhma1EBKfiVdp2xiwNoCHt6jMOmwxjsnNev46KWUkaIksfCQk2W5Mu+c1Jh0WGPCfoUBawvoOmWT1d4Miy3nQczIuXpvJp2mxjJ4Uw0T9hsg09KM6fhcdBIxyYWXJM9FJzHjaJBpaTDpsAEzeFMNnabGGhVec+RtA1LlqAFd4vGley0Q8wZTEnWmpWGdWX3sUC3PHnW0K+b/n0qoZ1oaTEszfCQc5PGle0GXwv0k7PxI87S9EMjMMo35rvMdILPDbErrzlA4iOmw4SBh0/iXgUxLg8mnQvw9V2Zmmdau/D1XtpoxpiYe3qPw8B6FW6IqreOCvwpkWhqMinMwaFEi46PTfrFMXG38HLr6OHe8ttPykXZNYzrr4q0JdJoay4C1BS2cdfCmGuZsTrd6Hv/T5ozZJ7no9L1xWZE1fU0bD193unXx3GESFZNcyIb4nDazaUN8Dh6PkTy1O307CmgT9itM2K9YWnkuOumi26wTV6dZR43NXOXKj3LpPHknEY+us0DaDWiWnwCr92bSdcomBm+q4eE9ShsThTXh2jRn5mxOZ/CmmjYzZkRsgE5TY40Q33bhu/iiF66VcJjh604TuTfbUnnk3myGrzttQZgzZtJhzQrvfabHWGNccNELnz2tfSUcJjxADVhbwIC1BdYsMyOp+fyH9yhWGnAks/TS0gDTV4qK8q2NxU5TY7klqrIFTDhQ6+gZ/hwzdoSbpKgo/9LPj5hnR8yUwEwVw810MRkRG7BSRXPpLyrKv/RUsT2YI5mlLZLnEbEBK1q2lhGxASt5vuO1nZY5ioryL5TJX7icENwuioryjV1rr4+oAzkMWbDvouXEkAX7iDqQg8/rQ5MaLgZxaQWWJslWSWkWWBkFzl9UYP2PvgjFPNrj8/osM/2YcIQfE46QnpFmfL7K7SLocWpBj1Mz6+D0jLQWzzPb3b/6aI8SVnCbvXTTVOZxno6kqCjfKlPNUH4pIP9XPGz/N319UFnrf2iKLGi6LmggqCBoIOi6JuiqIqCrgqIrgqyrgoYu6JpiiK4LKgigCpquCCEdQdVVAU0VdP2iMGW29tplmtbcQNQ1QEXXNDQdQGsWHZBbvdQsKkTQfaiaBJrc/PyLPpQ2zqqbL9U10GV0TUbTZUCyQAoaJPaVinx5RmbVKZnVWRpf56r8WKlQFww2Q4bf8VdMXwsEtfkdGb97xSAb8yRG7df4zYYQ3deEsK2WsK1UsK1U6LIqxJWfKQzcEODVw0GS7KbG1F8Pout6C7WuL5Dpv1PBtlLEFgWXfyHTY61Ery91rvkiwLWfB7h6jcxV/5LoskLF9gl0+tjLI7FesuuxzKnrHeqneQdL143Bjacj6wqg4ZFUph8JYvusCdsXIldvhGvXi/T+SuS6dQrXrZO4fp3Ib76UuH5NiD6fi1z/mcgNnwa5epWMbbHG1StEvsoSjbeoq2i60h6MYNN1XTAhNF1vdlBoVFSG7/Nh+1Ti2o1Brl8v03uDyDVfN3DDVz5u+FKh15cKvdbp9FoHvT5X6PW5wjVr4LrPda6NkugTJdL1EwXbIpkVx5sdGaXZ8S9gGgNIJ6ipPHgghO3TED23h+ixTafXZpmb1ofos0ml+9dw1VcaV3wapMvKIF1WSVz+qULPzxV6faZw9Wc613yq0Xt1iN9Ehei+WMG2QObz03JHDtxsGk07P2XRmZ/hx7ZG5rqtMjdubqTHFonrNov8doPMZRvA9pmPqz8X+MNWhb/tkrg/VuGWaJXLPmmk85Imen6m0+sz6BMlcsNqP9etVujysU63jwIcrwy1N6UFm6Zrgma4KKBxrE7lyq999PnaT58dcMNWjV5bFa7d6sP2lcj/+szP6/FNHK2SqQtpSKqIKItUN2psyJH52yYXtkV+uq9UuP5fMj1XqVy9WuWGFSE6LQgxbHMQv6kVXW92B12wKZouSEjGNNMVJvwgYdugcGOsym+2q/TZqnD9dh3bVz5u3h4guVJtnpJa808zkJlBMMS7SQG6vB/gimUKvVdK9Fmu0nu5zLXLZGzvaWzLDhggmoysqwYIKoKqG+rKqVO5douP62JUfvutxg2xCn1iZTpv0rgpRuF0XQAIgRJElSUURUWWZWRZRpFlgrIKeIEg7yaC7X2FXkslei+XDVkmY1sQ4pFNDaA3hwcdNF0XbGjNZwNQWXZaxrZV5XexMjftFLnpW4ne34rYNvjZUywBQUJqEEkMoEk6oqIgySqipCCKEt6Qis8fRNEaAB+TtijYInV6Lwtx7VKRPstkIj5S6PGBRGFtwFCgApquCDYFTQANXZeZkiARsVPnlu9kfhcr0/cbiYivA4w94DM0oet4VQVJUQiJGiFRIiTKBEMSAX+QhoBIvU/C1SQCfpIKGrl8kZerFitcu0Tkuk9ErlsiYXtDYuMpYyobE0gVbIouC6DiDsgMiwtx406Z/rs0+u6WGPCNSI8tIZbnSoCCEvITkBRkWSMUkAgEJbz+EE2+IA3eAPUNjTR6fNTWSni9PuoFN/d8KtBpkcg1n3jp82GQ3h/6sc33seAHb/P6pYOmCTY0VQCNEkHhrgMhfrdL5k/fafT/XqT/boU+sRI/2r0AhESFYFDCF1TwBSWa/CE8TQHcjQFcDX6cdQGq63w43PWU1AoEmup4emMjtvl+enzop/d7Aa57N4Btvo/Z37jCHBzBpuqaAHDOHWDo/iD99in8+XuZO/er/H6fxsB/h0irDgGqoYGAhOAL0eALUd/oo87TRK2nCUddI3anQKXTTUl1DUVVNXga6nh2mwvb6066L3Bz3btOekU2YXtd5MVNDmuVVtEFm6brAmiUu4OMPODnjv0idx+UGHpQ4q6DEnf928+h0iCg0egN0OgXqW8MUCd4cXm81LgbqHIJlDs9lFd5KK90U1hWQ3GlgLOqlrs/rsQ2q45rFjq57q0yukc6sL3iYc62akBDR0fRNcGmq5oAQYSAyuQEibsPhnjgkMYD8T4ePOTnv/ZrfJrtBTWE4A3ibvRTJ3hx1jdRXddApbOeMoebEruL3Ao3p8vqOVVSR1JuDZkFtbywvgDb0zl0eqmanm+Wct2bFdhmlvP2Po/hH6qIrmiCTdNUAVVElTVeyfTz10My435UGHNE5JGfJIYf1ZiV4kFo8uILBKirD+LwBHC43Dhq6ymurqfAUU9ORS05RSU0NHmQVRW/JCMqOho6354U6DEri04z8+nxWim2fxSx8ZgLEAlJCqoiCzZZUwVZVECDjUVNDD8s8sRRlSmJOs8mwbPHZJ466iO2yI8aDNJU56a8tpGqaicOZx2FVfWcLa8lq7CMBn8IHfAGZQKSik/SQAoBOjEZtdiezqTTS/l0fzmPrFIBNB9CUCcoSYJN0TTBKymgS5TXBXn8pwCTj8lMT1WZmarx+nGR2Rk680+GOFleh9/bgMtZR3V1HYWVLvJKajiTV0pVjRsV8IVEgrLaLApeERSCAAx5/xS2+48zZvlZAmKIQFMTHq+PppAi2DRdFQIyyKIfRImoMz6ePO7lpUyJl08r/PN0iMjTEh9kS6zNEUgp92GvaaDAXstZh4DLG0JoChAMyviDMn5Jxi/K+EISIVnFr0h4JWPZ33a8mNteSCI6vhpZbMDhaqChyYfHHxRsmhYURBECoRDoMvkukVfTFN7IlHk7W+aDXIlVOSHW5ob4qhi2F4v8WNLIiSov5wLgkVVERSUYMqa2LyTjF1UCkkpQ1vGLImJAxCsai2SdKFJQ6aG0ooqK+gBuVxOCTxBsuq4IkqQSFCVCkgyqzg8lXt5J9/H+WViVJ7G+KMSOEoVdJSp77DJxdRrH3Rq5goLDJyMERRqCIt6QbPiHqBAQFSRJJSCrhGSZJklDUs/nIefsNRRXe3DWefE0NjUf21BURFEiGDRWVH9I5Nu8Rt7Pk/lXocbWIpFvKzT2VSr8YJdIcEqk1Svke2TsPhV3SMYTEmkISngDCr6QTFBSCUkqQUnFL2kEJUNLflFF1aGuyUepow6HuxG34DdyVkVRkCQFUVLxBWR0ScEfFPmuuIG1hTIxpSr/rpA46FBIqJHJdGmcqVPJa1Co9MrUBiTcQQlPQKYhoNAUUvCJCn5JJSApBCTZEr8oEVJU/IpKiaOOmnov9Q1+QyOqqiErGqKiIYk6/mAATQ4QalRItPvZU+EnvkrmxxqJRJdIVp1KTr1GQaNChVei2idTE9BwBRTqAzKeoEyjKNMkKvglhaCkNAMZogAeX4DS6npcDQE8jYHmM0aajqLqyLJOSNbwSTJev0woEKCxyU9OdZCEkgAJ1UGSBYWsBo3cRihq0qj0KVT5ZBwBjdqQRn1IRhBVGiWVRlklqOiIikZQ1hAV4ytjJE2n0ummqt6LU/AjNAYEm64jaBqoqo6iaEiKhiirBESVhkAQr9eH0ChSUu3nVGkdGY4mUmt8ZLoC5DWoFDUplHpVKnw6VT6ZWn+IuqCEJ6TQEFINzUgSflXFJ8nUe304XALVdQ3UNwaob/TT5A0ZILoO4TCyrBKSZHxBGcEfxNPgpdETwO32U+ZoIKesnrPlHrLtbn6urCfPXk+B3U2R3cO5qgbOVTVQUilwrkKgtEqguLKe4sp6yhwNlNg9VLkEhKYgjd4QTX6RYFA+X2Dpuo6maaiqiqqqKIqGKKn4QwrekERjIIC70YenMUBjk0S9EKK23our3ovb48Xj8SI0BfD4ROq9IdyNQeoa/Lg8AZxuPzV1PuobRASfguAN0egP4Q1KBEMykqwKNkAxMnpDNM1oSxhQGrKiI6oqTapIkyTiDYUIiDLBkEwoICOGjHghKxqKqqCoEooqEVJFgkqIkBIiKIsEpBB+MYA/FMAXkgiICiHRmK2KoilWo6bZRIKu61bjRdd1QdEQVBVBkzRBlVRBFhVBVTRBUXRBknVB1hAUECQQNF0XUHVB13RB0XRBVDRBUjRBUTVBUlRBlBRBlGQhJGuCJOuCouiCpuqCqqpl/7Eemqor5HnS2Ja/hPezpvCP1PuYlfo3vvo5EnfA0baH9qs+CKZpBIIh7DUuyuw1lNprqHDU4mnwoqoamq5xyn2YVTkv8cKJO3n+TH+eTB7Ao/H9eSr+TnbmrfyfgdiddZzKKaK0yklhuYN6oWVfvabay+6Tu3gzaSJPpPZm9E9XMmnvH1n60wKSanZypuEg35WuZlrCMLb9vPSXgzicdWTkFLX7vya5Dq/spk62s8v1AW+cu53ns29kSd6z/Fi9mZ/L8tpqVFfZeHYxBe7MSwdJy85v8Xd1oJwDFRtZlTeTD88+wcKsMSzMGsv8rL8wNbMnc7LuJN6xg6AcsF6TW1xBkzfQct9P8pDrSkfT1QuDKKrKz8UV1t+V3kKi89/m1YyhvHlyMPOz/ouFZ4fwYe59fJAzjLfO3s66wuep8p7jbF0iUTkzOe76/rzZ6jxUVteGtch06gL2C4PIikJFtcv6e3/ZeuamDOHNU//NivwxfFY8jnXlE/iyYiKflz/Eh4WD2Gv/CL/YQIJjI2+dvJvXTt7FtJS+LPt5OvVBY383KEoUlFaGzSz5wqb5ubC0WSsyG3PfZUbKnXzw8wOsKX6EdWUT+NI+nq8cY1nrGMnikjuJd0Xhld1sr3iTt37+IyuLHmZN0WMszxnPzLSBvJnxMMWNPxv7vUITLrdw8VlzMswnNud+xD+O3cGy3LF8ce5R1pZN4IuKsXzlGM0X1SP4uPJ2jgpraJAcfFb+CJHnbuOz8pF8UT6OL0om8nnRJFblPcrLaXfxxolROHzGd2idq7xIHBEavTQFQwAcLNvMP5Lu5JOcsawpmsRnJROIKnuYtVWjWVP9Vz6q7McRz0pUTSa2Zh6LSgeytOJPfGa/j3UVY1lTMoFPz01kdcEjLM95hNmp/8UHmU+j6MYnlrJyz3UMknHW0IbDW8rLyfexIGs4nxU8zqqi8Xx07gGiKkfyheN+ltnvJEFYGdYOFWlUqjniWcGK8iFElQ1jTek4Pi2awOqCR1iZ9wgfnx3Hs4l9+aHc+BqH2voGRFFqC+JpaEKSjOR2Y84iZqX8majcx1ieN57Xc+/hvXPD+aziAZaX30VGY0yH0/1s00E+KR7KquL7+ezceFbnT2BFzkSW5Uzg7VP38UbKQ3hCdc1aKWoLktHsG06/nbnJ9/H+6VGsyJnIC9l38kreMNaUPsKSkkHsdy26aABMcK3lw4L/5l9FY1mdP56lOeP55Ox4Psh+mOeT7+BAyUZj17O8qiWIKMkUlNoBOFQaw4zkQSw+M5bZp+7in7mPsKnkFVade4DPSsfTJNVeFCSk+lhbPIVl+Q+wMnccS8+OY/GZsXxwZjTTj9/OkqwXACi3O/H5A+dBKhy1lFQac33t2bf5R/KdvJnxFxadnkSyYzuf5j3BssIR/Kt4DBvLp/NF2dOsqXiSNRVPsKbyCeNnxZN8XjaFz4ufJrr4Bf5V8Agr8h5iWc5YPs4ey4enR/P+6YeYnfZn3kh9CAUfqgz2Gtd5kLOFpZTYjUMHH516jmlJA3jjxHCO2XexteBtFpwZyqqC0awo+huLCv7Eu4W38V7x73mvtD/vl/Xl/bJ+vFfye94tuo2F+X/g3dw/szT/b6zIHcMnZ0fz0ZmHWXT6ISKzRvJq5mBeSh5MSeNZyzyyrBggWTlFlNsNssiMKYz9oQe7i/9FmmM/r6bezZKfx7Is5yGW5f+NFYUjWHXuflaXDmN12V+JKhtGVNkwVpX9lZXFw1lRNILl+Q/ySc6DfHRmFIuyRhF5ciRvZ/6NNzPvZ3baIJ5N+AM/1xsfXcg9V47XH2wLMidpFE/9eAcVQg7Lsp7j9fShfHTmIT4+M4rIrKG8ljGAeSf78eaZfszP7sc/z/bln9n9mH+mH29m9eO1jP7MPfF7ZibfxvSE3zP1UD+eiruVxw/cxIT9fRj+764Mje3M6bqjAOQVl+MPhgyQvHPllFQapnkhfgRf5y7haNV3PJvwe945+QDvnnyAf2bcQ0zR22S7fySzbj+Z7n2cdO/jZP1eTtbvI9O9j8y6fWS49pHm3Edq9T6OV+0luXIPRyt2k1C+i/jybzhYupUfSrfjV40wX1zhQNN0A8RR66bEbjjr5p+Xc9IRz9snJvJ88h94O/N+3s64j1dS7mJLXuT/v0e/vT6qa93nnVXXdXLOlRtJi6qSWLmL8Yd682rGvcxLG8qbJ4byRuoQXj56L+UNuRcdoDHk5kDJNvaXbuZA2Rb2l21hX9nX7C3byNaCKJKr4pqnbw3+QLBlQDttxn4dPsh4hseP3sjcjP/m5dRBvJYymNdTBjMtvh8rT865KMja0wsZvqsr4/f3ZNyBnjx88CpGxV3BiAM2bt5iY8PPKwz/KKlsG1lDooTgCRJAYPKR/jyb2pcZaQOZdfyPzDn+J145/l/MSfojU364lW05yzuE2F30FU/80JcZSQN5+fifmH38Tmam3MGM1Dt4LOE6pv90DyHFCGLZ+SXtL3pn88rJCR5hbPy1TEq6jqnJv2XGsduZdfwPzD52By8n/5FZSX9g8sGbeDflGU7VHMUTqKMhVM/Z2hMsSZ/JY3G38I/E25l77I/MOv4HZhy/nRkptzE1+Rbu+beNhMrvjLEKSi+cj0T+8AaPZfTi2eQ/8Gj89fz96C3MSB7AjOTfMzPpNmYn3c7MowN4/IdrmXKoPy8l3MtLP/2Fpw7fxiMHr+HFxH7MTrqNmUm/56XkAbyY3I/pyb/jr/tsRJ542hqnOGydaRdkxv6J/DXBxvflX/Fd0Rru2W3jmYTrmZnUnxlJ/ZhxtB+zjg5g1tH+vJBwM1Pjr+fZ+Ot5PuFmZiX2Y9ZR43kvJfXlpeR+PJ90M3/da2Nm4gME5MZ2c5F2QV5OeYA/7rZxrOYgANE/f8S933ViTFxXZiX1ZfbRvsxK7MusxFuZnXgrs8JkZuKtzEi8lZlHf8espL48Gd+Lu3fbeDVpLA1BY+kvc7T7ZTktQUQlyLQjg/nzv20cyo+zrsdX7OKR/bcybLeNp368hpd+uok5ib9lbuKtzfI75ib+jtmJv2PGT7fwfMJveOj7zty/O4JPs+YjKsYUdTc04Wloav/YRusLz/04lAeTIsgsPENewfnc0is1EH32Qx47MICH913F+O//F+O/t/H4wW7877gIHtnfhXHfd2Hs91cyZl9v3k19lgLPaev15TV1NDR6Oz4/0vrC26ceYVhcL45X/GB4d2Eljf7Q+cJI9pHqiGPVqVeZd+wRZicOZ0bCvbyS9DAfpD3PnnNfUuO3ny9NVI2T+eVI8oVPGrUB2ZsfzX1HehJTtMK6FgyJZOYW0+gXf1EIz8wro9LhvKTn2lrugkMoFOS5n/7C0APXYK8tb3GepMrh5HB8Cmknz5JbXEpBSQVlFbVU2N0UlVWRW1RK1s95/JCQzMkzPyPLMpqm4ff7CQQChEIhJElCURQ0TcPsVOm6fn6tCT+oUOkq4bGE27n/qzv4KeMIwVCQQCBAbV0ttXW1VFRWkJ19lrS0DJKSj5F4NInk5OOcPHmK/Px8amtrcbvd1NTU4HQ6cbvdNDU1WTCyLKOqaguYDmvfgNzE4bIYdpWv4UT5EezuMkQl9B877PT/DQC7cLwx8LR3hQAAAABJRU5ErkJggg==) no-repeat;padding-left:40px}
+ .browser .browser-firefox{background-position:0 -34px}
+ .browser .browser-ie{background-position:0 -68px;margin-left:0px}
+ .browser .browser-360{background-position:0 -170px;margin-left: -27px}
+ </style>
+</head>
+<body style="margin-top:50px">
+<h1>请升级您的浏览器,以便我们更好的为您提供服务!</h1>
+<p>您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。</p>
+<hr>
+<h2>请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束</h2>
+<p>自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 <a href="https://www.microsoft.com/zh-cn/WindowsForBusiness/End-of-IE-support">微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明</a> 。</p>
+<hr>
+<h2>您可以选择更先进的浏览器</h2>
+<p>推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。</p>
+<ul class="browser">
+ <li class="browser-chrome"><a href="https://www.google.cn/chrome/browser/desktop/index.html?hl=zh-CN&standalone=1"> 谷歌浏览器<span>Google Chrome</span></a></li>
+ <li class="browser-firefox"><a href="https://www.mozilla.org/zh-CN/firefox/new/"> 火狐浏览器<span>Mozilla Firefox</span></a></li>
+ <li class="browser-ie"><a href="https://windows.microsoft.com/zh-cn/internet-explorer/download-ie"> IE 11 浏览器<span>Internet Explorer</span></a></li>
+ <li class="browser-360"><a href="http://se.360.cn/"> 360安全浏览器<span>360 Chrome</span></a></li>
+ <div class="clean"></div>
+</ul>
+<hr>
+</body>
+</html>
\ No newline at end of file
diff --git a/sgd-ui/public/index.html b/sgd-ui/public/index.html
new file mode 100644
index 0000000..925455c
--- /dev/null
+++ b/sgd-ui/public/index.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="renderer" content="webkit">
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+ <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+ <title><%= webpackConfig.name %></title>
+ <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
+ <style>
+ html,
+ body,
+ #app {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+ }
+ .chromeframe {
+ margin: 0.2em 0;
+ background: #ccc;
+ color: #000;
+ padding: 0.2em 0;
+ }
+
+ #loader-wrapper {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 999999;
+ }
+
+ #loader {
+ display: block;
+ position: relative;
+ left: 50%;
+ top: 50%;
+ width: 150px;
+ height: 150px;
+ margin: -75px 0 0 -75px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #FFF;
+ -webkit-animation: spin 2s linear infinite;
+ -ms-animation: spin 2s linear infinite;
+ -moz-animation: spin 2s linear infinite;
+ -o-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ z-index: 1001;
+ }
+
+ #loader:before {
+ content: "";
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ right: 5px;
+ bottom: 5px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #FFF;
+ -webkit-animation: spin 3s linear infinite;
+ -moz-animation: spin 3s linear infinite;
+ -o-animation: spin 3s linear infinite;
+ -ms-animation: spin 3s linear infinite;
+ animation: spin 3s linear infinite;
+ }
+
+ #loader:after {
+ content: "";
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ right: 15px;
+ bottom: 15px;
+ border-radius: 50%;
+ border: 3px solid transparent;
+ border-top-color: #FFF;
+ -moz-animation: spin 1.5s linear infinite;
+ -o-animation: spin 1.5s linear infinite;
+ -ms-animation: spin 1.5s linear infinite;
+ -webkit-animation: spin 1.5s linear infinite;
+ animation: spin 1.5s linear infinite;
+ }
+
+
+ @-webkit-keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ -ms-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }
+
+ @keyframes spin {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ -ms-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }
+
+
+ #loader-wrapper .loader-section {
+ position: fixed;
+ top: 0;
+ width: 51%;
+ height: 100%;
+ background: #7171C6;
+ z-index: 1000;
+ -webkit-transform: translateX(0);
+ -ms-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ #loader-wrapper .loader-section.section-left {
+ left: 0;
+ }
+
+ #loader-wrapper .loader-section.section-right {
+ right: 0;
+ }
+
+
+ .loaded #loader-wrapper .loader-section.section-left {
+ -webkit-transform: translateX(-100%);
+ -ms-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+ transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+ }
+
+ .loaded #loader-wrapper .loader-section.section-right {
+ -webkit-transform: translateX(100%);
+ -ms-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+ transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+ }
+
+ .loaded #loader {
+ opacity: 0;
+ -webkit-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+ }
+
+ .loaded #loader-wrapper {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ -ms-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transition: all 0.3s 1s ease-out;
+ transition: all 0.3s 1s ease-out;
+ }
+
+ .no-js #loader-wrapper {
+ display: none;
+ }
+
+ .no-js h1 {
+ color: #222222;
+ }
+
+ #loader-wrapper .load_title {
+ font-family: 'Open Sans';
+ color: #FFF;
+ font-size: 19px;
+ width: 100%;
+ text-align: center;
+ z-index: 9999999999999;
+ position: absolute;
+ top: 60%;
+ opacity: 1;
+ line-height: 30px;
+ }
+
+ #loader-wrapper .load_title span {
+ font-weight: normal;
+ font-style: italic;
+ font-size: 13px;
+ color: #FFF;
+ opacity: 0.5;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="app">
+ <div id="loader-wrapper">
+ <div id="loader"></div>
+ <div class="loader-section section-left"></div>
+ <div class="loader-section section-right"></div>
+ <div class="load_title">正在加载系统资源,请耐心等待</div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/sgd-ui/public/robots.txt b/sgd-ui/public/robots.txt
new file mode 100644
index 0000000..77470cb
--- /dev/null
+++ b/sgd-ui/public/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
\ No newline at end of file
diff --git a/ruoyi-ui/public/styles/theme-chalk/index.css b/sgd-ui/public/styles/theme-chalk/index.css
similarity index 100%
rename from ruoyi-ui/public/styles/theme-chalk/index.css
rename to sgd-ui/public/styles/theme-chalk/index.css
diff --git a/sgd-ui/src/App.vue b/sgd-ui/src/App.vue
new file mode 100644
index 0000000..12df51d
--- /dev/null
+++ b/sgd-ui/src/App.vue
@@ -0,0 +1,20 @@
+<template>
+ <div id="app">
+ <router-view />
+ <theme-picker />
+ </div>
+</template>
+
+<script>
+import ThemePicker from "@/components/ThemePicker"
+
+export default {
+ name: "App",
+ components: { ThemePicker }
+}
+</script>
+<style scoped>
+#app .theme-picker {
+ display: none;
+}
+</style>
diff --git a/sgd-ui/src/api/login.js b/sgd-ui/src/api/login.js
new file mode 100644
index 0000000..f34245b
--- /dev/null
+++ b/sgd-ui/src/api/login.js
@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 登录方法
+export function login(username, password, code, uuid) {
+ return request({
+ url: '/auth/login',
+ headers: {
+ isToken: false,
+ repeatSubmit: false
+ },
+ method: 'post',
+ data: { username, password, code, uuid }
+ })
+}
+
+// 注册方法
+export function register(data) {
+ return request({
+ url: '/auth/register',
+ headers: {
+ isToken: false
+ },
+ method: 'post',
+ data: data
+ })
+}
+
+// 解锁屏幕
+export function unlockScreen(password) {
+ return request({
+ url: '/auth/unlockscreen',
+ method: 'post',
+ data: { password }
+ })
+}
+
+// 刷新方法
+export function refreshToken() {
+ return request({
+ url: '/auth/refresh',
+ method: 'post'
+ })
+}
+
+// 获取用户详细信息
+export function getInfo() {
+ return request({
+ url: '/system/user/getInfo',
+ method: 'get'
+ })
+}
+
+// 退出方法
+export function logout() {
+ return request({
+ url: '/auth/logout',
+ method: 'delete'
+ })
+}
+
+// 获取验证码
+export function getCodeImg() {
+ return request({
+ url: '/code',
+ headers: {
+ isToken: false
+ },
+ method: 'get',
+ timeout: 20000
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/menu.js b/sgd-ui/src/api/menu.js
new file mode 100644
index 0000000..845efd7
--- /dev/null
+++ b/sgd-ui/src/api/menu.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 获取路由
+export const getRouters = () => {
+ return request({
+ url: '/system/menu/getRouters',
+ method: 'get'
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/monitor/job.js b/sgd-ui/src/api/monitor/job.js
new file mode 100644
index 0000000..cb85117
--- /dev/null
+++ b/sgd-ui/src/api/monitor/job.js
@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 查询定时任务调度列表
+export function listJob(query) {
+ return request({
+ url: '/schedule/job/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询定时任务调度详细
+export function getJob(jobId) {
+ return request({
+ url: '/schedule/job/' + jobId,
+ method: 'get'
+ })
+}
+
+// 新增定时任务调度
+export function addJob(data) {
+ return request({
+ url: '/schedule/job',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改定时任务调度
+export function updateJob(data) {
+ return request({
+ url: '/schedule/job',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除定时任务调度
+export function delJob(jobId) {
+ return request({
+ url: '/schedule/job/' + jobId,
+ method: 'delete'
+ })
+}
+
+// 任务状态修改
+export function changeJobStatus(jobId, status) {
+ const data = {
+ jobId,
+ status
+ }
+ return request({
+ url: '/schedule/job/changeStatus',
+ method: 'put',
+ data: data
+ })
+}
+
+
+// 定时任务立即执行一次
+export function runJob(jobId, jobGroup) {
+ const data = {
+ jobId,
+ jobGroup
+ }
+ return request({
+ url: '/schedule/job/run',
+ method: 'put',
+ data: data
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/monitor/jobLog.js b/sgd-ui/src/api/monitor/jobLog.js
new file mode 100644
index 0000000..eea2666
--- /dev/null
+++ b/sgd-ui/src/api/monitor/jobLog.js
@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+// 查询调度日志列表
+export function listJobLog(query) {
+ return request({
+ url: '/schedule/job/log/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除调度日志
+export function delJobLog(jobLogId) {
+ return request({
+ url: '/schedule/job/log/' + jobLogId,
+ method: 'delete'
+ })
+}
+
+// 清空调度日志
+export function cleanJobLog() {
+ return request({
+ url: '/schedule/job/log/clean',
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/monitor/online.js b/sgd-ui/src/api/monitor/online.js
new file mode 100644
index 0000000..d53df58
--- /dev/null
+++ b/sgd-ui/src/api/monitor/online.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 查询在线用户列表
+export function list(query) {
+ return request({
+ url: '/system/online/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 强退用户
+export function forceLogout(tokenId) {
+ return request({
+ url: '/system/online/' + tokenId,
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/config.js b/sgd-ui/src/api/system/config.js
new file mode 100644
index 0000000..a404d82
--- /dev/null
+++ b/sgd-ui/src/api/system/config.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询参数列表
+export function listConfig(query) {
+ return request({
+ url: '/system/config/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询参数详细
+export function getConfig(configId) {
+ return request({
+ url: '/system/config/' + configId,
+ method: 'get'
+ })
+}
+
+// 根据参数键名查询参数值
+export function getConfigKey(configKey) {
+ return request({
+ url: '/system/config/configKey/' + configKey,
+ method: 'get'
+ })
+}
+
+// 新增参数配置
+export function addConfig(data) {
+ return request({
+ url: '/system/config',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改参数配置
+export function updateConfig(data) {
+ return request({
+ url: '/system/config',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除参数配置
+export function delConfig(configId) {
+ return request({
+ url: '/system/config/' + configId,
+ method: 'delete'
+ })
+}
+
+// 刷新参数缓存
+export function refreshCache() {
+ return request({
+ url: '/system/config/refreshCache',
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/dept.js b/sgd-ui/src/api/system/dept.js
new file mode 100644
index 0000000..b37643d
--- /dev/null
+++ b/sgd-ui/src/api/system/dept.js
@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询部门列表
+export function listDept(query) {
+ return request({
+ url: '/system/dept/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询部门列表(排除节点)
+export function listDeptExcludeChild(deptId) {
+ return request({
+ url: '/system/dept/list/exclude/' + deptId,
+ method: 'get'
+ })
+}
+
+// 查询部门详细
+export function getDept(deptId) {
+ return request({
+ url: '/system/dept/' + deptId,
+ method: 'get'
+ })
+}
+
+// 新增部门
+export function addDept(data) {
+ return request({
+ url: '/system/dept',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改部门
+export function updateDept(data) {
+ return request({
+ url: '/system/dept',
+ method: 'put',
+ data: data
+ })
+}
+
+// 保存部门排序
+export function updateDeptSort(data) {
+ return request({
+ url: '/system/dept/updateSort',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除部门
+export function delDept(deptId) {
+ return request({
+ url: '/system/dept/' + deptId,
+ method: 'delete'
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/system/dict/data.js b/sgd-ui/src/api/system/dict/data.js
new file mode 100644
index 0000000..6c9eb79
--- /dev/null
+++ b/sgd-ui/src/api/system/dict/data.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 查询字典数据列表
+export function listData(query) {
+ return request({
+ url: '/system/dict/data/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询字典数据详细
+export function getData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'get'
+ })
+}
+
+// 根据字典类型查询字典数据信息
+export function getDicts(dictType) {
+ return request({
+ url: '/system/dict/data/type/' + dictType,
+ method: 'get'
+ })
+}
+
+// 新增字典数据
+export function addData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改字典数据
+export function updateData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除字典数据
+export function delData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/dict/type.js b/sgd-ui/src/api/system/dict/type.js
new file mode 100644
index 0000000..a7a6e01
--- /dev/null
+++ b/sgd-ui/src/api/system/dict/type.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询字典类型列表
+export function listType(query) {
+ return request({
+ url: '/system/dict/type/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询字典类型详细
+export function getType(dictId) {
+ return request({
+ url: '/system/dict/type/' + dictId,
+ method: 'get'
+ })
+}
+
+// 新增字典类型
+export function addType(data) {
+ return request({
+ url: '/system/dict/type',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改字典类型
+export function updateType(data) {
+ return request({
+ url: '/system/dict/type',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除字典类型
+export function delType(dictId) {
+ return request({
+ url: '/system/dict/type/' + dictId,
+ method: 'delete'
+ })
+}
+
+// 刷新字典缓存
+export function refreshCache() {
+ return request({
+ url: '/system/dict/type/refreshCache',
+ method: 'delete'
+ })
+}
+
+// 获取字典选择框列表
+export function optionselect() {
+ return request({
+ url: '/system/dict/type/optionselect',
+ method: 'get'
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/system/logininfor.js b/sgd-ui/src/api/system/logininfor.js
new file mode 100644
index 0000000..e010dc3
--- /dev/null
+++ b/sgd-ui/src/api/system/logininfor.js
@@ -0,0 +1,33 @@
+import request from '@/utils/request'
+
+// 查询登录日志列表
+export function list(query) {
+ return request({
+ url: '/system/logininfor/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除登录日志
+export function delLogininfor(infoId) {
+ return request({
+ url: '/system/logininfor/' + infoId,
+ method: 'delete'
+ })
+}
+
+// 解锁用户登录状态
+export function unlockLogininfor(userName) {
+ return request({
+ url: '/system/logininfor/unlock/' + userName,
+ method: 'get'
+ })
+}
+// 清空登录日志
+export function cleanLogininfor() {
+ return request({
+ url: '/system/logininfor/clean',
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/menu.js b/sgd-ui/src/api/system/menu.js
new file mode 100644
index 0000000..fdf2138
--- /dev/null
+++ b/sgd-ui/src/api/system/menu.js
@@ -0,0 +1,69 @@
+import request from '@/utils/request'
+
+// 查询菜单列表
+export function listMenu(query) {
+ return request({
+ url: '/system/menu/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询菜单详细
+export function getMenu(menuId) {
+ return request({
+ url: '/system/menu/' + menuId,
+ method: 'get'
+ })
+}
+
+// 查询菜单下拉树结构
+export function treeselect() {
+ return request({
+ url: '/system/menu/treeselect',
+ method: 'get'
+ })
+}
+
+// 根据角色ID查询菜单下拉树结构
+export function roleMenuTreeselect(roleId) {
+ return request({
+ url: '/system/menu/roleMenuTreeselect/' + roleId,
+ method: 'get'
+ })
+}
+
+// 新增菜单
+export function addMenu(data) {
+ return request({
+ url: '/system/menu',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改菜单
+export function updateMenu(data) {
+ return request({
+ url: '/system/menu',
+ method: 'put',
+ data: data
+ })
+}
+
+// 保存菜单排序
+export function updateMenuSort(data) {
+ return request({
+ url: '/system/menu/updateSort',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除菜单
+export function delMenu(menuId) {
+ return request({
+ url: '/system/menu/' + menuId,
+ method: 'delete'
+ })
+}
\ No newline at end of file
diff --git a/sgd-ui/src/api/system/notice.js b/sgd-ui/src/api/system/notice.js
new file mode 100644
index 0000000..5c3ce0f
--- /dev/null
+++ b/sgd-ui/src/api/system/notice.js
@@ -0,0 +1,79 @@
+import request from '@/utils/request'
+
+// 查询公告列表
+export function listNotice(query) {
+ return request({
+ url: '/system/notice/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询公告详细
+export function getNotice(noticeId) {
+ return request({
+ url: '/system/notice/' + noticeId,
+ method: 'get'
+ })
+}
+
+// 新增公告
+export function addNotice(data) {
+ return request({
+ url: '/system/notice',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改公告
+export function updateNotice(data) {
+ return request({
+ url: '/system/notice',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除公告
+export function delNotice(noticeId) {
+ return request({
+ url: '/system/notice/' + noticeId,
+ method: 'delete'
+ })
+}
+
+// 首页顶部公告列表(带已读状态)
+export function listNoticeTop() {
+ return request({
+ url: '/system/notice/listTop',
+ method: 'get'
+ })
+}
+
+// 标记公告已读
+export function markNoticeRead(noticeId) {
+ return request({
+ url: '/system/notice/markRead',
+ method: 'post',
+ params: { noticeId }
+ })
+}
+
+// 批量标记已读
+export function markNoticeReadAll(ids) {
+ return request({
+ url: '/system/notice/markReadAll',
+ method: 'post',
+ params: { ids }
+ })
+}
+
+// 查询公告已读用户列表
+export function listNoticeReadUsers(query) {
+ return request({
+ url: '/system/notice/readUsers/list',
+ method: 'get',
+ params: query
+ })
+}
diff --git a/sgd-ui/src/api/system/operlog.js b/sgd-ui/src/api/system/operlog.js
new file mode 100644
index 0000000..51a4cc3
--- /dev/null
+++ b/sgd-ui/src/api/system/operlog.js
@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+// 查询操作日志列表
+export function list(query) {
+ return request({
+ url: '/system/operlog/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 删除操作日志
+export function delOperlog(operId) {
+ return request({
+ url: '/system/operlog/' + operId,
+ method: 'delete'
+ })
+}
+
+// 清空操作日志
+export function cleanOperlog() {
+ return request({
+ url: '/system/operlog/clean',
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/post.js b/sgd-ui/src/api/system/post.js
new file mode 100644
index 0000000..1a8e9ca
--- /dev/null
+++ b/sgd-ui/src/api/system/post.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询岗位列表
+export function listPost(query) {
+ return request({
+ url: '/system/post/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询岗位详细
+export function getPost(postId) {
+ return request({
+ url: '/system/post/' + postId,
+ method: 'get'
+ })
+}
+
+// 新增岗位
+export function addPost(data) {
+ return request({
+ url: '/system/post',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改岗位
+export function updatePost(data) {
+ return request({
+ url: '/system/post',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除岗位
+export function delPost(postId) {
+ return request({
+ url: '/system/post/' + postId,
+ method: 'delete'
+ })
+}
diff --git a/sgd-ui/src/api/system/role.js b/sgd-ui/src/api/system/role.js
new file mode 100644
index 0000000..f13e6f4
--- /dev/null
+++ b/sgd-ui/src/api/system/role.js
@@ -0,0 +1,119 @@
+import request from '@/utils/request'
+
+// 查询角色列表
+export function listRole(query) {
+ return request({
+ url: '/system/role/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询角色详细
+export function getRole(roleId) {
+ return request({
+ url: '/system/role/' + roleId,
+ method: 'get'
+ })
+}
+
+// 新增角色
+export function addRole(data) {
+ return request({
+ url: '/system/role',
+ method: 'post',
+ data: data
+ })
+}
+
+// 修改角色
+export function updateRole(data) {
+ return request({
+ url: '/system/role',
+ method: 'put',
+ data: data
+ })
+}
+
+// 角色数据权限
+export function dataScope(data) {
+ return request({
+ url: '/system/role/dataScope',
+ method: 'put',
+ data: data
+ })
+}
+
+// 角色状态修改
+export function changeRoleStatus(roleId, status) {
+ const data = {
+ roleId,
+ status
+ }
+ return request({
+ url: '/system/role/changeStatus',
+ method: 'put',
+ data: data
+ })
+}
+
+// 删除角色
+export function delRole(roleId) {
+ return request({
+ url: '/system/role/' + roleId,
+ method: 'delete'
+ })
+}
+
+// 查询角色已授权用户列表
+export function allocatedUserList(query) {
+ return request({
+ url: '/system/role/authUser/allocatedList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询角色未授权用户列表
+export function unallocatedUserList(query) {
+ return request({
+ url: '/system/role/authUser/unallocatedList',
+ method: 'get',
+ params: query
+ })
+}
+
+// 取消用户授权角色
+export function authUserCancel(data) {
+ return request({
+ url: '/system/role/authUser/cancel',
+ method: 'put',
+ data: data
+ })
+}
+
+// 批量取消用户授权角色
+export function authUserCancelAll(data) {
+ return request({
+ url: '/system/role/authUser/cancelAll',
+ method: 'put',
+ params: data
+ })
+}
+
+// 授权用户选择
+export function authUserSelectAll(data) {
+ return request({
+ url: '/system/role/authUser/selectAll',
+ method: 'put',
+ params: data
+ })
+}
+
+// 根据角色ID查询部门树结构
+export function deptTreeSelect(roleId) {
+ return request({
+ url: '/system/role/deptTree/' + roleId,
+ method: 'get'
+ })
+}
diff --git a/ruoyi-ui/src/api/system/user.js b/sgd-ui/src/api/system/user.js
similarity index 100%
rename from ruoyi-ui/src/api/system/user.js
rename to sgd-ui/src/api/system/user.js
diff --git a/sgd-ui/src/api/tool/gen.js b/sgd-ui/src/api/tool/gen.js
new file mode 100644
index 0000000..7524a0a
--- /dev/null
+++ b/sgd-ui/src/api/tool/gen.js
@@ -0,0 +1,76 @@
+import request from '@/utils/request'
+
+// 查询生成表数据
+export function listTable(query) {
+ return request({
+ url: '/code/gen/list',
+ method: 'get',
+ params: query
+ })
+}
+// 查询db数据库列表
+export function listDbTable(query) {
+ return request({
+ url: '/code/gen/db/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 查询表详细信息
+export function getGenTable(tableId) {
+ return request({
+ url: '/code/gen/' + tableId,
+ method: 'get'
+ })
+}
+
+// 修改代码生成信息
+export function updateGenTable(data) {
+ return request({
+ url: '/code/gen',
+ method: 'put',
+ data: data
+ })
+}
+
+// 导入表
+export function importTable(data) {
+ return request({
+ url: '/code/gen/importTable',
+ method: 'post',
+ params: data
+ })
+}
+
+// 预览生成代码
+export function previewTable(tableId) {
+ return request({
+ url: '/code/gen/preview/' + tableId,
+ method: 'get'
+ })
+}
+
+// 删除表数据
+export function delTable(tableId) {
+ return request({
+ url: '/code/gen/' + tableId,
+ method: 'delete'
+ })
+}
+
+// 生成代码(自定义路径)
+export function genCode(tableName) {
+ return request({
+ url: '/code/gen/genCode/' + tableName,
+ method: 'get'
+ })
+}
+
+// 同步数据库
+export function synchDb(tableName) {
+ return request({
+ url: '/code/gen/synchDb/' + tableName,
+ method: 'get'
+ })
+}
diff --git a/ruoyi-ui/src/assets/401_images/401.gif b/sgd-ui/src/assets/401_images/401.gif
similarity index 100%
rename from ruoyi-ui/src/assets/401_images/401.gif
rename to sgd-ui/src/assets/401_images/401.gif
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404.png b/sgd-ui/src/assets/404_images/404.png
similarity index 100%
rename from ruoyi-ui/src/assets/404_images/404.png
rename to sgd-ui/src/assets/404_images/404.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404_cloud.png b/sgd-ui/src/assets/404_images/404_cloud.png
similarity index 100%
rename from ruoyi-ui/src/assets/404_images/404_cloud.png
rename to sgd-ui/src/assets/404_images/404_cloud.png
Binary files differ
diff --git a/sgd-ui/src/assets/icons/index.js b/sgd-ui/src/assets/icons/index.js
new file mode 100644
index 0000000..2c6b309
--- /dev/null
+++ b/sgd-ui/src/assets/icons/index.js
@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)
diff --git a/ruoyi-ui/src/assets/icons/svg/404.svg b/sgd-ui/src/assets/icons/svg/404.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/404.svg
rename to sgd-ui/src/assets/icons/svg/404.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/bell.svg b/sgd-ui/src/assets/icons/svg/bell.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/bell.svg
rename to sgd-ui/src/assets/icons/svg/bell.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/bug.svg b/sgd-ui/src/assets/icons/svg/bug.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/bug.svg
rename to sgd-ui/src/assets/icons/svg/bug.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/build.svg b/sgd-ui/src/assets/icons/svg/build.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/build.svg
rename to sgd-ui/src/assets/icons/svg/build.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/button.svg b/sgd-ui/src/assets/icons/svg/button.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/button.svg
rename to sgd-ui/src/assets/icons/svg/button.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/cascader.svg b/sgd-ui/src/assets/icons/svg/cascader.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/cascader.svg
rename to sgd-ui/src/assets/icons/svg/cascader.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/chart.svg b/sgd-ui/src/assets/icons/svg/chart.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/chart.svg
rename to sgd-ui/src/assets/icons/svg/chart.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/checkbox.svg b/sgd-ui/src/assets/icons/svg/checkbox.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/checkbox.svg
rename to sgd-ui/src/assets/icons/svg/checkbox.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/client.svg b/sgd-ui/src/assets/icons/svg/client.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/client.svg
rename to sgd-ui/src/assets/icons/svg/client.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/clipboard.svg b/sgd-ui/src/assets/icons/svg/clipboard.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/clipboard.svg
rename to sgd-ui/src/assets/icons/svg/clipboard.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/code.svg b/sgd-ui/src/assets/icons/svg/code.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/code.svg
rename to sgd-ui/src/assets/icons/svg/code.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/color.svg b/sgd-ui/src/assets/icons/svg/color.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/color.svg
rename to sgd-ui/src/assets/icons/svg/color.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/component.svg b/sgd-ui/src/assets/icons/svg/component.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/component.svg
rename to sgd-ui/src/assets/icons/svg/component.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/dashboard.svg b/sgd-ui/src/assets/icons/svg/dashboard.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/dashboard.svg
rename to sgd-ui/src/assets/icons/svg/dashboard.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/date-range.svg b/sgd-ui/src/assets/icons/svg/date-range.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/date-range.svg
rename to sgd-ui/src/assets/icons/svg/date-range.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/date.svg b/sgd-ui/src/assets/icons/svg/date.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/date.svg
rename to sgd-ui/src/assets/icons/svg/date.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/dict.svg b/sgd-ui/src/assets/icons/svg/dict.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/dict.svg
rename to sgd-ui/src/assets/icons/svg/dict.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/documentation.svg b/sgd-ui/src/assets/icons/svg/documentation.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/documentation.svg
rename to sgd-ui/src/assets/icons/svg/documentation.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/download.svg b/sgd-ui/src/assets/icons/svg/download.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/download.svg
rename to sgd-ui/src/assets/icons/svg/download.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/drag.svg b/sgd-ui/src/assets/icons/svg/drag.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/drag.svg
rename to sgd-ui/src/assets/icons/svg/drag.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/druid.svg b/sgd-ui/src/assets/icons/svg/druid.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/druid.svg
rename to sgd-ui/src/assets/icons/svg/druid.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/edit.svg b/sgd-ui/src/assets/icons/svg/edit.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/edit.svg
rename to sgd-ui/src/assets/icons/svg/edit.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/education.svg b/sgd-ui/src/assets/icons/svg/education.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/education.svg
rename to sgd-ui/src/assets/icons/svg/education.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/email.svg b/sgd-ui/src/assets/icons/svg/email.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/email.svg
rename to sgd-ui/src/assets/icons/svg/email.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/enter.svg b/sgd-ui/src/assets/icons/svg/enter.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/enter.svg
rename to sgd-ui/src/assets/icons/svg/enter.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/example.svg b/sgd-ui/src/assets/icons/svg/example.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/example.svg
rename to sgd-ui/src/assets/icons/svg/example.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/excel.svg b/sgd-ui/src/assets/icons/svg/excel.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/excel.svg
rename to sgd-ui/src/assets/icons/svg/excel.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg b/sgd-ui/src/assets/icons/svg/exit-fullscreen.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg
rename to sgd-ui/src/assets/icons/svg/exit-fullscreen.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/eye-open.svg b/sgd-ui/src/assets/icons/svg/eye-open.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/eye-open.svg
rename to sgd-ui/src/assets/icons/svg/eye-open.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/eye.svg b/sgd-ui/src/assets/icons/svg/eye.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/eye.svg
rename to sgd-ui/src/assets/icons/svg/eye.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/form.svg b/sgd-ui/src/assets/icons/svg/form.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/form.svg
rename to sgd-ui/src/assets/icons/svg/form.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/fullscreen.svg b/sgd-ui/src/assets/icons/svg/fullscreen.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/fullscreen.svg
rename to sgd-ui/src/assets/icons/svg/fullscreen.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/github.svg b/sgd-ui/src/assets/icons/svg/github.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/github.svg
rename to sgd-ui/src/assets/icons/svg/github.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/guide.svg b/sgd-ui/src/assets/icons/svg/guide.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/guide.svg
rename to sgd-ui/src/assets/icons/svg/guide.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/icon.svg b/sgd-ui/src/assets/icons/svg/icon.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/icon.svg
rename to sgd-ui/src/assets/icons/svg/icon.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/input.svg b/sgd-ui/src/assets/icons/svg/input.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/input.svg
rename to sgd-ui/src/assets/icons/svg/input.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/international.svg b/sgd-ui/src/assets/icons/svg/international.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/international.svg
rename to sgd-ui/src/assets/icons/svg/international.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/job.svg b/sgd-ui/src/assets/icons/svg/job.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/job.svg
rename to sgd-ui/src/assets/icons/svg/job.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/language.svg b/sgd-ui/src/assets/icons/svg/language.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/language.svg
rename to sgd-ui/src/assets/icons/svg/language.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/link.svg b/sgd-ui/src/assets/icons/svg/link.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/link.svg
rename to sgd-ui/src/assets/icons/svg/link.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/list.svg b/sgd-ui/src/assets/icons/svg/list.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/list.svg
rename to sgd-ui/src/assets/icons/svg/list.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/lock.svg b/sgd-ui/src/assets/icons/svg/lock.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/lock.svg
rename to sgd-ui/src/assets/icons/svg/lock.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/log.svg b/sgd-ui/src/assets/icons/svg/log.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/log.svg
rename to sgd-ui/src/assets/icons/svg/log.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/logininfor.svg b/sgd-ui/src/assets/icons/svg/logininfor.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/logininfor.svg
rename to sgd-ui/src/assets/icons/svg/logininfor.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/message.svg b/sgd-ui/src/assets/icons/svg/message.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/message.svg
rename to sgd-ui/src/assets/icons/svg/message.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/money.svg b/sgd-ui/src/assets/icons/svg/money.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/money.svg
rename to sgd-ui/src/assets/icons/svg/money.svg
diff --git a/sgd-ui/src/assets/icons/svg/monitor.svg b/sgd-ui/src/assets/icons/svg/monitor.svg
new file mode 100644
index 0000000..bc308cb
--- /dev/null
+++ b/sgd-ui/src/assets/icons/svg/monitor.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/more-up.svg b/sgd-ui/src/assets/icons/svg/more-up.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/more-up.svg
rename to sgd-ui/src/assets/icons/svg/more-up.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/nacos.svg b/sgd-ui/src/assets/icons/svg/nacos.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/nacos.svg
rename to sgd-ui/src/assets/icons/svg/nacos.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/nested.svg b/sgd-ui/src/assets/icons/svg/nested.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/nested.svg
rename to sgd-ui/src/assets/icons/svg/nested.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/number.svg b/sgd-ui/src/assets/icons/svg/number.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/number.svg
rename to sgd-ui/src/assets/icons/svg/number.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/online.svg b/sgd-ui/src/assets/icons/svg/online.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/online.svg
rename to sgd-ui/src/assets/icons/svg/online.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/password.svg b/sgd-ui/src/assets/icons/svg/password.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/password.svg
rename to sgd-ui/src/assets/icons/svg/password.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/pdf.svg b/sgd-ui/src/assets/icons/svg/pdf.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/pdf.svg
rename to sgd-ui/src/assets/icons/svg/pdf.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/people.svg b/sgd-ui/src/assets/icons/svg/people.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/people.svg
rename to sgd-ui/src/assets/icons/svg/people.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/peoples.svg b/sgd-ui/src/assets/icons/svg/peoples.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/peoples.svg
rename to sgd-ui/src/assets/icons/svg/peoples.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/phone.svg b/sgd-ui/src/assets/icons/svg/phone.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/phone.svg
rename to sgd-ui/src/assets/icons/svg/phone.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/post.svg b/sgd-ui/src/assets/icons/svg/post.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/post.svg
rename to sgd-ui/src/assets/icons/svg/post.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/qq.svg b/sgd-ui/src/assets/icons/svg/qq.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/qq.svg
rename to sgd-ui/src/assets/icons/svg/qq.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/question.svg b/sgd-ui/src/assets/icons/svg/question.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/question.svg
rename to sgd-ui/src/assets/icons/svg/question.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/radio.svg b/sgd-ui/src/assets/icons/svg/radio.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/radio.svg
rename to sgd-ui/src/assets/icons/svg/radio.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/rate.svg b/sgd-ui/src/assets/icons/svg/rate.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/rate.svg
rename to sgd-ui/src/assets/icons/svg/rate.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/row.svg b/sgd-ui/src/assets/icons/svg/row.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/row.svg
rename to sgd-ui/src/assets/icons/svg/row.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/search.svg b/sgd-ui/src/assets/icons/svg/search.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/search.svg
rename to sgd-ui/src/assets/icons/svg/search.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/select.svg b/sgd-ui/src/assets/icons/svg/select.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/select.svg
rename to sgd-ui/src/assets/icons/svg/select.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/sentinel.svg b/sgd-ui/src/assets/icons/svg/sentinel.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/sentinel.svg
rename to sgd-ui/src/assets/icons/svg/sentinel.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/server.svg b/sgd-ui/src/assets/icons/svg/server.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/server.svg
rename to sgd-ui/src/assets/icons/svg/server.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/shopping.svg b/sgd-ui/src/assets/icons/svg/shopping.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/shopping.svg
rename to sgd-ui/src/assets/icons/svg/shopping.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/size.svg b/sgd-ui/src/assets/icons/svg/size.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/size.svg
rename to sgd-ui/src/assets/icons/svg/size.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/skill.svg b/sgd-ui/src/assets/icons/svg/skill.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/skill.svg
rename to sgd-ui/src/assets/icons/svg/skill.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/slider.svg b/sgd-ui/src/assets/icons/svg/slider.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/slider.svg
rename to sgd-ui/src/assets/icons/svg/slider.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/star.svg b/sgd-ui/src/assets/icons/svg/star.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/star.svg
rename to sgd-ui/src/assets/icons/svg/star.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/swagger.svg b/sgd-ui/src/assets/icons/svg/swagger.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/swagger.svg
rename to sgd-ui/src/assets/icons/svg/swagger.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/switch.svg b/sgd-ui/src/assets/icons/svg/switch.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/switch.svg
rename to sgd-ui/src/assets/icons/svg/switch.svg
diff --git a/sgd-ui/src/assets/icons/svg/system.svg b/sgd-ui/src/assets/icons/svg/system.svg
new file mode 100644
index 0000000..5992593
--- /dev/null
+++ b/sgd-ui/src/assets/icons/svg/system.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827724451" class="icon" style="" viewBox="0 0 1084 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10233" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M1080.09609 434.500756c-4.216302-23.731757-26.9241-47.945376-50.595623-53.185637l-17.648235-4.095836a175.940257 175.940257 0 0 1-101.612877-80.832531 177.807476 177.807476 0 0 1-18.732427-129.801867l5.541425-16.684509c7.10748-23.129428-2.108151-54.992624-20.599646-70.833873 0 0-16.624276-14.094495-63.244529-41.199293-46.800951-26.984332-66.858502-34.513443-66.858502-34.513443-22.76803-8.372371-54.631227-0.361397-71.255503 17.407304l-12.287509 13.251234a173.470708 173.470708 0 0 1-120.465769 48.065842A174.13327 174.13327 0 0 1 421.329029 33.590675L409.583617 20.761071C393.140039 2.99237 361.096144-4.898138 338.267881 3.353767c0 0-20.358715 7.529111-67.099434 34.513443-46.800951 27.34573-63.244529 41.440225-63.244529 41.440225-18.431263 15.66055-27.646894 47.222582-20.539413 70.592941l5.059562 16.865207a178.048407 178.048407 0 0 1-18.672194 129.621169 174.916297 174.916297 0 0 1-102.275439 81.073463l-17.045906 3.854904c-23.310126 5.42096-46.258856 29.333415-50.595623 53.185637 0 0-3.854905 21.382674-3.854905 75.712737 0 54.330062 3.854905 75.712736 3.854905 75.712736 4.216302 23.972688 26.9241 47.945376 50.595623 53.185637l16.624276 3.854905a174.253736 174.253736 0 0 1 102.395904 81.314394c23.310126 40.837896 28.911785 87.337683 18.732427 129.801867l-4.81863 16.443578c-7.10748 23.129428 2.108151 54.992624 20.599646 70.833872 0 0 16.624276 14.094495 63.244529 41.199293 46.800951 27.104798 66.918735 34.513443 66.918735 34.513443 22.707798 8.372371 54.631227 0.361397 71.255503-17.407303l11.624947-12.588673a175.096996 175.096996 0 0 1 242.256662 0.120465l11.624947 12.648906c16.383345 17.708468 48.427239 25.598976 71.255503 17.347071 0 0 20.358715-7.529111 67.159666-34.513443 46.740719-27.104798 63.124063-41.199293 63.124064-41.199293 18.491496-15.600317 27.707127-47.463513 20.599646-70.833873l-5.059562-17.106139a176.723284 176.723284 0 0 1 18.672194-129.139305 176.060722 176.060722 0 0 1 102.395904-81.314394l16.68451-3.854905c23.310126-5.42096 46.258856-29.333415 50.595623-53.185637 0 0 3.854905-21.382674 3.854904-75.712737-0.240932-54.330062-4.095836-75.833202-4.095836-75.833202z m-537.819428 293.334149c-119.261112 0-216.175824-97.336342-216.175824-217.621412a216.657687 216.657687 0 0 1 216.236057-217.320249c119.200879 0 216.115591 97.276109 216.11559 217.56118-0.240932 120.044139-96.974945 217.320248-216.175823 217.320249z" p-id="10234"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tab.svg b/sgd-ui/src/assets/icons/svg/tab.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/tab.svg
rename to sgd-ui/src/assets/icons/svg/tab.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/table.svg b/sgd-ui/src/assets/icons/svg/table.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/table.svg
rename to sgd-ui/src/assets/icons/svg/table.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/textarea.svg b/sgd-ui/src/assets/icons/svg/textarea.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/textarea.svg
rename to sgd-ui/src/assets/icons/svg/textarea.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/theme.svg b/sgd-ui/src/assets/icons/svg/theme.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/theme.svg
rename to sgd-ui/src/assets/icons/svg/theme.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/time-range.svg b/sgd-ui/src/assets/icons/svg/time-range.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/time-range.svg
rename to sgd-ui/src/assets/icons/svg/time-range.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/time.svg b/sgd-ui/src/assets/icons/svg/time.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/time.svg
rename to sgd-ui/src/assets/icons/svg/time.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/tool.svg b/sgd-ui/src/assets/icons/svg/tool.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/tool.svg
rename to sgd-ui/src/assets/icons/svg/tool.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/tree-table.svg b/sgd-ui/src/assets/icons/svg/tree-table.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/tree-table.svg
rename to sgd-ui/src/assets/icons/svg/tree-table.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/tree.svg b/sgd-ui/src/assets/icons/svg/tree.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/tree.svg
rename to sgd-ui/src/assets/icons/svg/tree.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/upload.svg b/sgd-ui/src/assets/icons/svg/upload.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/upload.svg
rename to sgd-ui/src/assets/icons/svg/upload.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/user.svg b/sgd-ui/src/assets/icons/svg/user.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/user.svg
rename to sgd-ui/src/assets/icons/svg/user.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/validCode.svg b/sgd-ui/src/assets/icons/svg/validCode.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/validCode.svg
rename to sgd-ui/src/assets/icons/svg/validCode.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/wechat.svg b/sgd-ui/src/assets/icons/svg/wechat.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/wechat.svg
rename to sgd-ui/src/assets/icons/svg/wechat.svg
diff --git a/ruoyi-ui/src/assets/icons/svg/zip.svg b/sgd-ui/src/assets/icons/svg/zip.svg
similarity index 100%
rename from ruoyi-ui/src/assets/icons/svg/zip.svg
rename to sgd-ui/src/assets/icons/svg/zip.svg
diff --git a/sgd-ui/src/assets/icons/svgo.yml b/sgd-ui/src/assets/icons/svgo.yml
new file mode 100644
index 0000000..d11906a
--- /dev/null
+++ b/sgd-ui/src/assets/icons/svgo.yml
@@ -0,0 +1,22 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+ # - name
+ #
+ # or:
+ # - name: false
+ # - name: true
+ #
+ # or:
+ # - name:
+ # param1: 1
+ # param2: 2
+
+- removeAttrs:
+ attrs:
+ - 'fill'
+ - 'fill-rule'
diff --git a/sgd-ui/src/assets/images/dark.svg b/sgd-ui/src/assets/images/dark.svg
new file mode 100644
index 0000000..f646bd7
--- /dev/null
+++ b/sgd-ui/src/assets/images/dark.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+ <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+ <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+ <feMerge>
+ <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+ <feMergeNode in="SourceGraphic"></feMergeNode>
+ </feMerge>
+ </filter>
+ <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+ <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+ <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+ <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+ </filter>
+ </defs>
+ <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+ <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+ <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+ <mask id="mask-3" fill="white">
+ <use xlink:href="#path-2"></use>
+ </mask>
+ <g id="Rectangle-18">
+ <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+ <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+ </g>
+ <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+ <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/sgd-ui/src/assets/images/light.svg b/sgd-ui/src/assets/images/light.svg
new file mode 100644
index 0000000..ab7cc08
--- /dev/null
+++ b/sgd-ui/src/assets/images/light.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+ <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+ <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+ <feMerge>
+ <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+ <feMergeNode in="SourceGraphic"></feMergeNode>
+ </feMerge>
+ </filter>
+ <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+ <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+ <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+ <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+ <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+ </filter>
+ </defs>
+ <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
+ <g id="Group-8" transform="translate(1167.000000, 0.000000)">
+ <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
+ <mask id="mask-3" fill="white">
+ <use xlink:href="#path-2"></use>
+ </mask>
+ <g id="Rectangle-18">
+ <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+ <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+ </g>
+ <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+ <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/images/login-background.jpg b/sgd-ui/src/assets/images/login-background.jpg
similarity index 100%
rename from ruoyi-ui/src/assets/images/login-background.jpg
rename to sgd-ui/src/assets/images/login-background.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/images/pay.png b/sgd-ui/src/assets/images/pay.png
similarity index 100%
rename from ruoyi-ui/src/assets/images/pay.png
rename to sgd-ui/src/assets/images/pay.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/images/profile.jpg b/sgd-ui/src/assets/images/profile.jpg
similarity index 100%
rename from ruoyi-ui/src/assets/images/profile.jpg
rename to sgd-ui/src/assets/images/profile.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/logo/logo.png b/sgd-ui/src/assets/logo/logo.png
similarity index 100%
rename from ruoyi-ui/src/assets/logo/logo.png
rename to sgd-ui/src/assets/logo/logo.png
Binary files differ
diff --git a/sgd-ui/src/assets/styles/btn.scss b/sgd-ui/src/assets/styles/btn.scss
new file mode 100644
index 0000000..e6ba1a8
--- /dev/null
+++ b/sgd-ui/src/assets/styles/btn.scss
@@ -0,0 +1,99 @@
+@import './variables.scss';
+
+@mixin colorBtn($color) {
+ background: $color;
+
+ &:hover {
+ color: $color;
+
+ &:before,
+ &:after {
+ background: $color;
+ }
+ }
+}
+
+.blue-btn {
+ @include colorBtn($blue)
+}
+
+.light-blue-btn {
+ @include colorBtn($light-blue)
+}
+
+.red-btn {
+ @include colorBtn($red)
+}
+
+.pink-btn {
+ @include colorBtn($pink)
+}
+
+.green-btn {
+ @include colorBtn($green)
+}
+
+.tiffany-btn {
+ @include colorBtn($tiffany)
+}
+
+.yellow-btn {
+ @include colorBtn($yellow)
+}
+
+.pan-btn {
+ font-size: 14px;
+ color: #fff;
+ padding: 14px 36px;
+ border-radius: 8px;
+ border: none;
+ outline: none;
+ transition: 600ms ease all;
+ position: relative;
+ display: inline-block;
+
+ &:hover {
+ background: #fff;
+
+ &:before,
+ &:after {
+ width: 100%;
+ transition: 600ms ease all;
+ }
+ }
+
+ &:before,
+ &:after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ height: 2px;
+ width: 0;
+ transition: 400ms ease all;
+ }
+
+ &::after {
+ right: inherit;
+ top: inherit;
+ left: 0;
+ bottom: 0;
+ }
+}
+
+.custom-button {
+ display: inline-block;
+ line-height: 1;
+ white-space: nowrap;
+ cursor: pointer;
+ background: #fff;
+ color: #fff;
+ -webkit-appearance: none;
+ text-align: center;
+ box-sizing: border-box;
+ outline: 0;
+ margin: 0;
+ padding: 10px 15px;
+ font-size: 14px;
+ border-radius: 4px;
+}
diff --git a/sgd-ui/src/assets/styles/element-ui.scss b/sgd-ui/src/assets/styles/element-ui.scss
new file mode 100644
index 0000000..363092a
--- /dev/null
+++ b/sgd-ui/src/assets/styles/element-ui.scss
@@ -0,0 +1,92 @@
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+ font-weight: 400 !important;
+}
+
+.el-upload {
+ input[type="file"] {
+ display: none !important;
+ }
+}
+
+.el-upload__input {
+ display: none;
+}
+
+.cell {
+ .el-tag {
+ margin-right: 0px;
+ }
+}
+
+.small-padding {
+ .cell {
+ padding-left: 5px;
+ padding-right: 5px;
+ }
+}
+
+.fixed-width {
+ .el-button--mini {
+ padding: 7px 10px;
+ width: 60px;
+ }
+}
+
+.status-col {
+ .cell {
+ padding: 0 10px;
+ text-align: center;
+
+ .el-tag {
+ margin-right: 0px;
+ }
+ }
+}
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+ transform: none;
+ left: 0;
+ position: relative;
+ margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+ .el-upload {
+ width: 100%;
+
+ .el-upload-dragger {
+ width: 100%;
+ height: 200px;
+ }
+ }
+}
+
+// dropdown
+.el-dropdown-menu {
+ a {
+ display: block
+ }
+}
+
+// fix date-picker ui bug in filter-item
+.el-range-editor.el-input__inner {
+ display: inline-flex !important;
+}
+
+// to fix el-date-picker css style
+.el-range-separator {
+ box-sizing: content-box;
+}
+
+.el-menu--collapse
+ > div
+ > .el-submenu
+ > .el-submenu__title
+ .el-submenu__icon-arrow {
+ display: none;
+}
\ No newline at end of file
diff --git a/sgd-ui/src/assets/styles/element-variables.scss b/sgd-ui/src/assets/styles/element-variables.scss
new file mode 100644
index 0000000..1615ff2
--- /dev/null
+++ b/sgd-ui/src/assets/styles/element-variables.scss
@@ -0,0 +1,31 @@
+/**
+* I think element-ui's default theme color is too light for long-term use.
+* So I modified the default color and you can modify it to your liking.
+**/
+
+/* theme color */
+$--color-primary: #1890ff;
+$--color-success: #13ce66;
+$--color-warning: #ffba00;
+$--color-danger: #ff4949;
+// $--color-info: #1E1E1E;
+
+$--button-font-weight: 400;
+
+// $--color-text-regular: #1f2d3d;
+
+$--border-color-light: #dfe4ed;
+$--border-color-lighter: #e6ebf5;
+
+$--table-border: 1px solid #dfe6ec;
+
+/* icon font path, required */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+
+@import "~element-ui/packages/theme-chalk/src/index";
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+ theme: $--color-primary;
+}
diff --git a/sgd-ui/src/assets/styles/index.scss b/sgd-ui/src/assets/styles/index.scss
new file mode 100644
index 0000000..bb87292
--- /dev/null
+++ b/sgd-ui/src/assets/styles/index.scss
@@ -0,0 +1,178 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+@import './btn.scss';
+
+body {
+ height: 100%;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+ font-weight: 700;
+}
+
+html {
+ height: 100%;
+ box-sizing: border-box;
+}
+
+#app {
+ height: 100%;
+}
+
+*,
+*:before,
+*:after {
+ box-sizing: inherit;
+}
+
+.no-padding {
+ padding: 0px !important;
+}
+
+.padding-content {
+ padding: 4px 0;
+}
+
+a:focus,
+a:active {
+ outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+ cursor: pointer;
+ color: inherit;
+ text-decoration: none;
+}
+
+div:focus {
+ outline: none;
+}
+
+.fr {
+ float: right;
+}
+
+.fl {
+ float: left;
+}
+
+.pr-5 {
+ padding-right: 5px;
+}
+
+.pl-5 {
+ padding-left: 5px;
+}
+
+.block {
+ display: block;
+}
+
+.pointer {
+ cursor: pointer;
+}
+
+.inlineBlock {
+ display: block;
+}
+
+.clearfix {
+ &:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+ }
+}
+
+aside {
+ background: #eef1f6;
+ padding: 8px 24px;
+ margin-bottom: 20px;
+ border-radius: 2px;
+ display: block;
+ line-height: 32px;
+ font-size: 16px;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+ color: #2c3e50;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+ a {
+ color: #337ab7;
+ cursor: pointer;
+
+ &:hover {
+ color: rgb(32, 160, 255);
+ }
+ }
+}
+
+//main-container全局样式
+.app-container {
+ padding: 20px;
+}
+
+.components-container {
+ margin: 30px 50px;
+ position: relative;
+}
+
+.text-center {
+ text-align: center
+}
+
+.sub-navbar {
+ height: 50px;
+ line-height: 50px;
+ position: relative;
+ width: 100%;
+ text-align: right;
+ padding-right: 20px;
+ transition: 600ms ease position;
+ background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
+
+ .subtitle {
+ font-size: 20px;
+ color: #fff;
+ }
+
+ &.draft {
+ background: #d0d0d0;
+ }
+
+ &.deleted {
+ background: #d0d0d0;
+ }
+}
+
+.link-type,
+.link-type:focus {
+ color: #337ab7;
+ cursor: pointer;
+
+ &:hover {
+ color: rgb(32, 160, 255);
+ }
+}
+
+.filter-container {
+ padding-bottom: 10px;
+
+ .filter-item {
+ display: inline-block;
+ vertical-align: middle;
+ margin-bottom: 10px;
+ }
+}
diff --git a/sgd-ui/src/assets/styles/mixin.scss b/sgd-ui/src/assets/styles/mixin.scss
new file mode 100644
index 0000000..06fa061
--- /dev/null
+++ b/sgd-ui/src/assets/styles/mixin.scss
@@ -0,0 +1,66 @@
+@mixin clearfix {
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+}
+
+@mixin scrollBar {
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+}
+
+@mixin relative {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+@mixin pct($pct) {
+ width: #{$pct};
+ position: relative;
+ margin: 0 auto;
+}
+
+@mixin triangle($width, $height, $color, $direction) {
+ $width: $width/2;
+ $color-border-style: $height solid $color;
+ $transparent-border-style: $width solid transparent;
+ height: 0;
+ width: 0;
+
+ @if $direction==up {
+ border-bottom: $color-border-style;
+ border-left: $transparent-border-style;
+ border-right: $transparent-border-style;
+ }
+
+ @else if $direction==right {
+ border-left: $color-border-style;
+ border-top: $transparent-border-style;
+ border-bottom: $transparent-border-style;
+ }
+
+ @else if $direction==down {
+ border-top: $color-border-style;
+ border-left: $transparent-border-style;
+ border-right: $transparent-border-style;
+ }
+
+ @else if $direction==left {
+ border-right: $color-border-style;
+ border-top: $transparent-border-style;
+ border-bottom: $transparent-border-style;
+ }
+}
diff --git a/sgd-ui/src/assets/styles/ruoyi.scss b/sgd-ui/src/assets/styles/ruoyi.scss
new file mode 100644
index 0000000..cb1314d
--- /dev/null
+++ b/sgd-ui/src/assets/styles/ruoyi.scss
@@ -0,0 +1,484 @@
+/**
+* 通用css样式布局处理
+* Copyright (c) 2019 ruoyi
+*/
+
+/** 基础通用 **/
+.pt5 {
+ padding-top: 5px;
+}
+
+.pr5 {
+ padding-right: 5px;
+}
+
+.pb5 {
+ padding-bottom: 5px;
+}
+
+.mt5 {
+ margin-top: 5px;
+}
+
+.mr5 {
+ margin-right: 5px;
+}
+
+.mb5 {
+ margin-bottom: 5px;
+}
+
+.mb8 {
+ margin-bottom: 8px;
+}
+
+.ml5 {
+ margin-left: 5px;
+}
+
+.mt10 {
+ margin-top: 10px;
+}
+
+.mr10 {
+ margin-right: 10px;
+}
+
+.mb10 {
+ margin-bottom: 10px;
+}
+.ml10 {
+ margin-left: 10px;
+}
+
+.mt20 {
+ margin-top: 20px;
+}
+
+.mr20 {
+ margin-right: 20px;
+}
+
+.mb20 {
+ margin-bottom: 20px;
+}
+.ml20 {
+ margin-left: 20px;
+}
+
+.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
+ font-family: inherit;
+ font-weight: 500;
+ line-height: 1.1;
+ color: inherit;
+}
+
+.el-message-box__status + .el-message-box__message{
+ word-break: break-word;
+}
+
+.el-dialog:not(.is-fullscreen) {
+ margin-top: 6vh !important;
+}
+
+.el-dialog__body {
+ padding: 8px 20px !important;
+}
+
+.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
+ overflow: auto;
+ overflow-x: hidden;
+ max-height: 70vh;
+ padding: 10px 20px 0;
+}
+
+.el-table {
+ .el-table__header-wrapper, .el-table__fixed-header-wrapper {
+ th {
+ word-break: break-word;
+ background-color: #f8f8f9;
+ color: #515a6e;
+ height: 40px;
+ font-size: 13px;
+ }
+ }
+
+ .el-table__body-wrapper {
+ .el-button [class*="el-icon-"] + span {
+ margin-left: 1px;
+ }
+ }
+}
+
+/** 表单布局 **/
+.form-header {
+ font-size: 15px;
+ color: #6379bb;
+ border-bottom: 1px solid #ddd;
+ margin: 8px 10px 25px 10px;
+ padding-bottom: 5px
+}
+
+/** 表格布局 **/
+.pagination-container {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 20px;
+}
+
+/* tree border */
+.tree-border {
+ margin-top: 5px;
+ border: 1px solid #e5e6e7;
+ background: #FFFFFF none;
+ border-radius: 4px;
+}
+
+/* horizontal el menu */
+.el-menu--horizontal .el-menu-item .svg-icon + span,
+.el-menu--horizontal .el-submenu__title .svg-icon + span {
+ margin-left: 3px;
+}
+
+.el-menu--horizontal .el-menu--popup {
+ min-width: 120px !important;
+}
+
+@media (max-width: 768px) {
+ .pagination-container .el-pagination > .el-pagination__jump {
+ display: none !important;
+ }
+ .pagination-container .el-pagination > .el-pagination__sizes {
+ display: none !important;
+ }
+}
+
+.el-table .fixed-width .el-button--mini {
+ padding-left: 0;
+ padding-right: 0;
+ width: inherit;
+}
+
+/** 表格更多操作下拉样式 */
+.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
+ cursor: pointer;
+ margin-left: 5px;
+}
+
+.el-table .el-dropdown, .el-icon-arrow-down {
+ font-size: 12px;
+}
+
+.el-tree-node__content > .el-checkbox {
+ margin-right: 8px;
+}
+
+.list-group-striped > .list-group-item {
+ border-left: 0;
+ border-right: 0;
+ border-radius: 0;
+ padding-left: 0;
+ padding-right: 0;
+}
+
+.list-group {
+ padding-left: 0px;
+ list-style: none;
+}
+
+.list-group-item {
+ border-bottom: 1px solid #e7eaec;
+ border-top: 1px solid #e7eaec;
+ margin-bottom: -1px;
+ padding: 11px 0px;
+ font-size: 13px;
+}
+
+.pull-right {
+ float: right !important;
+}
+
+.el-card__header {
+ padding: 14px 15px 7px;
+ min-height: 40px;
+}
+
+.el-card__body {
+ padding: 15px 20px 20px 20px;
+}
+
+.card-box {
+ margin-bottom: 10px;
+}
+
+/* button color */
+.el-button--cyan.is-active,
+.el-button--cyan:active {
+ background: #20B2AA;
+ border-color: #20B2AA;
+ color: #FFFFFF;
+}
+
+.el-button--cyan:focus,
+.el-button--cyan:hover {
+ background: #48D1CC;
+ border-color: #48D1CC;
+ color: #FFFFFF;
+}
+
+.el-button--cyan {
+ background-color: #20B2AA;
+ border-color: #20B2AA;
+ color: #FFFFFF;
+}
+
+/** 详细卡片样式 */
+.detail-drawer {
+ .el-drawer__header {
+ margin-bottom: 6px;
+ padding: 8px 12px 6px;
+ font-size: 15px;
+ color: #303133;
+ background: #f8f8f8;
+ }
+ .section-header {
+ font-size: 15px;
+ color: #6379bb;
+ border-bottom: 1px solid #ddd;
+ margin: 12px 0 16px 0;
+ padding-bottom: 8px;
+ }
+ .drawer-content {
+ padding: 0 20px 20px 20px;
+ .info-item {
+ display: flex;
+ align-items: flex-start;
+ padding: 8px 0;
+ min-height: 40px;
+ }
+ .info-label {
+ flex-shrink: 0;
+ width: 200px;
+ color: #606266;
+ font-size: 13px;
+ line-height: 1.6;
+ padding-top: 4px;
+ text-align: right;
+ margin-right: 14px;
+ }
+ .info-value {
+ flex: 1;
+ color: #303133;
+ font-size: 13px;
+ font-weight: 500;
+ line-height: 1.6;
+ word-break: break-all;
+ padding-top: 4px;
+ min-height: 1.6em;
+ &.plaintext {
+ border-bottom: 1px dashed #dde1e6;
+ }
+ }
+ }
+}
+
+.detail-wrap { padding: 0 4px; }
+
+.detail-card {
+ border: 1px solid #ebeef5;
+ border-radius: 6px;
+ margin-bottom: 14px;
+ overflow: hidden;
+}
+
+.detail-card-title {
+ background: #f7f9fb;
+ padding: 8px 16px;
+ font-size: 13px;
+ font-weight: 600;
+ color: #333;
+ border-bottom: 1px solid #ebeef5;
+}
+.detail-card-title i { margin-right: 5px; color: #409EFF; }
+
+.detail-row { padding: 0 8px; }
+
+.detail-item {
+ display: flex;
+ align-items: flex-start;
+ padding: 10px 8px;
+ font-size: 13px;
+ border-bottom: 1px solid #f5f7fa;
+}
+.detail-item:last-child { border-bottom: none; }
+
+.detail-label {
+ flex-shrink: 0;
+ width: 72px;
+ color: #909399;
+ margin-right: 12px;
+}
+.detail-value { color: #303133; flex: 1; word-break: break-all; }
+.detail-location { color: #999; font-size: 12px; }
+
+.method-tag {
+ display: inline-block;
+ padding: 1px 7px;
+ border-radius: 3px;
+ font-size: 11px;
+ font-weight: 700;
+ margin-right: 6px;
+ vertical-align: middle;
+}
+.mono { font-family: Consolas, 'SFMono-Regular', monospace; font-size: 12px; }
+.code-body { padding: 14px; }
+.code-wrap {
+ background: #f7f9fb;
+ border: 1px solid #e8ecf0;
+ border-radius: 4px;
+ overflow: hidden;
+ max-height: 260px;
+ position: relative;
+}
+.code-action {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ z-index: 10;
+ margin: 0;
+ padding: 0;
+}
+.code-action .el-button {
+ height: 24px;
+ font-size: 12px;
+ padding: 4px 8px;
+ background: rgba(255, 255, 255, 0.9);
+ border: 1px solid #dcdcdc;
+}
+.code-action .el-button:hover {
+ background: #ffffff;
+ border-color: #409EFF;
+}
+.code-pre {
+ margin: 0;
+ padding: 12px 14px;
+ font-size: 12px;
+ line-height: 1.6;
+ font-family: Consolas, 'SFMono-Regular', monospace;
+ color: #444;
+ white-space: pre-wrap;
+ word-break: break-all;
+ overflow: auto;
+ max-height: 240px;
+ display: block;
+}
+
+/* tree-sidebar content */
+.tree-sidebar-manage-wrap {
+ display: flex;
+ gap: 0;
+ min-height: calc(100vh - 130px);
+ padding: 0 !important;
+ overflow: hidden;
+}
+
+.tree-sidebar-content {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ background: #fff;
+
+ .content-inner {
+ padding: 12px 16px;
+ height: 100%;
+ overflow-y: auto;
+ }
+}
+
+/* error */
+.error-title { color: #c0392b !important; }
+.error-title i { color: #c0392b !important; }
+.error-body { padding: 12px 16px; }
+.error-msg {
+ background: #fff8f8;
+ border-left: 3px solid #e74c3c;
+ border-radius: 3px;
+ padding: 8px 12px;
+ color: #c0392b;
+ font-size: 12px;
+ line-height: 1.7;
+ word-break: break-all;
+ white-space: pre-wrap;
+}
+
+/* http method */
+.method-GET { background: #e8f5e9; color: #27ae60; }
+.method-POST { background: #e3f2fd; color: #1565c0; }
+.method-PUT { background: #fff3e0; color: #e65100; }
+.method-DELETE { background: #ffebee; color: #c62828; }
+
+/* text color */
+.text-navy {
+ color: #1ab394;
+}
+
+.text-primary {
+ color: inherit;
+}
+
+.text-success {
+ color: #1c84c6;
+}
+
+.text-info {
+ color: #23c6c8;
+}
+
+.text-warning {
+ color: #f8ac59;
+}
+
+.text-danger {
+ color: #ed5565;
+}
+
+.text-muted {
+ color: #888888;
+}
+
+/* image */
+.img-circle {
+ border-radius: 50%;
+}
+
+.img-lg {
+ width: 120px;
+ height: 120px;
+}
+
+.avatar-upload-preview {
+ position: relative;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 200px;
+ height: 200px;
+ border-radius: 50%;
+ box-shadow: 0 0 4px #ccc;
+ overflow: hidden;
+}
+
+/* 拖拽列样式 */
+.allowDrag { cursor: grab; }
+.allowDrag:active { cursor: grabbing; }
+
+.sortable-ghost {
+ opacity: .8;
+ color: #fff !important;
+ background: #42b983 !important;
+}
+
+.top-right-btn {
+ position: relative;
+ float: right;
+}
diff --git a/sgd-ui/src/assets/styles/sidebar.scss b/sgd-ui/src/assets/styles/sidebar.scss
new file mode 100644
index 0000000..3e3c473
--- /dev/null
+++ b/sgd-ui/src/assets/styles/sidebar.scss
@@ -0,0 +1,321 @@
+#app {
+
+ .main-container {
+ height: 100%;
+ transition: margin-left .28s;
+ margin-left: $base-sidebar-width;
+ position: relative;
+ }
+
+ .sidebarHide {
+ margin-left: 0!important;
+ }
+
+ .sidebar-container {
+ -webkit-transition: width .28s;
+ transition: width 0.28s;
+ width: $base-sidebar-width !important;
+ background-color: $base-menu-background;
+ height: 100%;
+ position: fixed;
+ font-size: 0px;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1001;
+ overflow: hidden;
+ -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
+ box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
+
+ // reset element-ui css
+ .horizontal-collapse-transition {
+ transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+ }
+
+ .scrollbar-wrapper {
+ overflow-x: hidden !important;
+ }
+
+ .el-scrollbar__bar.is-vertical {
+ right: 0px;
+ }
+
+ .el-scrollbar {
+ height: 100%;
+ }
+
+ &.has-logo {
+ .el-scrollbar {
+ height: calc(100% - 50px);
+ }
+ }
+
+ .is-horizontal {
+ display: none;
+ }
+
+ a {
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ }
+
+ .svg-icon {
+ margin-right: 10px !important;
+ }
+
+ .el-menu {
+ border: none;
+ height: 100%;
+ width: 100% !important;
+ }
+
+ .el-menu-item, .el-submenu__title {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ height: 44px !important;
+ line-height: 44px !important;
+ }
+
+ // menu hover
+ .submenu-title-noDropdown,
+ .el-submenu__title {
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.06) !important;
+ }
+ }
+
+ & .theme-dark .is-active > .el-submenu__title {
+ color: $base-menu-color-active !important;
+ }
+
+ & .nest-menu .el-submenu>.el-submenu__title,
+ & .el-submenu .el-menu-item {
+ min-width: $base-sidebar-width !important;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.06) !important;
+ }
+ }
+
+ & .theme-dark .nest-menu .el-submenu>.el-submenu__title,
+ & .theme-dark .el-submenu .el-menu-item {
+ background-color: $base-sub-menu-background !important;
+
+ &:hover {
+ background-color: $base-sub-menu-hover !important;
+ }
+ }
+
+ // theme-dark 深色主题
+ &.theme-dark {
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.4);
+ border-right: none;
+
+ .el-menu-item.is-active {
+ position: relative;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
+ border-right: 3px solid var(--current-color, #409eff);
+ pointer-events: none;
+ z-index: 1;
+ }
+ }
+
+ .el-submenu.is-active > .el-submenu__title {
+ color: var(--current-color, #409eff) !important;
+ }
+
+ .el-menu-item:not(.is-active),
+ .submenu-title-noDropdown,
+ .el-submenu__title {
+ position: relative;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-color: transparent;
+ pointer-events: none;
+ z-index: 1;
+ transition: background-color 0.2s;
+ }
+
+ &:hover::before {
+ background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
+ }
+ }
+ }
+
+ // theme-light 浅色主题
+ &.theme-light {
+ border-right: 1px solid #e8eaf0;
+ box-shadow: none;
+
+ .el-menu-item,
+ .el-submenu__title {
+ color: rgba(0, 0, 0, 0.65);
+ }
+
+ .el-menu-item.is-active {
+ color: var(--current-color, #409eff) !important;
+ position: relative;
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-color: var(--current-color-light, #ecf5ff);
+ border-right: 3px solid var(--current-color, #409eff);
+ pointer-events: none;
+ z-index: 1;
+ }
+ }
+
+ .el-submenu.is-active > .el-submenu__title {
+ color: var(--current-color, #409eff) !important;
+ }
+
+ .el-menu-item:not(.is-active):hover,
+ .submenu-title-noDropdown:hover,
+ .el-submenu__title:hover {
+ background-color: #f5f7fa !important;
+ color: rgba(0, 0, 0, 0.85) !important;
+ }
+
+ .nest-menu .el-submenu > .el-submenu__title,
+ .el-submenu .el-menu-item {
+ background-color: #fafafa !important;
+
+ &:hover {
+ background-color: #f0f5ff !important;
+ }
+ }
+ }
+ }
+
+ .hideSidebar {
+ .sidebar-container {
+ width: 54px !important;
+ }
+
+ .main-container {
+ margin-left: 54px;
+ }
+
+ .el-menu:not(.el-menu--horizontal) {
+ .submenu-title-noDropdown {
+ padding: 0 !important;
+ position: relative;
+
+ .el-tooltip {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+ }
+ }
+ }
+
+ .el-submenu {
+ overflow: hidden;
+
+ &>.el-submenu__title {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+
+ }
+ }
+
+ .el-menu--collapse {
+ .el-submenu {
+ &>.el-submenu__title {
+ &>span {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ display: inline-block;
+ }
+ }
+ }
+ }
+ }
+
+ .el-menu--collapse .el-menu .el-submenu {
+ min-width: $base-sidebar-width !important;
+ }
+
+ // mobile responsive
+ .mobile {
+ .main-container {
+ margin-left: 0px;
+ }
+
+ .sidebar-container {
+ transition: transform .28s;
+ width: $base-sidebar-width !important;
+ }
+
+ &.hideSidebar {
+ .sidebar-container {
+ pointer-events: none;
+ transition-duration: 0.3s;
+ transform: translate3d(-$base-sidebar-width, 0, 0);
+ }
+ }
+ }
+
+ .withoutAnimation {
+
+ .main-container,
+ .sidebar-container {
+ transition: none;
+ }
+ }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+ &>.el-menu {
+ .svg-icon {
+ margin-right: 16px;
+ }
+ }
+
+ .nest-menu .el-submenu>.el-submenu__title,
+ .el-menu-item {
+ &:hover {
+ // you can use $subMenuHover
+ background-color: rgba(0, 0, 0, 0.06) !important;
+ }
+ }
+
+ // the scroll bar appears when the subMenu is too long
+ >.el-menu--popup {
+ max-height: 100vh;
+ overflow-y: auto;
+
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+ }
+}
diff --git a/sgd-ui/src/assets/styles/transition.scss b/sgd-ui/src/assets/styles/transition.scss
new file mode 100644
index 0000000..073f8c6
--- /dev/null
+++ b/sgd-ui/src/assets/styles/transition.scss
@@ -0,0 +1,49 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+ opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform--move,
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+ transition: all .5s;
+}
+
+.fade-transform-enter {
+ opacity: 0;
+ transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+ opacity: 0;
+ transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+ transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+ opacity: 0;
+ transform: translateX(20px);
+}
+
+.breadcrumb-move {
+ transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+ position: absolute;
+}
diff --git a/sgd-ui/src/assets/styles/variables.scss b/sgd-ui/src/assets/styles/variables.scss
new file mode 100644
index 0000000..b5d6699
--- /dev/null
+++ b/sgd-ui/src/assets/styles/variables.scss
@@ -0,0 +1,39 @@
+// base color
+$blue:#324157;
+$light-blue:#3A71A8;
+$red:#C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow:#FEC171;
+$panGreen: #30B08F;
+
+// 默认菜单主题风格
+$base-menu-color: #bfcbd9;
+$base-menu-color-active: #ffffff;
+$base-menu-background: #1a1f2e;
+$base-logo-title-color: #ffffff;
+
+$base-menu-light-color:rgba(0,0,0,.70);
+$base-menu-light-background:#ffffff;
+$base-logo-light-title-color: #001529;
+
+$base-sub-menu-background: #141824;
+$base-sub-menu-hover: rgba(255,255,255,.06);
+
+$base-sidebar-width: 200px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+ menuColor: $base-menu-color;
+ menuLightColor: $base-menu-light-color;
+ menuColorActive: $base-menu-color-active;
+ menuBackground: $base-menu-background;
+ menuLightBackground: $base-menu-light-background;
+ subMenuBackground: $base-sub-menu-background;
+ subMenuHover: $base-sub-menu-hover;
+ sideBarWidth: $base-sidebar-width;
+ logoTitleColor: $base-logo-title-color;
+ logoLightTitleColor: $base-logo-light-title-color
+}
diff --git a/sgd-ui/src/components/Breadcrumb/index.vue b/sgd-ui/src/components/Breadcrumb/index.vue
new file mode 100644
index 0000000..84f4831
--- /dev/null
+++ b/sgd-ui/src/components/Breadcrumb/index.vue
@@ -0,0 +1,102 @@
+<template>
+ <el-breadcrumb class="app-breadcrumb" separator="/">
+ <transition-group name="breadcrumb">
+ <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
+ <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
+ <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+ </el-breadcrumb-item>
+ </transition-group>
+ </el-breadcrumb>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ levelList: null
+ }
+ },
+ watch: {
+ $route(route) {
+ // if you go to the redirect page, do not update the breadcrumbs
+ if (route.path.startsWith('/redirect/')) {
+ return
+ }
+ this.getBreadcrumb()
+ }
+ },
+ created() {
+ this.getBreadcrumb()
+ },
+ methods: {
+ getBreadcrumb() {
+ // only show routes with meta.title
+ let matched = []
+ const router = this.$route
+ const pathNum = this.findPathNum(router.path)
+ // multi-level menu
+ if (pathNum > 2) {
+ const reg = /\/\w+/gi
+ const pathList = router.path.match(reg).map((item, index) => {
+ if (index !== 0) item = item.slice(1)
+ return item
+ })
+ this.getMatched(pathList, this.$store.getters.defaultRoutes, matched)
+ } else {
+ matched = router.matched.filter(item => item.meta && item.meta.title)
+ }
+ // 判断是否为首页
+ if (!this.isDashboard(matched[0])) {
+ matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
+ }
+ this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+ },
+ findPathNum(str, char = "/") {
+ let index = str.indexOf(char)
+ let num = 0
+ while (index !== -1) {
+ num++
+ index = str.indexOf(char, index + 1)
+ }
+ return num
+ },
+ getMatched(pathList, routeList, matched) {
+ let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0])
+ if (data) {
+ matched.push(data)
+ if (data.children && pathList.length) {
+ pathList.shift()
+ this.getMatched(pathList, data.children, matched)
+ }
+ }
+ },
+ isDashboard(route) {
+ const name = route && route.name
+ if (!name) {
+ return false
+ }
+ return name.trim() === 'Index'
+ },
+ handleLink(item) {
+ const { redirect, path } = item
+ if (redirect) {
+ this.$router.push(redirect)
+ return
+ }
+ this.$router.push(path)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+ display: inline-block;
+ font-size: 14px;
+ line-height: 50px;
+ .no-redirect {
+ color: #97a8be;
+ cursor: text;
+ }
+}
+</style>
diff --git a/ruoyi-ui/src/components/Crontab/day.vue b/sgd-ui/src/components/Crontab/day.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/day.vue
rename to sgd-ui/src/components/Crontab/day.vue
diff --git a/ruoyi-ui/src/components/Crontab/hour.vue b/sgd-ui/src/components/Crontab/hour.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/hour.vue
rename to sgd-ui/src/components/Crontab/hour.vue
diff --git a/ruoyi-ui/src/components/Crontab/index.vue b/sgd-ui/src/components/Crontab/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/index.vue
rename to sgd-ui/src/components/Crontab/index.vue
diff --git a/ruoyi-ui/src/components/Crontab/min.vue b/sgd-ui/src/components/Crontab/min.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/min.vue
rename to sgd-ui/src/components/Crontab/min.vue
diff --git a/sgd-ui/src/components/Crontab/month.vue b/sgd-ui/src/components/Crontab/month.vue
new file mode 100644
index 0000000..da60132
--- /dev/null
+++ b/sgd-ui/src/components/Crontab/month.vue
@@ -0,0 +1,114 @@
+<template>
+ <el-form size='small'>
+ <el-form-item>
+ <el-radio v-model='radioValue' :label="1">
+ 月,允许的通配符[, - * /]
+ </el-radio>
+ </el-form-item>
+
+ <el-form-item>
+ <el-radio v-model='radioValue' :label="2">
+ 周期从
+ <el-input-number v-model='cycle01' :min="1" :max="11" /> -
+ <el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> 月
+ </el-radio>
+ </el-form-item>
+
+ <el-form-item>
+ <el-radio v-model='radioValue' :label="3">
+ 从
+ <el-input-number v-model='average01' :min="1" :max="11" /> 月开始,每
+ <el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> 月月执行一次
+ </el-radio>
+ </el-form-item>
+
+ <el-form-item>
+ <el-radio v-model='radioValue' :label="4">
+ 指定
+ <el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
+ <el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option>
+ </el-select>
+ </el-radio>
+ </el-form-item>
+ </el-form>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ radioValue: 1,
+ cycle01: 1,
+ cycle02: 2,
+ average01: 1,
+ average02: 1,
+ checkboxList: [],
+ checkNum: this.check
+ }
+ },
+ name: 'crontab-month',
+ props: ['check', 'cron'],
+ methods: {
+ // 单选按钮值变化时
+ radioChange() {
+ switch (this.radioValue) {
+ case 1:
+ this.$emit('update', 'month', '*')
+ break
+ case 2:
+ this.$emit('update', 'month', this.cycleTotal)
+ break
+ case 3:
+ this.$emit('update', 'month', this.averageTotal)
+ break
+ case 4:
+ this.$emit('update', 'month', this.checkboxString)
+ break
+ }
+ },
+ // 周期两个值变化时
+ cycleChange() {
+ if (this.radioValue == '2') {
+ this.$emit('update', 'month', this.cycleTotal)
+ }
+ },
+ // 平均两个值变化时
+ averageChange() {
+ if (this.radioValue == '3') {
+ this.$emit('update', 'month', this.averageTotal)
+ }
+ },
+ // checkbox值变化时
+ checkboxChange() {
+ if (this.radioValue == '4') {
+ this.$emit('update', 'month', this.checkboxString)
+ }
+ }
+ },
+ watch: {
+ 'radioValue': 'radioChange',
+ 'cycleTotal': 'cycleChange',
+ 'averageTotal': 'averageChange',
+ 'checkboxString': 'checkboxChange'
+ },
+ computed: {
+ // 计算两个周期值
+ cycleTotal: function () {
+ const cycle01 = this.checkNum(this.cycle01, 1, 11)
+ const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
+ return cycle01 + '-' + cycle02
+ },
+ // 计算平均用到的值
+ averageTotal: function () {
+ const average01 = this.checkNum(this.average01, 1, 11)
+ const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
+ return average01 + '/' + average02
+ },
+ // 计算勾选的checkbox值合集
+ checkboxString: function () {
+ let str = this.checkboxList.join()
+ return str == '' ? '*' : str
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/result.vue b/sgd-ui/src/components/Crontab/result.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/result.vue
rename to sgd-ui/src/components/Crontab/result.vue
diff --git a/ruoyi-ui/src/components/Crontab/second.vue b/sgd-ui/src/components/Crontab/second.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/second.vue
rename to sgd-ui/src/components/Crontab/second.vue
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/sgd-ui/src/components/Crontab/week.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/week.vue
rename to sgd-ui/src/components/Crontab/week.vue
diff --git a/ruoyi-ui/src/components/Crontab/year.vue b/sgd-ui/src/components/Crontab/year.vue
similarity index 100%
rename from ruoyi-ui/src/components/Crontab/year.vue
rename to sgd-ui/src/components/Crontab/year.vue
diff --git a/sgd-ui/src/components/DictData/index.js b/sgd-ui/src/components/DictData/index.js
new file mode 100644
index 0000000..7b85d4a
--- /dev/null
+++ b/sgd-ui/src/components/DictData/index.js
@@ -0,0 +1,49 @@
+import Vue from 'vue'
+import store from '@/store'
+import DataDict from '@/utils/dict'
+import { getDicts as getDicts } from '@/api/system/dict/data'
+
+function searchDictByKey(dict, key) {
+ if (key == null && key == "") {
+ return null
+ }
+ try {
+ for (let i = 0; i < dict.length; i++) {
+ if (dict[i].key == key) {
+ return dict[i].value
+ }
+ }
+ } catch (e) {
+ return null
+ }
+}
+
+function install() {
+ Vue.use(DataDict, {
+ metas: {
+ '*': {
+ labelField: 'dictLabel',
+ valueField: 'dictValue',
+ request(dictMeta) {
+ const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
+ if (storeDict) {
+ return new Promise(resolve => { resolve(storeDict) })
+ } else {
+ return new Promise((resolve, reject) => {
+ getDicts(dictMeta.type).then(res => {
+ store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
+ resolve(res.data)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ }
+ },
+ },
+ },
+ })
+}
+
+export default {
+ install,
+}
\ No newline at end of file
diff --git a/sgd-ui/src/components/DictTag/index.vue b/sgd-ui/src/components/DictTag/index.vue
new file mode 100644
index 0000000..7c86744
--- /dev/null
+++ b/sgd-ui/src/components/DictTag/index.vue
@@ -0,0 +1,93 @@
+<template>
+ <div>
+ <template v-for="(item, index) in options">
+ <template v-if="isValueMatch(item.value)">
+ <span
+ v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
+ :key="item.value"
+ :index="index"
+ :class="item.raw.cssClass"
+ >{{ item.label + ' ' }}</span
+ >
+ <el-tag
+ v-else
+ :disable-transitions="true"
+ :key="item.value"
+ :index="index"
+ :type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
+ :class="item.raw.cssClass"
+ >
+ {{ item.label + ' ' }}
+ </el-tag>
+ </template>
+ </template>
+ <template v-if="unmatch && showValue">
+ {{ unmatchArray | handleArray }}
+ </template>
+ </div>
+</template>
+
+<script>
+export default {
+ name: "DictTag",
+ props: {
+ options: {
+ type: Array,
+ default: null,
+ },
+ value: [Number, String, Array],
+ showValue: {
+ type: Boolean,
+ default: true,
+ },
+ separator: {
+ type: String,
+ default: ","
+ }
+ },
+ data() {
+ return {
+ unmatchArray: [], // 记录未匹配的项
+ }
+ },
+ computed: {
+ values() {
+ if (this.value === null || typeof this.value === 'undefined' || this.value === '') return []
+ if (typeof this.value === 'number' || typeof this.value === 'boolean') return [this.value]
+ return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator)
+ },
+ unmatch() {
+ this.unmatchArray = []
+ // 没有value不显示
+ if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false
+ // 传入值为数组
+ let unmatch = false // 添加一个标志来判断是否有未匹配项
+ this.values.forEach(item => {
+ if (!this.options.some(v => v.value == item)) {
+ this.unmatchArray.push(item)
+ unmatch = true // 如果有未匹配项,将标志设置为true
+ }
+ })
+ return unmatch // 返回标志的值
+ },
+ },
+ methods: {
+ isValueMatch(itemValue) {
+ return this.values.some(val => val == itemValue)
+ }
+ },
+ filters: {
+ handleArray(array) {
+ if (array.length === 0) return ''
+ return array.reduce((pre, cur) => {
+ return pre + ' ' + cur
+ })
+ },
+ }
+}
+</script>
+<style scoped>
+.el-tag + .el-tag {
+ margin-left: 10px;
+}
+</style>
diff --git a/sgd-ui/src/components/Editor/index.vue b/sgd-ui/src/components/Editor/index.vue
new file mode 100644
index 0000000..61fe98e
--- /dev/null
+++ b/sgd-ui/src/components/Editor/index.vue
@@ -0,0 +1,297 @@
+<template>
+ <div>
+ <el-upload
+ :action="uploadUrl"
+ :before-upload="handleBeforeUpload"
+ :on-success="handleUploadSuccess"
+ :on-error="handleUploadError"
+ name="file"
+ :show-file-list="false"
+ :headers="headers"
+ style="display: none"
+ ref="upload"
+ v-if="this.type == 'url'"
+ >
+ </el-upload>
+ <div class="editor" ref="editor" :style="styles"></div>
+ </div>
+</template>
+
+<script>
+import axios from "axios"
+import Quill from "quill"
+import "quill/dist/quill.core.css"
+import "quill/dist/quill.snow.css"
+import "quill/dist/quill.bubble.css"
+import { getToken } from "@/utils/auth"
+
+export default {
+ name: "Editor",
+ props: {
+ /* 编辑器的内容 */
+ value: {
+ type: String,
+ default: "",
+ },
+ /* 高度 */
+ height: {
+ type: Number,
+ default: null,
+ },
+ /* 最小高度 */
+ minHeight: {
+ type: Number,
+ default: null,
+ },
+ /* 只读 */
+ readOnly: {
+ type: Boolean,
+ default: false,
+ },
+ /* 上传文件大小限制(MB) */
+ fileSize: {
+ type: Number,
+ default: 5,
+ },
+ /* 类型(base64格式、url格式) */
+ type: {
+ type: String,
+ default: "url",
+ }
+ },
+ data() {
+ return {
+ uploadUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
+ headers: {
+ Authorization: "Bearer " + getToken()
+ },
+ Quill: null,
+ currentValue: "",
+ options: {
+ theme: "snow",
+ bounds: document.body,
+ debug: "warn",
+ modules: {
+ // 工具栏配置
+ toolbar: [
+ ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
+ ["blockquote", "code-block"], // 引用 代码块
+ [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
+ [{ indent: "-1" }, { indent: "+1" }], // 缩进
+ [{ size: ["small", false, "large", "huge"] }], // 字体大小
+ [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
+ [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
+ [{ align: [] }], // 对齐方式
+ ["clean"], // 清除文本格式
+ ["link", "image", "video"] // 链接、图片、视频
+ ],
+ },
+ placeholder: "请输入内容",
+ readOnly: this.readOnly,
+ },
+ }
+ },
+ computed: {
+ styles() {
+ let style = {}
+ if (this.minHeight) {
+ style.minHeight = `${this.minHeight}px`
+ }
+ if (this.height) {
+ style.height = `${this.height}px`
+ }
+ return style
+ }
+ },
+ watch: {
+ value: {
+ handler(val) {
+ if (val !== this.currentValue) {
+ this.currentValue = val === null ? "" : val
+ if (this.Quill) {
+ this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
+ }
+ }
+ },
+ immediate: true,
+ },
+ },
+ mounted() {
+ this.init()
+ },
+ beforeDestroy() {
+ this.Quill = null
+ },
+ methods: {
+ init() {
+ const editor = this.$refs.editor
+ this.Quill = new Quill(editor, this.options)
+ // 如果设置了上传地址则自定义图片上传事件
+ if (this.type == 'url') {
+ let toolbar = this.Quill.getModule("toolbar")
+ toolbar.addHandler("image", (value) => {
+ if (value) {
+ this.$refs.upload.$children[0].$refs.input.click()
+ } else {
+ this.quill.format("image", false)
+ }
+ })
+ this.Quill.root.addEventListener('paste', this.handlePasteCapture, true)
+ }
+ this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
+ this.Quill.on("text-change", (delta, oldDelta, source) => {
+ const html = this.$refs.editor.children[0].innerHTML
+ const text = this.Quill.getText()
+ const quill = this.Quill
+ this.currentValue = html
+ this.$emit("input", html)
+ this.$emit("on-change", { html, text, quill })
+ })
+ this.Quill.on("text-change", (delta, oldDelta, source) => {
+ this.$emit("on-text-change", delta, oldDelta, source)
+ })
+ this.Quill.on("selection-change", (range, oldRange, source) => {
+ this.$emit("on-selection-change", range, oldRange, source)
+ })
+ this.Quill.on("editor-change", (eventName, ...args) => {
+ this.$emit("on-editor-change", eventName, ...args)
+ })
+ },
+ // 上传前校检格式和大小
+ handleBeforeUpload(file) {
+ const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]
+ const isJPG = type.includes(file.type)
+ // 检验文件格式
+ if (!isJPG) {
+ this.$message.error(`图片格式错误!`)
+ return false
+ }
+ // 校检文件大小
+ if (this.fileSize) {
+ const isLt = file.size / 1024 / 1024 < this.fileSize
+ if (!isLt) {
+ this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`)
+ return false
+ }
+ }
+ return true
+ },
+ handleUploadSuccess(res, file) {
+ // 如果上传成功
+ if (res.code == 200) {
+ // 获取富文本组件实例
+ let quill = this.Quill
+ // 获取光标所在位置
+ let length = quill.getSelection().index
+ // 插入图片 res.url为服务器返回的图片地址
+ quill.insertEmbed(length, "image", res.data.url)
+ // 调整光标到最后
+ quill.setSelection(length + 1)
+ } else {
+ this.$message.error("图片插入失败")
+ }
+ },
+ handleUploadError() {
+ this.$message.error("图片插入失败")
+ },
+ // 复制粘贴图片处理
+ handlePasteCapture(e) {
+ const clipboard = e.clipboardData || window.clipboardData
+ if (clipboard && clipboard.items) {
+ for (let i = 0; i < clipboard.items.length; i++) {
+ const item = clipboard.items[i]
+ if (item.type.indexOf('image') !== -1) {
+ e.preventDefault()
+ const file = item.getAsFile()
+ this.insertImage(file)
+ }
+ }
+ }
+ },
+ insertImage(file) {
+ const formData = new FormData()
+ formData.append("file", file)
+ axios.post(this.uploadUrl, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: this.headers.Authorization } }).then(res => {
+ this.handleUploadSuccess(res.data)
+ })
+ }
+ }
+}
+</script>
+
+<style>
+.editor, .ql-toolbar {
+ white-space: pre-wrap !important;
+ line-height: normal !important;
+}
+.quill-img {
+ display: none;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+ content: "请输入链接地址:";
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+ border-right: 0px;
+ content: "保存";
+ padding-right: 0px;
+}
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+ content: "请输入视频地址:";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+ content: "14px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+ content: "10px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+ content: "18px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+ content: "32px";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+ content: "文本";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+ content: "标题1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+ content: "标题2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+ content: "标题3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+ content: "标题4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+ content: "标题5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+ content: "标题6";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+ content: "标准字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+ content: "衬线字体";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+ content: "等宽字体";
+}
+</style>
diff --git a/ruoyi-ui/src/components/ExcelImportDialog/index.vue b/sgd-ui/src/components/ExcelImportDialog/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/ExcelImportDialog/index.vue
rename to sgd-ui/src/components/ExcelImportDialog/index.vue
diff --git a/sgd-ui/src/components/FileUpload/index.vue b/sgd-ui/src/components/FileUpload/index.vue
new file mode 100644
index 0000000..2678bc0
--- /dev/null
+++ b/sgd-ui/src/components/FileUpload/index.vue
@@ -0,0 +1,261 @@
+<template>
+ <div class="upload-file">
+ <el-upload
+ multiple
+ :action="uploadFileUrl"
+ :before-upload="handleBeforeUpload"
+ :file-list="fileList"
+ :data="data"
+ :limit="limit"
+ :on-error="handleUploadError"
+ :on-exceed="handleExceed"
+ :on-success="handleUploadSuccess"
+ :show-file-list="false"
+ :headers="headers"
+ class="upload-file-uploader"
+ ref="fileUpload"
+ v-if="!disabled"
+ >
+ <!-- 上传按钮 -->
+ <el-button size="mini" type="primary">选取文件</el-button>
+ <!-- 上传提示 -->
+ <div class="el-upload__tip" slot="tip" v-if="showTip">
+ 请上传
+ <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+ <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+ 的文件
+ </div>
+ </el-upload>
+
+ <!-- 文件列表 -->
+ <transition-group ref="uploadFileList" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+ <li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
+ <el-link :href="file.url" :underline="false" target="_blank">
+ <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+ </el-link>
+ <div class="ele-upload-list__item-content-action">
+ <el-link :underline="false" @click="handleDelete(index)" type="danger" v-if="!disabled">删除</el-link>
+ </div>
+ </li>
+ </transition-group>
+ </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth"
+import Sortable from 'sortablejs'
+
+export default {
+ name: "FileUpload",
+ props: {
+ // 值
+ value: [String, Object, Array],
+ // 上传接口地址
+ action: {
+ type: String,
+ default: "/file/upload"
+ },
+ // 上传携带的参数
+ data: {
+ type: Object
+ },
+ // 数量限制
+ limit: {
+ type: Number,
+ default: 5
+ },
+ // 大小限制(MB)
+ fileSize: {
+ type: Number,
+ default: 5
+ },
+ // 文件类型, 例如['png', 'jpg', 'jpeg']
+ fileType: {
+ type: Array,
+ default: () => ["doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "pdf"]
+ },
+ // 是否显示提示
+ isShowTip: {
+ type: Boolean,
+ default: true
+ },
+ // 禁用组件(仅查看文件)
+ disabled: {
+ type: Boolean,
+ default: false
+ },
+ // 拖动排序
+ drag: {
+ type: Boolean,
+ default: true
+ }
+ },
+ data() {
+ return {
+ number: 0,
+ uploadList: [],
+ uploadFileUrl: process.env.VUE_APP_BASE_API + this.action, // 上传文件服务器地址
+ headers: {
+ Authorization: "Bearer " + getToken(),
+ },
+ fileList: []
+ }
+ },
+ mounted() {
+ if (this.drag && !this.disabled) {
+ this.$nextTick(() => {
+ const element = this.$refs.uploadFileList?.$el || this.$refs.uploadFileList
+ Sortable.create(element, {
+ ghostClass: 'file-upload-darg',
+ onEnd: (evt) => {
+ const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
+ this.fileList.splice(evt.newIndex, 0, movedItem)
+ this.$emit("input", this.listToString(this.fileList))
+ }
+ })
+ })
+ }
+ },
+ watch: {
+ value: {
+ handler(val) {
+ if (val) {
+ let temp = 1
+ // 首先将值转为数组
+ const list = Array.isArray(val) ? val : this.value.split(',')
+ // 然后将数组转为对象数组
+ this.fileList = list.map(item => {
+ if (typeof item === "string") {
+ item = { name: item, url: item }
+ }
+ item.uid = item.uid || new Date().getTime() + temp++
+ return item
+ })
+ } else {
+ this.fileList = []
+ return []
+ }
+ },
+ deep: true,
+ immediate: true
+ }
+ },
+ computed: {
+ // 是否显示提示
+ showTip() {
+ return this.isShowTip && (this.fileType || this.fileSize)
+ },
+ },
+ methods: {
+ // 上传前校检格式和大小
+ handleBeforeUpload(file) {
+ // 校检文件类型
+ if (this.fileType) {
+ const fileName = file.name.split('.')
+ const fileExt = fileName[fileName.length - 1]
+ const isTypeOk = this.fileType.indexOf(fileExt) >= 0
+ if (!isTypeOk) {
+ this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}格式文件!`)
+ return false
+ }
+ }
+ // 校检文件名是否包含特殊字符
+ if (file.name.includes(',')) {
+ this.$modal.msgError('文件名不正确,不能包含英文逗号!')
+ return false
+ }
+ // 校检文件大小
+ if (this.fileSize) {
+ const isLt = file.size / 1024 / 1024 < this.fileSize
+ if (!isLt) {
+ this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`)
+ return false
+ }
+ }
+ this.$modal.loading("正在上传文件,请稍候...")
+ this.number++
+ return true
+ },
+ // 文件个数超出
+ handleExceed() {
+ this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
+ },
+ // 上传失败
+ handleUploadError(err) {
+ this.$modal.msgError("上传文件失败,请重试")
+ this.$modal.closeLoading()
+ },
+ // 上传成功回调
+ handleUploadSuccess(res, file) {
+ if (res.code === 200) {
+ this.uploadList.push({ name: res.data.url, url: res.data.url })
+ this.uploadedSuccessfully()
+ } else {
+ this.number--
+ this.$modal.closeLoading()
+ this.$modal.msgError(res.msg)
+ this.$refs.fileUpload.handleRemove(file)
+ this.uploadedSuccessfully()
+ }
+ },
+ // 删除文件
+ handleDelete(index) {
+ this.fileList.splice(index, 1)
+ this.$emit("input", this.listToString(this.fileList))
+ },
+ // 上传结束处理
+ uploadedSuccessfully() {
+ if (this.number > 0 && this.uploadList.length === this.number) {
+ this.fileList = this.fileList.concat(this.uploadList)
+ this.uploadList = []
+ this.number = 0
+ this.$emit("input", this.listToString(this.fileList))
+ this.$modal.closeLoading()
+ }
+ },
+ // 获取文件名称
+ getFileName(name) {
+ // 如果是url那么取最后的名字 如果不是直接返回
+ if (name.lastIndexOf("/") > -1) {
+ return name.slice(name.lastIndexOf("/") + 1)
+ } else {
+ return name
+ }
+ },
+ // 对象转成指定字符串分隔
+ listToString(list, separator) {
+ let strs = ""
+ separator = separator || ","
+ for (let i in list) {
+ strs += list[i].url + separator
+ }
+ return strs != '' ? strs.substr(0, strs.length - 1) : ''
+ }
+ }
+}
+</script>
+
+<style scoped lang="scss">
+.file-upload-darg {
+ opacity: 0.5;
+ background: #c8ebfb;
+}
+.upload-file-uploader {
+ margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+ border: 1px solid #e4e7ed;
+ line-height: 2;
+ margin-bottom: 10px;
+ position: relative;
+}
+.upload-file-list .ele-upload-list__item-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+ margin-right: 10px;
+}
+</style>
\ No newline at end of file
diff --git a/sgd-ui/src/components/Hamburger/index.vue b/sgd-ui/src/components/Hamburger/index.vue
new file mode 100644
index 0000000..368b002
--- /dev/null
+++ b/sgd-ui/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+<template>
+ <div style="padding: 0 15px;" @click="toggleClick">
+ <svg
+ :class="{'is-active':isActive}"
+ class="hamburger"
+ viewBox="0 0 1024 1024"
+ xmlns="http://www.w3.org/2000/svg"
+ width="64"
+ height="64"
+ >
+ <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+ </svg>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'Hamburger',
+ props: {
+ isActive: {
+ type: Boolean,
+ default: false
+ }
+ },
+ methods: {
+ toggleClick() {
+ this.$emit('toggleClick')
+ }
+ }
+}
+</script>
+
+<style scoped>
+.hamburger {
+ display: inline-block;
+ vertical-align: middle;
+ width: 20px;
+ height: 20px;
+}
+
+.hamburger.is-active {
+ transform: rotate(180deg);
+}
+</style>
diff --git a/sgd-ui/src/components/HeaderSearch/index.vue b/sgd-ui/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..93f71ea
--- /dev/null
+++ b/sgd-ui/src/components/HeaderSearch/index.vue
@@ -0,0 +1,397 @@
+<template>
+ <div class="header-search">
+ <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+ <el-dialog
+ :visible.sync="show"
+ width="600px"
+ @close="close"
+ @opened="onDialogOpened"
+ :show-close="false"
+ append-to-body
+ >
+ <el-input
+ v-model="search"
+ ref="headerSearchSelectRef"
+ size="large"
+ @input="querySearch"
+ prefix-icon="el-icon-search"
+ placeholder="菜单搜索,支持标题、URL模糊查询"
+ clearable
+ @keyup.enter.native="selectActiveResult"
+ @keydown.up.native="navigateResult('up')"
+ @keydown.down.native="navigateResult('down')"
+ >
+ </el-input>
+
+ <div class="result-count" v-if="search && options.length > 0">
+ 找到 <strong>{{ options.length }}</strong> 个结果
+ </div>
+
+ <el-scrollbar wrap-class="right-scrollbar-wrapper">
+ <div class="result-wrap">
+ <template v-if="options.length > 0">
+ <div
+ class="search-item"
+ v-for="(item, index) in options"
+ :key="item.path"
+ :class="{ 'is-active': index === activeIndex }"
+ :style="activeStyle(index)"
+ @mouseenter="activeIndex = index"
+ @mouseleave="activeIndex = -1"
+ >
+ <div class="left">
+ <svg-icon class="menu-icon" :icon-class="item.icon" />
+ </div>
+ <div class="search-info" @click="change(item)">
+ <div class="menu-title" v-html="highlightText(item.title.join(' / '))"></div>
+ <div class="menu-path" v-html="highlightText(item.path)"></div>
+ </div>
+ <svg-icon icon-class="enter" v-show="index === activeIndex" />
+ </div>
+ </template>
+
+ <div class="empty-state" v-else-if="search && options.length === 0">
+ <i class="el-icon-search empty-icon"></i>
+ <p class="empty-text">未找到 "<strong>{{ search }}</strong>" 相关菜单</p>
+ <p class="empty-tip">试试其他关键词或路径</p>
+ </div>
+
+ </div>
+ </el-scrollbar>
+
+ <div class="search-footer">
+ <span class="shortcut-item">
+ <kbd>↑</kbd><kbd>↓</kbd> 切换
+ </span>
+ <span class="shortcut-item">
+ <kbd>↵</kbd> 选择
+ </span>
+ <span class="shortcut-item">
+ <kbd>Esc</kbd> 关闭
+ </span>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import Fuse from 'fuse.js/dist/fuse.min.js'
+import path from 'path'
+import { isHttp } from '@/utils/validate'
+
+export default {
+ name: 'HeaderSearch',
+ data() {
+ return {
+ search: '',
+ options: [],
+ searchPool: [],
+ activeIndex: -1,
+ show: false,
+ fuse: undefined
+ }
+ },
+ computed: {
+ theme() {
+ return this.$store.state.settings.theme
+ },
+ routes() {
+ return this.$store.getters.defaultRoutes
+ }
+ },
+ watch: {
+ routes() {
+ this.searchPool = this.generateRoutes(this.routes)
+ },
+ searchPool(list) {
+ this.initFuse(list)
+ }
+ },
+ mounted() {
+ this.searchPool = this.generateRoutes(this.routes)
+ },
+ methods: {
+ click() {
+ this.show = !this.show
+ if (this.show) {
+ this.options = this.searchPool
+ }
+ },
+ onDialogOpened() {
+ this.$nextTick(() => {
+ this.$refs.headerSearchSelectRef && this.$refs.headerSearchSelectRef.focus()
+ })
+ },
+ close() {
+ this.$refs.headerSearchSelectRef && this.$refs.headerSearchSelectRef.blur()
+ this.search = ''
+ this.options = this.searchPool
+ this.show = false
+ this.activeIndex = -1
+ },
+ change(val) {
+ const p = val.path
+ const query = val.query
+ if (isHttp(val.path)) {
+ // http(s):// 路径新窗口打开
+ const pindex = p.indexOf('http')
+ window.open(p.substr(pindex, p.length), '_blank')
+ } else {
+ if (query) {
+ this.$router.push({ path: p, query: JSON.parse(query) })
+ } else {
+ this.$router.push(p)
+ }
+ }
+ this.search = ''
+ this.options = this.searchPool
+ this.$nextTick(() => {
+ this.show = false
+ })
+ },
+ initFuse(list) {
+ this.fuse = new Fuse(list, {
+ shouldSort: true,
+ threshold: 0.2,
+ minMatchCharLength: 1,
+ keys: [{
+ name: 'title',
+ weight: 0.7
+ }, {
+ name: 'path',
+ weight: 0.3
+ }]
+ })
+ },
+ generateRoutes(routes, basePath = '/', prefixTitle = []) {
+ let res = []
+ for (const router of routes) {
+ if (router.hidden) { continue }
+ const data = {
+ path: !isHttp(router.path) ? path.resolve(basePath, router.path) : router.path,
+ title: [...prefixTitle],
+ icon: ''
+ }
+ if (router.meta && router.meta.title) {
+ data.title = [...data.title, router.meta.title]
+ data.icon = router.meta.icon
+ if (router.redirect !== 'noRedirect') {
+ res.push(data)
+ }
+ }
+ if (router.query) {
+ data.query = router.query
+ }
+ if (router.children) {
+ const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+ if (tempRoutes.length >= 1) {
+ res = [...res, ...tempRoutes]
+ }
+ }
+ }
+ return res
+ },
+ querySearch(query) {
+ this.activeIndex = -1
+ if (query !== '') {
+ const q = query.toLowerCase()
+ const pathMatches = this.searchPool.filter(item =>
+ item.path.toLowerCase().includes(q)
+ )
+ const fuseMatches = this.fuse.search(query).map(item => item.item)
+ const merged = [...pathMatches]
+ fuseMatches.forEach(item => {
+ if (!merged.find(m => m.path === item.path)) {
+ merged.push(item)
+ }
+ })
+ this.options = merged
+ } else {
+ this.options = this.searchPool
+ }
+ },
+ activeStyle(index) {
+ if (index !== this.activeIndex) return {}
+ return {
+ 'background-color': this.theme,
+ 'color': '#fff'
+ }
+ },
+ navigateResult(direction) {
+ if (direction === 'up') {
+ this.activeIndex = this.activeIndex <= 0 ? this.options.length - 1 : this.activeIndex - 1
+ } else if (direction === 'down') {
+ this.activeIndex = this.activeIndex >= this.options.length - 1 ? 0 : this.activeIndex + 1
+ }
+ },
+ selectActiveResult() {
+ if (this.options.length > 0 && this.activeIndex >= 0) {
+ this.change(this.options[this.activeIndex])
+ }
+ },
+ highlightText(text) {
+ if (!text) return ''
+ if (!this.search) return text
+ const keyword = this.escapeRegExp(this.search)
+ const reg = new RegExp(`(${keyword})`, 'gi')
+ return text.replace(reg, '<span class="highlight">$1</span>')
+ },
+ escapeRegExp(str) {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ }
+ }
+}
+</script>
+
+<style lang='scss' scoped>
+::v-deep {
+ .el-dialog__header {
+ padding: 6px !important;
+ }
+
+ .highlight {
+ color: red;
+ font-weight: 600;
+ }
+
+ .is-active .highlight {
+ color: rgba(255, 255, 255, 0.9);
+ font-weight: 600;
+ }
+}
+
+.header-search {
+ .search-icon {
+ cursor: pointer;
+ font-size: 18px;
+ vertical-align: middle;
+ }
+}
+
+.result-count {
+ padding: 6px 16px 0;
+ font-size: 12px;
+ color: #aaa;
+
+ strong {
+ color: red;
+ font-weight: 600;
+ }
+}
+
+.result-wrap {
+ height: 280px;
+ margin: 4px 0;
+
+ .search-item {
+ display: flex;
+ height: 48px;
+ align-items: center;
+ padding-right: 10px;
+ border-radius: 4px;
+ transition: background 0.15s;
+
+ .left {
+ width: 60px;
+ text-align: center;
+ flex-shrink: 0;
+
+ .menu-icon {
+ width: 18px;
+ height: 18px;
+ }
+ }
+
+ .search-info {
+ padding-left: 5px;
+ margin-top: 10px;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ flex: 1;
+ overflow: hidden;
+
+ .menu-title,
+ .menu-path {
+ height: 20px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .menu-path {
+ color: #ccc;
+ font-size: 10px;
+ }
+ }
+ }
+
+ .search-item:hover {
+ cursor: pointer;
+ }
+
+ .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+
+ .empty-icon {
+ font-size: 42px;
+ color: #e0e0e0;
+ margin-bottom: 14px;
+ }
+
+ .empty-text {
+ font-size: 14px;
+ color: #999;
+ margin: 0 0 6px;
+
+ strong {
+ color: #666;
+ }
+ }
+
+ .empty-tip {
+ font-size: 12px;
+ color: #bbb;
+ margin: 0;
+ }
+ }
+}
+
+.search-footer {
+ display: flex;
+ align-items: center;
+ gap: 28px;
+ padding: 10px 20px;
+ border-top: 1px solid #f0f0f0;
+ color: #999;
+ font-size: 12px;
+
+ .shortcut-item {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ }
+
+ kbd {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 20px;
+ height: 20px;
+ padding: 0 5px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ background: #f7f7f7;
+ color: #555;
+ font-size: 11px;
+ font-family: inherit;
+ line-height: 1;
+ box-shadow: 0 1px 0 #ccc;
+ }
+}
+</style>
\ No newline at end of file
diff --git a/sgd-ui/src/components/IconSelect/index.vue b/sgd-ui/src/components/IconSelect/index.vue
new file mode 100644
index 0000000..8dadc02
--- /dev/null
+++ b/sgd-ui/src/components/IconSelect/index.vue
@@ -0,0 +1,104 @@
+<!-- @author zhengjie -->
+<template>
+ <div class="icon-body">
+ <el-input v-model="name" class="icon-search" clearable placeholder="请输入图标名称" @clear="filterIcons" @input="filterIcons">
+ <i slot="suffix" class="el-icon-search el-input__icon" />
+ </el-input>
+ <div class="icon-list">
+ <div class="list-container">
+ <div v-for="(item, index) in iconList" class="icon-item-wrapper" :key="index" @click="selectedIcon(item)">
+ <div :class="['icon-item', { active: activeIcon === item }]">
+ <svg-icon :icon-class="item" class-name="icon" style="height: 25px;width: 16px;"/>
+ <span>{{ item }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+ name: 'IconSelect',
+ props: {
+ activeIcon: {
+ type: String
+ }
+ },
+ data() {
+ return {
+ name: '',
+ iconList: icons
+ }
+ },
+ methods: {
+ filterIcons() {
+ this.iconList = icons
+ if (this.name) {
+ this.iconList = this.iconList.filter(item => item.includes(this.name))
+ }
+ },
+ selectedIcon(name) {
+ this.$emit('selected', name)
+ document.body.click()
+ },
+ reset() {
+ this.name = ''
+ this.iconList = icons
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+ .icon-body {
+ width: 100%;
+ padding: 10px;
+ .icon-search {
+ position: relative;
+ margin-bottom: 5px;
+ }
+ .icon-list {
+ height: 200px;
+ overflow: auto;
+ .list-container {
+ display: flex;
+ flex-wrap: wrap;
+ .icon-item-wrapper {
+ width: calc(100% / 3);
+ height: 25px;
+ line-height: 25px;
+ cursor: pointer;
+ display: flex;
+ .icon-item {
+ display: flex;
+ max-width: 100%;
+ height: 100%;
+ padding: 0 5px;
+ &:hover {
+ background: #ececec;
+ border-radius: 5px;
+ }
+ .icon {
+ flex-shrink: 0;
+ }
+ span {
+ display: inline-block;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ padding-left: 2px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+ .icon-item.active {
+ background: #ececec;
+ border-radius: 5px;
+ }
+ }
+ }
+ }
+ }
+</style>
diff --git a/sgd-ui/src/components/IconSelect/requireIcons.js b/sgd-ui/src/components/IconSelect/requireIcons.js
new file mode 100644
index 0000000..99e5c54
--- /dev/null
+++ b/sgd-ui/src/components/IconSelect/requireIcons.js
@@ -0,0 +1,11 @@
+
+const req = require.context('../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+ return i.match(re)[1]
+})
+
+export default icons
diff --git a/ruoyi-ui/src/components/ImagePreview/index.vue b/sgd-ui/src/components/ImagePreview/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/ImagePreview/index.vue
rename to sgd-ui/src/components/ImagePreview/index.vue
diff --git a/sgd-ui/src/components/ImageUpload/index.vue b/sgd-ui/src/components/ImageUpload/index.vue
new file mode 100644
index 0000000..7a96b9a
--- /dev/null
+++ b/sgd-ui/src/components/ImageUpload/index.vue
@@ -0,0 +1,266 @@
+<template>
+ <div class="component-upload-image">
+ <el-upload
+ multiple
+ :disabled="disabled"
+ :action="uploadImgUrl"
+ list-type="picture-card"
+ :on-success="handleUploadSuccess"
+ :before-upload="handleBeforeUpload"
+ :data="data"
+ :limit="limit"
+ :on-error="handleUploadError"
+ :on-exceed="handleExceed"
+ ref="imageUpload"
+ :on-remove="handleDelete"
+ :show-file-list="true"
+ :headers="headers"
+ :file-list="fileList"
+ :on-preview="handlePictureCardPreview"
+ :class="{hide: this.fileList.length >= this.limit}"
+ >
+ <i class="el-icon-plus"></i>
+ </el-upload>
+
+ <!-- 上传提示 -->
+ <div class="el-upload__tip" slot="tip" v-if="showTip && !disabled">
+ 请上传
+ <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+ <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+ 的文件
+ </div>
+
+ <el-dialog
+ :visible.sync="dialogVisible"
+ title="预览"
+ width="800"
+ append-to-body
+ >
+ <img
+ :src="dialogImageUrl"
+ style="display: block; max-width: 100%; margin: 0 auto"
+ />
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth"
+import Sortable from 'sortablejs'
+
+export default {
+ props: {
+ value: [String, Object, Array],
+ // 上传接口地址
+ action: {
+ type: String,
+ default: "/file/upload"
+ },
+ // 上传携带的参数
+ data: {
+ type: Object
+ },
+ // 图片数量限制
+ limit: {
+ type: Number,
+ default: 5
+ },
+ // 大小限制(MB)
+ fileSize: {
+ type: Number,
+ default: 5
+ },
+ // 文件类型, 例如['png', 'jpg', 'jpeg']
+ fileType: {
+ type: Array,
+ default: () => ["png", "jpg", "jpeg"]
+ },
+ // 是否显示提示
+ isShowTip: {
+ type: Boolean,
+ default: true
+ },
+ // 禁用组件(仅查看图片)
+ disabled: {
+ type: Boolean,
+ default: false
+ },
+ // 拖动排序
+ drag: {
+ type: Boolean,
+ default: true
+ }
+ },
+ data() {
+ return {
+ number: 0,
+ uploadList: [],
+ dialogImageUrl: "",
+ dialogVisible: false,
+ hideUpload: false,
+ uploadImgUrl: process.env.VUE_APP_BASE_API + this.action, // 上传的图片服务器地址
+ headers: {
+ Authorization: "Bearer " + getToken(),
+ },
+ fileList: []
+ }
+ },
+ mounted() {
+ if (this.drag && !this.disabled) {
+ this.$nextTick(() => {
+ const element = this.$refs.imageUpload?.$el?.querySelector('.el-upload-list')
+ Sortable.create(element, {
+ onEnd: (evt) => {
+ const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
+ this.fileList.splice(evt.newIndex, 0, movedItem)
+ this.$emit("input", this.listToString(this.fileList))
+ }
+ })
+ })
+ }
+ },
+ watch: {
+ value: {
+ handler(val) {
+ if (val) {
+ // 首先将值转为数组
+ const list = Array.isArray(val) ? val : this.value.split(',')
+ // 然后将数组转为对象数组
+ this.fileList = list.map(item => {
+ if (typeof item === "string") {
+ item = { name: item, url: item }
+ }
+ return item
+ })
+ } else {
+ this.fileList = []
+ return []
+ }
+ },
+ deep: true,
+ immediate: true
+ }
+ },
+ computed: {
+ // 是否显示提示
+ showTip() {
+ return this.isShowTip && (this.fileType || this.fileSize)
+ },
+ },
+ methods: {
+ // 上传前loading加载
+ handleBeforeUpload(file) {
+ let isImg = false
+ if (this.fileType.length) {
+ let fileExtension = ""
+ if (file.name.lastIndexOf(".") > -1) {
+ fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1)
+ }
+ isImg = this.fileType.some(type => {
+ if (file.type.indexOf(type) > -1) return true
+ if (fileExtension && fileExtension.indexOf(type) > -1) return true
+ return false
+ })
+ } else {
+ isImg = file.type.indexOf("image") > -1
+ }
+
+ if (!isImg) {
+ this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}图片格式文件!`)
+ return false
+ }
+ if (file.name.includes(',')) {
+ this.$modal.msgError('文件名不正确,不能包含英文逗号!')
+ return false
+ }
+ if (this.fileSize) {
+ const isLt = file.size / 1024 / 1024 < this.fileSize
+ if (!isLt) {
+ this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`)
+ return false
+ }
+ }
+ this.$modal.loading("正在上传图片,请稍候...")
+ this.number++
+ },
+ // 文件个数超出
+ handleExceed() {
+ this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
+ },
+ // 上传成功回调
+ handleUploadSuccess(res, file) {
+ if (res.code === 200) {
+ this.uploadList.push({ name: res.data.url, url: res.data.url })
+ this.uploadedSuccessfully()
+ } else {
+ this.number--
+ this.$modal.closeLoading()
+ this.$modal.msgError(res.msg)
+ this.$refs.imageUpload.handleRemove(file)
+ this.uploadedSuccessfully()
+ }
+ },
+ // 删除图片
+ handleDelete(file) {
+ const findex = this.fileList.map(f => f.name).indexOf(file.name)
+ if (findex > -1) {
+ this.fileList.splice(findex, 1)
+ this.$emit("input", this.listToString(this.fileList))
+ }
+ },
+ // 上传失败
+ handleUploadError() {
+ this.$modal.msgError("上传图片失败,请重试")
+ this.$modal.closeLoading()
+ },
+ // 上传结束处理
+ uploadedSuccessfully() {
+ if (this.number > 0 && this.uploadList.length === this.number) {
+ this.fileList = this.fileList.concat(this.uploadList)
+ this.uploadList = []
+ this.number = 0
+ this.$emit("input", this.listToString(this.fileList))
+ this.$modal.closeLoading()
+ }
+ },
+ // 预览
+ handlePictureCardPreview(file) {
+ this.dialogImageUrl = file.url
+ this.dialogVisible = true
+ },
+ // 对象转成指定字符串分隔
+ listToString(list, separator) {
+ let strs = ""
+ separator = separator || ","
+ for (let i in list) {
+ if (list[i].url) {
+ strs += list[i].url.replace(this.baseUrl, "") + separator
+ }
+ }
+ return strs != '' ? strs.substr(0, strs.length - 1) : ''
+ }
+ }
+}
+</script>
+<style scoped lang="scss">
+// .el-upload--picture-card 控制加号部分
+::v-deep.hide .el-upload--picture-card {
+ display: none;
+}
+
+::v-deep .el-upload-list--picture-card.is-disabled + .el-upload--picture-card {
+ display: none !important;
+}
+
+// 去掉动画效果
+::v-deep .el-list-enter-active,
+::v-deep .el-list-leave-active {
+ transition: all 0s;
+}
+
+::v-deep .el-list-enter, .el-list-leave-active {
+ opacity: 0;
+ transform: translateY(0);
+}
+</style>
+
diff --git a/sgd-ui/src/components/Pagination/index.vue b/sgd-ui/src/components/Pagination/index.vue
new file mode 100644
index 0000000..08ac487
--- /dev/null
+++ b/sgd-ui/src/components/Pagination/index.vue
@@ -0,0 +1,113 @@
+<template>
+ <div :class="{'hidden':hidden}" class="pagination-container">
+ <el-pagination
+ :background="background"
+ :current-page.sync="currentPage"
+ :page-size.sync="pageSize"
+ :layout="layout"
+ :page-sizes="pageSizes"
+ :pager-count="pagerCount"
+ :total="total"
+ v-bind="$attrs"
+ @size-change="handleSizeChange"
+ @current-change="handleCurrentChange"
+ />
+ </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+ name: 'Pagination',
+ props: {
+ total: {
+ required: true,
+ type: Number
+ },
+ page: {
+ type: Number,
+ default: 1
+ },
+ limit: {
+ type: Number,
+ default: 20
+ },
+ pageSizes: {
+ type: Array,
+ default() {
+ return [10, 20, 30, 50]
+ }
+ },
+ // 移动端页码按钮的数量端默认值5
+ pagerCount: {
+ type: Number,
+ default: document.body.clientWidth < 992 ? 5 : 7
+ },
+ layout: {
+ type: String,
+ default: 'total, sizes, prev, pager, next, jumper'
+ },
+ background: {
+ type: Boolean,
+ default: true
+ },
+ autoScroll: {
+ type: Boolean,
+ default: true
+ },
+ hidden: {
+ type: Boolean,
+ default: false
+ }
+ },
+ data() {
+ return {
+ }
+ },
+ computed: {
+ currentPage: {
+ get() {
+ return this.page
+ },
+ set(val) {
+ this.$emit('update:page', val)
+ }
+ },
+ pageSize: {
+ get() {
+ return this.limit
+ },
+ set(val) {
+ this.$emit('update:limit', val)
+ }
+ }
+ },
+ methods: {
+ handleSizeChange(val) {
+ if (this.currentPage * val > this.total) {
+ this.currentPage = 1
+ }
+ this.$emit('pagination', { page: this.currentPage, limit: val })
+ if (this.autoScroll) {
+ scrollTo(0, 800)
+ }
+ },
+ handleCurrentChange(val) {
+ this.$emit('pagination', { page: val, limit: this.pageSize })
+ if (this.autoScroll) {
+ scrollTo(0, 800)
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+ background: #fff;
+}
+.pagination-container.hidden {
+ display: none;
+}
+</style>
diff --git a/sgd-ui/src/components/PanThumb/index.vue b/sgd-ui/src/components/PanThumb/index.vue
new file mode 100644
index 0000000..b24e026
--- /dev/null
+++ b/sgd-ui/src/components/PanThumb/index.vue
@@ -0,0 +1,141 @@
+<template>
+ <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+ <div class="pan-info">
+ <div class="pan-info-roles-container">
+ <slot />
+ </div>
+ </div>
+ <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'PanThumb',
+ props: {
+ image: {
+ type: String,
+ required: true
+ },
+ zIndex: {
+ type: Number,
+ default: 1
+ },
+ width: {
+ type: String,
+ default: '150px'
+ },
+ height: {
+ type: String,
+ default: '150px'
+ }
+ }
+}
+</script>
+
+<style scoped>
+.pan-item {
+ width: 200px;
+ height: 200px;
+ border-radius: 50%;
+ display: inline-block;
+ position: relative;
+ cursor: default;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+ padding: 20px;
+ text-align: center;
+}
+
+.pan-thumb {
+ width: 100%;
+ height: 100%;
+ background-position: center center;
+ background-size: cover;
+ border-radius: 50%;
+ overflow: hidden;
+ position: absolute;
+ transform-origin: 95% 40%;
+ transition: all 0.3s ease-in-out;
+}
+
+/* .pan-thumb:after {
+ content: '';
+ width: 8px;
+ height: 8px;
+ position: absolute;
+ border-radius: 50%;
+ top: 40%;
+ left: 95%;
+ margin: -4px 0 0 -4px;
+ background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+ box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+} */
+
+.pan-info {
+ position: absolute;
+ width: inherit;
+ height: inherit;
+ border-radius: 50%;
+ overflow: hidden;
+ box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+ color: #fff;
+ text-transform: uppercase;
+ position: relative;
+ letter-spacing: 2px;
+ font-size: 18px;
+ margin: 0 60px;
+ padding: 22px 0 0 0;
+ height: 85px;
+ font-family: 'Open Sans', Arial, sans-serif;
+ text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+ color: #fff;
+ padding: 10px 5px;
+ font-style: italic;
+ margin: 0 30px;
+ font-size: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+ display: block;
+ color: #333;
+ width: 80px;
+ height: 80px;
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 50%;
+ color: #fff;
+ font-style: normal;
+ font-weight: 700;
+ text-transform: uppercase;
+ font-size: 9px;
+ letter-spacing: 1px;
+ padding-top: 24px;
+ margin: 7px auto 0;
+ font-family: 'Open Sans', Arial, sans-serif;
+ opacity: 0;
+ transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+ transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+ background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+ transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+ opacity: 1;
+ transform: translateX(0px) rotate(0deg);
+}
+</style>
diff --git a/ruoyi-ui/src/components/ParentView/index.vue b/sgd-ui/src/components/ParentView/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/ParentView/index.vue
rename to sgd-ui/src/components/ParentView/index.vue
diff --git a/ruoyi-ui/src/components/RightToolbar/index.vue b/sgd-ui/src/components/RightToolbar/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/RightToolbar/index.vue
rename to sgd-ui/src/components/RightToolbar/index.vue
diff --git a/ruoyi-ui/src/components/RuoYi/Doc/index.vue b/sgd-ui/src/components/RuoYi/Doc/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/RuoYi/Doc/index.vue
rename to sgd-ui/src/components/RuoYi/Doc/index.vue
diff --git a/ruoyi-ui/src/components/RuoYi/Git/index.vue b/sgd-ui/src/components/RuoYi/Git/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/RuoYi/Git/index.vue
rename to sgd-ui/src/components/RuoYi/Git/index.vue
diff --git a/sgd-ui/src/components/Screenfull/index.vue b/sgd-ui/src/components/Screenfull/index.vue
new file mode 100644
index 0000000..d4e539c
--- /dev/null
+++ b/sgd-ui/src/components/Screenfull/index.vue
@@ -0,0 +1,57 @@
+<template>
+ <div>
+ <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+ </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+ name: 'Screenfull',
+ data() {
+ return {
+ isFullscreen: false
+ }
+ },
+ mounted() {
+ this.init()
+ },
+ beforeDestroy() {
+ this.destroy()
+ },
+ methods: {
+ click() {
+ if (!screenfull.isEnabled) {
+ this.$message({ message: '你的浏览器不支持全屏', type: 'warning' })
+ return false
+ }
+ screenfull.toggle()
+ },
+ change() {
+ this.isFullscreen = screenfull.isFullscreen
+ },
+ init() {
+ if (screenfull.isEnabled) {
+ screenfull.on('change', this.change)
+ }
+ },
+ destroy() {
+ if (screenfull.isEnabled) {
+ screenfull.off('change', this.change)
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+ display: inline-block;
+ cursor: pointer;
+ fill: #5a5e66;;
+ width: 20px;
+ height: 20px;
+ vertical-align: 10px;
+}
+</style>
diff --git a/sgd-ui/src/components/SizeSelect/index.vue b/sgd-ui/src/components/SizeSelect/index.vue
new file mode 100644
index 0000000..e513948
--- /dev/null
+++ b/sgd-ui/src/components/SizeSelect/index.vue
@@ -0,0 +1,55 @@
+<template>
+ <el-dropdown trigger="click" @command="handleSetSize">
+ <div>
+ <svg-icon class-name="size-icon" icon-class="size" />
+ </div>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+ {{ item.label }}
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+</template>
+
+<script>
+export default {
+ data() {
+ return {
+ sizeOptions: [
+ { label: 'Default', value: 'default' },
+ { label: 'Medium', value: 'medium' },
+ { label: 'Small', value: 'small' },
+ { label: 'Mini', value: 'mini' }
+ ]
+ }
+ },
+ computed: {
+ size() {
+ return this.$store.getters.size
+ }
+ },
+ methods: {
+ handleSetSize(size) {
+ this.$ELEMENT.size = size
+ this.$store.dispatch('app/setSize', size)
+ this.refreshView()
+ this.$message({
+ message: 'Switch Size Success',
+ type: 'success'
+ })
+ },
+ refreshView() {
+ // In order to make the cached page re-rendered
+ this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+ const { fullPath } = this.$route
+
+ this.$nextTick(() => {
+ this.$router.replace({
+ path: '/redirect' + fullPath
+ })
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/components/SvgIcon/index.vue b/sgd-ui/src/components/SvgIcon/index.vue
new file mode 100644
index 0000000..e4bf5ad
--- /dev/null
+++ b/sgd-ui/src/components/SvgIcon/index.vue
@@ -0,0 +1,61 @@
+<template>
+ <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+ <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+ <use :xlink:href="iconName" />
+ </svg>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+ name: 'SvgIcon',
+ props: {
+ iconClass: {
+ type: String,
+ required: true
+ },
+ className: {
+ type: String,
+ default: ''
+ }
+ },
+ computed: {
+ isExternal() {
+ return isExternal(this.iconClass)
+ },
+ iconName() {
+ return `#icon-${this.iconClass}`
+ },
+ svgClass() {
+ if (this.className) {
+ return 'svg-icon ' + this.className
+ } else {
+ return 'svg-icon'
+ }
+ },
+ styleExternalIcon() {
+ return {
+ mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+ '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ overflow: hidden;
+}
+
+.svg-external-icon {
+ background-color: currentColor;
+ mask-size: cover!important;
+ display: inline-block;
+}
+</style>
diff --git a/ruoyi-ui/src/components/ThemePicker/index.vue b/sgd-ui/src/components/ThemePicker/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/ThemePicker/index.vue
rename to sgd-ui/src/components/ThemePicker/index.vue
diff --git a/ruoyi-ui/src/components/TreePanel/index.vue b/sgd-ui/src/components/TreePanel/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/TreePanel/index.vue
rename to sgd-ui/src/components/TreePanel/index.vue
diff --git a/ruoyi-ui/src/components/iFrame/index.vue b/sgd-ui/src/components/iFrame/index.vue
similarity index 100%
rename from ruoyi-ui/src/components/iFrame/index.vue
rename to sgd-ui/src/components/iFrame/index.vue
diff --git a/ruoyi-ui/src/directive/dialog/drag.js b/sgd-ui/src/directive/dialog/drag.js
similarity index 100%
rename from ruoyi-ui/src/directive/dialog/drag.js
rename to sgd-ui/src/directive/dialog/drag.js
diff --git a/sgd-ui/src/directive/dialog/dragHeight.js b/sgd-ui/src/directive/dialog/dragHeight.js
new file mode 100644
index 0000000..cf4786e
--- /dev/null
+++ b/sgd-ui/src/directive/dialog/dragHeight.js
@@ -0,0 +1,34 @@
+/**
+ * v-dialogDragWidth 可拖动弹窗高度(右下角)
+ * Copyright (c) 2019 ruoyi
+ */
+
+export default {
+ bind(el) {
+ const dragDom = el.querySelector('.el-dialog')
+ const lineEl = document.createElement('div')
+ lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;'
+ lineEl.addEventListener('mousedown',
+ function(e) {
+ // 鼠标按下,计算当前元素距离可视区的距离
+ const disX = e.clientX - el.offsetLeft
+ const disY = e.clientY - el.offsetTop
+ // 当前宽度 高度
+ const curWidth = dragDom.offsetWidth
+ const curHeight = dragDom.offsetHeight
+ document.onmousemove = function(e) {
+ e.preventDefault() // 移动时禁用默认事件
+ // 通过事件委托,计算移动的距离
+ const xl = e.clientX - disX
+ const yl = e.clientY - disY
+ dragDom.style.width = `${curWidth + xl}px`
+ dragDom.style.height = `${curHeight + yl}px`
+ }
+ document.onmouseup = function(e) {
+ document.onmousemove = null
+ document.onmouseup = null
+ }
+ }, false)
+ dragDom.appendChild(lineEl)
+ }
+}
diff --git a/sgd-ui/src/directive/dialog/dragWidth.js b/sgd-ui/src/directive/dialog/dragWidth.js
new file mode 100644
index 0000000..93ab05f
--- /dev/null
+++ b/sgd-ui/src/directive/dialog/dragWidth.js
@@ -0,0 +1,30 @@
+/**
+ * v-dialogDragWidth 可拖动弹窗宽度(右侧边)
+ * Copyright (c) 2019 ruoyi
+ */
+
+export default {
+ bind(el) {
+ const dragDom = el.querySelector('.el-dialog')
+ const lineEl = document.createElement('div')
+ lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;'
+ lineEl.addEventListener('mousedown',
+ function (e) {
+ // 鼠标按下,计算当前元素距离可视区的距离
+ const disX = e.clientX - el.offsetLeft
+ // 当前宽度
+ const curWidth = dragDom.offsetWidth
+ document.onmousemove = function (e) {
+ e.preventDefault() // 移动时禁用默认事件
+ // 通过事件委托,计算移动的距离
+ const l = e.clientX - disX
+ dragDom.style.width = `${curWidth + l}px`
+ }
+ document.onmouseup = function (e) {
+ document.onmousemove = null
+ document.onmouseup = null
+ }
+ }, false)
+ dragDom.appendChild(lineEl)
+ }
+}
diff --git a/ruoyi-ui/src/directive/index.js b/sgd-ui/src/directive/index.js
similarity index 100%
rename from ruoyi-ui/src/directive/index.js
rename to sgd-ui/src/directive/index.js
diff --git a/sgd-ui/src/directive/module/clipboard.js b/sgd-ui/src/directive/module/clipboard.js
new file mode 100644
index 0000000..4c11fc9
--- /dev/null
+++ b/sgd-ui/src/directive/module/clipboard.js
@@ -0,0 +1,54 @@
+/**
+* v-clipboard 文字复制剪贴
+* Copyright (c) 2021 ruoyi
+*/
+
+import Clipboard from 'clipboard'
+export default {
+ bind(el, binding, vnode) {
+ switch (binding.arg) {
+ case 'success':
+ el._vClipBoard_success = binding.value
+ break
+ case 'error':
+ el._vClipBoard_error = binding.value
+ break
+ default: {
+ const clipboard = new Clipboard(el, {
+ text: () => binding.value,
+ action: () => binding.arg === 'cut' ? 'cut' : 'copy'
+ })
+ clipboard.on('success', e => {
+ const callback = el._vClipBoard_success
+ callback && callback(e)
+ })
+ clipboard.on('error', e => {
+ const callback = el._vClipBoard_error
+ callback && callback(e)
+ })
+ el._vClipBoard = clipboard
+ }
+ }
+ },
+ update(el, binding) {
+ if (binding.arg === 'success') {
+ el._vClipBoard_success = binding.value
+ } else if (binding.arg === 'error') {
+ el._vClipBoard_error = binding.value
+ } else {
+ el._vClipBoard.text = function () { return binding.value }
+ el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy'
+ }
+ },
+ unbind(el, binding) {
+ if (!el._vClipboard) return
+ if (binding.arg === 'success') {
+ delete el._vClipBoard_success
+ } else if (binding.arg === 'error') {
+ delete el._vClipBoard_error
+ } else {
+ el._vClipBoard.destroy()
+ delete el._vClipBoard
+ }
+ }
+}
diff --git a/sgd-ui/src/directive/permission/hasPermi.js b/sgd-ui/src/directive/permission/hasPermi.js
new file mode 100644
index 0000000..15ca851
--- /dev/null
+++ b/sgd-ui/src/directive/permission/hasPermi.js
@@ -0,0 +1,28 @@
+ /**
+ * v-hasPermi 操作权限处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+import store from '@/store'
+
+export default {
+ inserted(el, binding, vnode) {
+ const { value } = binding
+ const all_permission = "*:*:*"
+ const permissions = store.getters && store.getters.permissions
+
+ if (value && value instanceof Array && value.length > 0) {
+ const permissionFlag = value
+
+ const hasPermissions = permissions.some(permission => {
+ return all_permission === permission || permissionFlag.includes(permission)
+ })
+
+ if (!hasPermissions) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ } else {
+ throw new Error(`请设置操作权限标签值`)
+ }
+ }
+}
diff --git a/sgd-ui/src/directive/permission/hasRole.js b/sgd-ui/src/directive/permission/hasRole.js
new file mode 100644
index 0000000..68cb8c8
--- /dev/null
+++ b/sgd-ui/src/directive/permission/hasRole.js
@@ -0,0 +1,28 @@
+ /**
+ * v-hasRole 角色权限处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+import store from '@/store'
+
+export default {
+ inserted(el, binding, vnode) {
+ const { value } = binding
+ const super_admin = "admin"
+ const roles = store.getters && store.getters.roles
+
+ if (value && value instanceof Array && value.length > 0) {
+ const roleFlag = value
+
+ const hasRole = roles.some(role => {
+ return super_admin === role || roleFlag.includes(role)
+ })
+
+ if (!hasRole) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ } else {
+ throw new Error(`请设置角色权限标签值"`)
+ }
+ }
+}
diff --git a/sgd-ui/src/layout/components/AppMain.vue b/sgd-ui/src/layout/components/AppMain.vue
new file mode 100644
index 0000000..3157e91
--- /dev/null
+++ b/sgd-ui/src/layout/components/AppMain.vue
@@ -0,0 +1,140 @@
+<template>
+ <section class="app-main">
+ <transition name="fade-transform" mode="out-in">
+ <keep-alive :include="cachedViews">
+ <router-view v-if="!$route.meta.link" :key="key" />
+ </keep-alive>
+ </transition>
+ <iframe-toggle />
+ <copyright />
+ </section>
+</template>
+
+<script>
+import copyright from "./Copyright/index"
+import iframeToggle from "./IframeToggle/index"
+
+export default {
+ name: 'AppMain',
+ components: { iframeToggle, copyright },
+ computed: {
+ cachedViews() {
+ return this.$store.state.tagsView.cachedViews
+ },
+ key() {
+ return this.$route.path
+ }
+ },
+ watch: {
+ $route() {
+ this.addIframe()
+ }
+ },
+ mounted() {
+ this.addIframe()
+ },
+ methods: {
+ addIframe() {
+ const { name } = this.$route
+ if (name && this.$route.meta.link) {
+ this.$store.dispatch('tagsView/addIframeView', this.$route)
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-main {
+ /* 50= navbar 50 */
+ min-height: calc(100vh - 50px);
+ width: 100%;
+ position: relative;
+ overflow: hidden;
+
+ &:fullscreen,
+ &:-webkit-full-screen,
+ &:-moz-full-screen,
+ &:-ms-fullscreen {
+ background: #fff;
+ overflow-y: auto;
+ }
+}
+
+.fixed-header + .app-main {
+ overflow-y: auto;
+ scrollbar-gutter: auto;
+ height: calc(100vh - 50px);
+ min-height: 0px;
+}
+
+.app-main:has(.copyright) {
+ padding-bottom: 36px;
+}
+
+.fixed-header + .app-main {
+ margin-top: 50px;
+}
+
+.hasTagsView {
+ .app-main {
+ /* 84 = navbar + tags-view = 50 + 34 */
+ min-height: calc(100vh - 84px);
+ }
+
+ .fixed-header + .app-main {
+ margin-top: 84px;
+ height: calc(100vh - 84px);
+ min-height: 0px;
+ }
+}
+
+/* 移动端fixed-header优化 */
+@media screen and (max-width: 991px) {
+ .fixed-header + .app-main {
+ padding-bottom: max(60px, calc(constant(safe-area-inset-bottom) + 40px));
+ padding-bottom: max(60px, calc(env(safe-area-inset-bottom) + 40px));
+ overscroll-behavior-y: none;
+ }
+
+ .hasTagsView .fixed-header + .app-main {
+ padding-bottom: max(60px, calc(constant(safe-area-inset-bottom) + 40px));
+ padding-bottom: max(60px, calc(env(safe-area-inset-bottom) + 40px));
+ overscroll-behavior-y: none;
+ }
+}
+
+@supports (-webkit-touch-callout: none) {
+ @media screen and (max-width: 991px) {
+ .fixed-header + .app-main {
+ padding-bottom: max(17px, calc(constant(safe-area-inset-bottom) + 10px));
+ padding-bottom: max(17px, calc(env(safe-area-inset-bottom) + 10px));
+ height: calc(100svh - 50px);
+ height: calc(100dvh - 50px);
+ }
+
+ .hasTagsView .fixed-header + .app-main {
+ padding-bottom: max(17px, calc(constant(safe-area-inset-bottom) + 10px));
+ padding-bottom: max(17px, calc(env(safe-area-inset-bottom) + 10px));
+ height: calc(100svh - 84px);
+ height: calc(100dvh - 84px);
+ }
+ }
+}
+</style>
+
+<style lang="scss">
+::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background-color: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: #c0c0c0;
+ border-radius: 3px;
+}
+</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/layout/components/Copyright/index.vue b/sgd-ui/src/layout/components/Copyright/index.vue
similarity index 100%
rename from ruoyi-ui/src/layout/components/Copyright/index.vue
rename to sgd-ui/src/layout/components/Copyright/index.vue
diff --git a/ruoyi-ui/src/layout/components/HeaderNotice/DetailView.vue b/sgd-ui/src/layout/components/HeaderNotice/DetailView.vue
similarity index 100%
rename from ruoyi-ui/src/layout/components/HeaderNotice/DetailView.vue
rename to sgd-ui/src/layout/components/HeaderNotice/DetailView.vue
diff --git a/ruoyi-ui/src/layout/components/HeaderNotice/index.vue b/sgd-ui/src/layout/components/HeaderNotice/index.vue
similarity index 100%
rename from ruoyi-ui/src/layout/components/HeaderNotice/index.vue
rename to sgd-ui/src/layout/components/HeaderNotice/index.vue
diff --git a/sgd-ui/src/layout/components/IframeToggle/index.vue b/sgd-ui/src/layout/components/IframeToggle/index.vue
new file mode 100644
index 0000000..7859067
--- /dev/null
+++ b/sgd-ui/src/layout/components/IframeToggle/index.vue
@@ -0,0 +1,33 @@
+<template>
+ <transition-group name="fade-transform" mode="out-in">
+ <inner-link
+ v-for="(item, index) in iframeViews"
+ :key="item.path"
+ :iframeId="'iframe' + index"
+ v-show="$route.path === item.path"
+ :src="iframeUrl(item.meta.link, item.query)"
+ ></inner-link>
+ </transition-group>
+</template>
+
+<script>
+import InnerLink from "../InnerLink/index"
+
+export default {
+ components: { InnerLink },
+ computed: {
+ iframeViews() {
+ return this.$store.state.tagsView.iframeViews
+ }
+ },
+ methods: {
+ iframeUrl(url, query) {
+ if (Object.keys(query).length > 0) {
+ let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&")
+ return url + "?" + params
+ }
+ return url
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/InnerLink/index.vue b/sgd-ui/src/layout/components/InnerLink/index.vue
new file mode 100644
index 0000000..ab75975
--- /dev/null
+++ b/sgd-ui/src/layout/components/InnerLink/index.vue
@@ -0,0 +1,47 @@
+<template>
+ <div :style="'height:' + height" v-loading="loading" element-loading-text="正在加载页面,请稍候!">
+ <iframe
+ :id="iframeId"
+ style="width: 100%; height: 100%"
+ :src="src"
+ frameborder="no"
+ ></iframe>
+ </div>
+</template>
+
+<script>
+export default {
+ props: {
+ src: {
+ type: String,
+ default: "/"
+ },
+ iframeId: {
+ type: String
+ }
+ },
+ data() {
+ return {
+ loading: false,
+ height: document.documentElement.clientHeight - 94.5 + "px;"
+ }
+ },
+ mounted() {
+ var _this = this
+ const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/")
+ const iframe = document.querySelector(iframeId)
+ // iframe页面loading控制
+ if (iframe.attachEvent) {
+ this.loading = true
+ iframe.attachEvent("onload", function () {
+ _this.loading = false
+ })
+ } else {
+ this.loading = true
+ iframe.onload = function () {
+ _this.loading = false
+ }
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/Navbar.vue b/sgd-ui/src/layout/components/Navbar.vue
new file mode 100644
index 0000000..16d6ba8
--- /dev/null
+++ b/sgd-ui/src/layout/components/Navbar.vue
@@ -0,0 +1,254 @@
+<template>
+ <div class="navbar" :class="'nav' + navType">
+ <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+
+ <breadcrumb v-if="navType == 1" id="breadcrumb-container" class="breadcrumb-container" />
+ <top-nav v-if="navType == 2" id="topmenu-container" class="topmenu-container" />
+ <template v-if="navType == 3">
+ <logo v-show="showLogo" :collapse="false"></logo>
+ <top-bar id="topbar-container" class="topbar-container" />
+ </template>
+ <div class="right-menu">
+ <template v-if="device!=='mobile'">
+ <search id="header-search" class="right-menu-item" />
+
+ <el-tooltip content="源码地址" effect="dark" placement="bottom">
+ <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
+ </el-tooltip>
+
+ <el-tooltip content="文档地址" effect="dark" placement="bottom">
+ <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
+ </el-tooltip>
+
+ <screenfull id="screenfull" class="right-menu-item hover-effect" />
+
+ <el-tooltip content="布局大小" effect="dark" placement="bottom">
+ <size-select id="size-select" class="right-menu-item hover-effect" />
+ </el-tooltip>
+
+ <el-tooltip content="消息通知" effect="dark" placement="bottom">
+ <header-notice id="header-notice" class="right-menu-item hover-effect" />
+ </el-tooltip>
+
+ </template>
+
+ <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
+ <div class="avatar-wrapper">
+ <img :src="avatar" class="user-avatar">
+ <span class="user-nickname"> {{ nickName }} </span>
+ </div>
+ <el-dropdown-menu slot="dropdown">
+ <router-link to="/user/profile">
+ <el-dropdown-item>个人中心</el-dropdown-item>
+ </router-link>
+ <el-dropdown-item @click.native="setLayout" v-if="setting">
+ <span>布局设置</span>
+ </el-dropdown-item>
+ <el-dropdown-item @click.native="lockScreen">
+ <span>锁定屏幕</span>
+ </el-dropdown-item>
+ <el-dropdown-item divided @click.native="logout">
+ <span>退出登录</span>
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </div>
+ </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Breadcrumb from '@/components/Breadcrumb'
+import TopNav from './TopNav'
+import TopBar from './TopBar'
+import Logo from './Sidebar/Logo'
+import Hamburger from '@/components/Hamburger'
+import Screenfull from '@/components/Screenfull'
+import SizeSelect from '@/components/SizeSelect'
+import Search from '@/components/HeaderSearch'
+import RuoYiGit from '@/components/RuoYi/Git'
+import RuoYiDoc from '@/components/RuoYi/Doc'
+import HeaderNotice from './HeaderNotice'
+
+export default {
+ components: {
+ Breadcrumb,
+ Logo,
+ TopNav,
+ TopBar,
+ Hamburger,
+ Screenfull,
+ SizeSelect,
+ Search,
+ RuoYiGit,
+ RuoYiDoc,
+ HeaderNotice
+ },
+ computed: {
+ ...mapGetters([
+ 'sidebar',
+ 'avatar',
+ 'device',
+ 'nickName'
+ ]),
+ setting: {
+ get() {
+ return this.$store.state.settings.showSettings
+ }
+ },
+ navType: {
+ get() {
+ return this.$store.state.settings.navType
+ }
+ },
+ showLogo: {
+ get() {
+ return this.$store.state.settings.sidebarLogo
+ }
+ }
+ },
+ methods: {
+ toggleSideBar() {
+ this.$store.dispatch('app/toggleSideBar')
+ },
+ setLayout(event) {
+ this.$emit('setLayout')
+ },
+ lockScreen() {
+ const currentPath = this.$route.fullPath
+ this.$store.dispatch('lock/lockScreen', currentPath).then(() => {
+ this.$router.push('/lock')
+ })
+ },
+ logout() {
+ this.$confirm('确定注销并退出系统吗?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ this.$store.dispatch('LogOut').then(() => {
+ location.href = '/index'
+ })
+ }).catch(() => {})
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.navbar.nav3 {
+ .hamburger-container {
+ display: none !important;
+ }
+}
+
+.navbar {
+ height: 50px;
+ overflow: hidden;
+ position: relative;
+ background: #fff;
+ box-shadow: 0 1px 4px rgba(0,21,41,.08);
+ display: flex;
+ align-items: center;
+ // padding: 0 8px;
+ box-sizing: border-box;
+
+ .hamburger-container {
+ line-height: 46px;
+ height: 100%;
+ cursor: pointer;
+ transition: background .3s;
+ -webkit-tap-highlight-color:transparent;
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ margin-right: 8px;
+
+ &:hover {
+ background: rgba(0, 0, 0, .025)
+ }
+ }
+
+ .breadcrumb-container {
+ flex-shrink: 0;
+ }
+
+ .topmenu-container {
+ position: absolute;
+ left: 50px;
+ }
+
+ .topbar-container {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ margin-left: 8px;
+ }
+
+ .right-menu {
+ height: 100%;
+ line-height: 50px;
+ display: flex;
+ align-items: center;
+ margin-left: auto;
+
+ &:focus {
+ outline: none;
+ }
+
+ .right-menu-item {
+ display: inline-block;
+ padding: 0 8px;
+ height: 100%;
+ font-size: 18px;
+ color: #5a5e66;
+ vertical-align: text-bottom;
+
+ &.hover-effect {
+ cursor: pointer;
+ transition: background .3s;
+
+ &:hover {
+ background: rgba(0, 0, 0, .025)
+ }
+ }
+ }
+
+ .avatar-container {
+ margin-right: 0px;
+ padding-right: 0px;
+
+ .avatar-wrapper {
+ margin-top: 10px;
+ right: 8px;
+ position: relative;
+
+ .user-avatar {
+ cursor: pointer;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ }
+
+ .user-nickname{
+ position: relative;
+ bottom: 10px;
+ left: 2px;
+ font-size: 14px;
+ font-weight: bold;
+ }
+
+ .el-icon-caret-bottom {
+ cursor: pointer;
+ position: absolute;
+ right: -20px;
+ top: 25px;
+ font-size: 12px;
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/layout/components/Settings/index.vue b/sgd-ui/src/layout/components/Settings/index.vue
new file mode 100644
index 0000000..d40f880
--- /dev/null
+++ b/sgd-ui/src/layout/components/Settings/index.vue
@@ -0,0 +1,430 @@
+<template>
+ <el-drawer size="280px" :visible="showSettings" :with-header="false" :append-to-body="true" :before-close="closeSetting" :lock-scroll="false">
+ <div class="drawer-container">
+ <div>
+ <div class="setting-drawer-content">
+ <div class="setting-drawer-title">
+ <h3 class="drawer-title">菜单导航设置</h3>
+ </div>
+ <div class="nav-wrap">
+ <el-tooltip content="左侧菜单" placement="bottom">
+ <div class="item left" @click="handleNavType(1)" :style="{'--theme': theme}" :class="{ activeItem: navType == 1 }">
+ <b></b><b></b>
+ </div>
+ </el-tooltip>
+
+ <el-tooltip content="混合菜单" placement="bottom">
+ <div class="item mix" @click="handleNavType(2)" :style="{'--theme': theme}" :class="{ activeItem: navType == 2 }">
+ <b></b><b></b>
+ </div>
+ </el-tooltip>
+ <el-tooltip content="顶部菜单" placement="bottom">
+ <div class="item top" @click="handleNavType(3)" :style="{'--theme': theme}" :class="{ activeItem: navType == 3 }">
+ <b></b><b></b>
+ </div>
+ </el-tooltip>
+ </div>
+ <div class="setting-drawer-title">
+ <h3 class="drawer-title">主题风格设置</h3>
+ </div>
+ <div class="setting-drawer-block-checbox">
+ <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
+ <img src="@/assets/images/dark.svg" alt="dark">
+ <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+ <i aria-label="图标: check" class="anticon anticon-check">
+ <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
+ <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+ </svg>
+ </i>
+ </div>
+ </div>
+ <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
+ <img src="@/assets/images/light.svg" alt="light">
+ <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+ <i aria-label="图标: check" class="anticon anticon-check">
+ <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
+ <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+ </svg>
+ </i>
+ </div>
+ </div>
+ </div>
+
+ <div class="drawer-item">
+ <span>主题颜色</span>
+ <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+ </div>
+ </div>
+
+ <el-divider/>
+
+ <h3 class="drawer-title">系统布局配置</h3>
+
+ <div class="drawer-item">
+ <span>开启页签</span>
+ <el-switch v-model="tagsView" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>持久化标签页</span>
+ <el-switch v-model="tagsViewPersist" :disabled="!tagsView" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>显示页签图标</span>
+ <el-switch v-model="tagsIcon" :disabled="!tagsView" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>标签页样式</span>
+ <el-radio-group v-model="tagsViewStyle" :disabled="!tagsView" size="mini" class="drawer-switch">
+ <el-radio-button label="card">卡片</el-radio-button>
+ <el-radio-button label="chrome">谷歌</el-radio-button>
+ </el-radio-group>
+ </div>
+
+ <div class="drawer-item">
+ <span>固定 Header</span>
+ <el-switch v-model="fixedHeader" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>显示 Logo</span>
+ <el-switch v-model="sidebarLogo" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>动态标题</span>
+ <el-switch v-model="dynamicTitle" class="drawer-switch" />
+ </div>
+
+ <div class="drawer-item">
+ <span>底部版权</span>
+ <el-switch v-model="footerVisible" class="drawer-switch" />
+ </div>
+
+ <el-divider/>
+
+ <el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
+ <el-button size="small" plain icon="el-icon-refresh" @click="resetSetting">重置配置</el-button>
+ </div>
+ </div>
+ </el-drawer>
+</template>
+
+<script>
+import ThemePicker from '@/components/ThemePicker'
+
+export default {
+ components: { ThemePicker },
+ expose: ['openSetting'],
+ data() {
+ return {
+ theme: this.$store.state.settings.theme,
+ sideTheme: this.$store.state.settings.sideTheme,
+ navType: this.$store.state.settings.navType,
+ showSettings: false
+ }
+ },
+ computed: {
+ fixedHeader: {
+ get() {
+ return this.$store.state.settings.fixedHeader
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'fixedHeader',
+ value: val
+ })
+ }
+ },
+ tagsViewPersist: {
+ get() {
+ return this.$store.state.settings.tagsViewPersist
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'tagsViewPersist',
+ value: val
+ })
+ }
+ },
+ tagsView: {
+ get() {
+ return this.$store.state.settings.tagsView
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'tagsView',
+ value: val
+ })
+ }
+ },
+ tagsIcon: {
+ get() {
+ return this.$store.state.settings.tagsIcon
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'tagsIcon',
+ value: val
+ })
+ }
+ },
+ tagsViewStyle: {
+ get() {
+ return this.$store.state.settings.tagsViewStyle
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'tagsViewStyle',
+ value: val
+ })
+ }
+ },
+ sidebarLogo: {
+ get() {
+ return this.$store.state.settings.sidebarLogo
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'sidebarLogo',
+ value: val
+ })
+ }
+ },
+ dynamicTitle: {
+ get() {
+ return this.$store.state.settings.dynamicTitle
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'dynamicTitle',
+ value: val
+ })
+ this.$store.dispatch('settings/setTitle', this.$store.state.settings.title)
+ }
+ },
+ footerVisible: {
+ get() {
+ return this.$store.state.settings.footerVisible
+ },
+ set(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'footerVisible',
+ value: val
+ })
+ }
+ }
+ },
+ watch: {
+ navType: {
+ handler(val) {
+ if (val == 1) {
+ this.$store.dispatch("app/toggleSideBarHide", false)
+ }
+ if (val == 2) {
+ }
+ if (val == 3) {
+ this.$store.dispatch("app/toggleSideBarHide", true)
+ }
+ if ([1, 3].includes(val)) {
+ this.$store.commit("SET_SIDEBAR_ROUTERS",this.$store.state.permission.defaultRoutes)
+ }
+ },
+ immediate: true,
+ deep: true
+ }
+ },
+ methods: {
+ themeChange(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'theme',
+ value: val
+ })
+ this.theme = val
+ },
+ handleTheme(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'sideTheme',
+ value: val
+ })
+ this.sideTheme = val
+ },
+ handleNavType(val) {
+ this.$store.dispatch('settings/changeSetting', {
+ key: 'navType',
+ value: val
+ })
+ this.navType = val
+ },
+ openSetting() {
+ this.showSettings = true
+ },
+ closeSetting(){
+ this.showSettings = false
+ },
+ saveSetting() {
+ this.$modal.loading("正在保存到本地,请稍候...")
+ if (!this.tagsViewPersist) {
+ this.$cache.local.remove('tags-view-visited')
+ }
+ this.$cache.local.set(
+ "layout-setting",
+ `{
+ "navType":${this.navType},
+ "tagsView":${this.tagsView},
+ "tagsIcon":${this.tagsIcon},
+ "tagsViewStyle":"${this.tagsViewStyle}",
+ "tagsViewPersist":${this.tagsViewPersist},
+ "fixedHeader":${this.fixedHeader},
+ "sidebarLogo":${this.sidebarLogo},
+ "dynamicTitle":${this.dynamicTitle},
+ "footerVisible":${this.footerVisible},
+ "sideTheme":"${this.sideTheme}",
+ "theme":"${this.theme}"
+ }`
+ )
+ setTimeout(this.$modal.closeLoading(), 1000)
+ },
+ resetSetting() {
+ this.$modal.loading("正在清除设置缓存并刷新,请稍候...")
+ this.$cache.local.remove('tags-view-visited')
+ this.$cache.local.remove("layout-setting")
+ setTimeout("window.location.reload()", 1000)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.setting-drawer-content {
+ .setting-drawer-title {
+ margin-bottom: 12px;
+ color: rgba(0, 0, 0, .85);
+ font-size: 14px;
+ line-height: 22px;
+ font-weight: bold;
+ }
+
+ .setting-drawer-block-checbox {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-top: 10px;
+ margin-bottom: 20px;
+
+ .setting-drawer-block-checbox-item {
+ position: relative;
+ margin-right: 16px;
+ border-radius: 2px;
+ cursor: pointer;
+
+ img {
+ width: 48px;
+ height: 48px;
+ }
+
+ .setting-drawer-block-checbox-selectIcon {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ padding-top: 15px;
+ padding-left: 24px;
+ color: #1890ff;
+ font-weight: 700;
+ font-size: 14px;
+ }
+ }
+ }
+}
+
+.drawer-container {
+ padding: 20px;
+ font-size: 14px;
+ line-height: 1.5;
+ word-wrap: break-word;
+
+ .drawer-title {
+ margin-bottom: 12px;
+ color: rgba(0, 0, 0, .85);
+ font-size: 14px;
+ line-height: 22px;
+ }
+
+ .drawer-item {
+ color: rgba(0, 0, 0, .65);
+ font-size: 14px;
+ padding: 12px 0;
+ }
+
+ .drawer-switch {
+ float: right
+ }
+}
+
+// 导航模式
+.nav-wrap {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-top: 10px;
+ margin-bottom: 20px;
+
+ .activeItem {
+ border: 2px solid #{'var(--theme)'} !important;
+ }
+
+ .item {
+ position: relative;
+ margin-right: 16px;
+ cursor: pointer;
+ width: 56px;
+ height: 48px;
+ border-radius: 4px;
+ background: #f0f2f5;
+ border: 2px solid transparent;
+ }
+
+ .left {
+ b:first-child {
+ display: block;
+ height: 30%;
+ background: #fff;
+ }
+ b:last-child {
+ width: 30%;
+ background: #1b2a47;
+ position: absolute;
+ height: 100%;
+ top: 0;
+ border-radius: 4px 0 0 4px;
+ }
+ }
+ .mix {
+ b:first-child {
+ border-radius: 4px 4px 0 0;
+ display: block;
+ height: 30%;
+ background: #1b2a47;
+ }
+ b:last-child {
+ width: 30%;
+ background: #1b2a47;
+ position: absolute;
+ height: 70%;
+ border-radius: 0 0 0 4px;
+ }
+ }
+ .top {
+ b:first-child {
+ display: block;
+ height: 30%;
+ background: #1b2a47;
+ border-radius: 4px 4px 0 0;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/layout/components/Sidebar/FixiOSBug.js b/sgd-ui/src/layout/components/Sidebar/FixiOSBug.js
new file mode 100644
index 0000000..6823726
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/FixiOSBug.js
@@ -0,0 +1,25 @@
+export default {
+ computed: {
+ device() {
+ return this.$store.state.app.device
+ }
+ },
+ mounted() {
+ // In order to fix the click on menu on the ios device will trigger the mouseleave bug
+ this.fixBugIniOS()
+ },
+ methods: {
+ fixBugIniOS() {
+ const $subMenu = this.$refs.subMenu
+ if ($subMenu) {
+ const handleMouseleave = $subMenu.handleMouseleave
+ $subMenu.handleMouseleave = (e) => {
+ if (this.device === 'mobile') {
+ return
+ }
+ handleMouseleave(e)
+ }
+ }
+ }
+ }
+}
diff --git a/sgd-ui/src/layout/components/Sidebar/Item.vue b/sgd-ui/src/layout/components/Sidebar/Item.vue
new file mode 100644
index 0000000..be3285d
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/Item.vue
@@ -0,0 +1,33 @@
+<script>
+export default {
+ name: 'MenuItem',
+ functional: true,
+ props: {
+ icon: {
+ type: String,
+ default: ''
+ },
+ title: {
+ type: String,
+ default: ''
+ }
+ },
+ render(h, context) {
+ const { icon, title } = context.props
+ const vnodes = []
+
+ if (icon) {
+ vnodes.push(<svg-icon icon-class={icon}/>)
+ }
+
+ if (title) {
+ if (title.length > 5) {
+ vnodes.push(<span slot='title' title={(title)}>{(title)}</span>)
+ } else {
+ vnodes.push(<span slot='title'>{(title)}</span>)
+ }
+ }
+ return vnodes
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/Sidebar/Link.vue b/sgd-ui/src/layout/components/Sidebar/Link.vue
new file mode 100644
index 0000000..8b0bc93
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/Link.vue
@@ -0,0 +1,43 @@
+<template>
+ <component :is="type" v-bind="linkProps(to)">
+ <slot />
+ </component>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+ props: {
+ to: {
+ type: [String, Object],
+ required: true
+ }
+ },
+ computed: {
+ isExternal() {
+ return isExternal(this.to)
+ },
+ type() {
+ if (this.isExternal) {
+ return 'a'
+ }
+ return 'router-link'
+ }
+ },
+ methods: {
+ linkProps(to) {
+ if (this.isExternal) {
+ return {
+ href: to,
+ target: '_blank',
+ rel: 'noopener'
+ }
+ }
+ return {
+ to: to
+ }
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/Sidebar/Logo.vue b/sgd-ui/src/layout/components/Sidebar/Logo.vue
new file mode 100644
index 0000000..966e656
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/Logo.vue
@@ -0,0 +1,95 @@
+<template>
+ <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' && navType !== 3 ? variables.menuBackground : variables.menuLightBackground }">
+ <transition name="sidebarLogoFade">
+ <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+ <img v-if="logo" :src="logo" class="sidebar-logo" />
+ <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' && navType !== 3 ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+ </router-link>
+ <router-link v-else key="expand" class="sidebar-logo-link" to="/">
+ <img v-if="logo" :src="logo" class="sidebar-logo" />
+ <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' && navType !== 3 ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+ </router-link>
+ </transition>
+ </div>
+</template>
+
+<script>
+import logoImg from '@/assets/logo/logo.png'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+ name: 'SidebarLogo',
+ props: {
+ collapse: {
+ type: Boolean,
+ required: true
+ }
+ },
+ computed: {
+ variables() {
+ return variables
+ },
+ sideTheme() {
+ return this.$store.state.settings.sideTheme
+ },
+ navType() {
+ return this.$store.state.settings.navType
+ }
+ },
+ data() {
+ return {
+ title: process.env.VUE_APP_TITLE,
+ logo: logoImg
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.sidebarLogoFade-enter-active {
+ transition: opacity 1.5s;
+}
+
+.sidebarLogoFade-enter,
+.sidebarLogoFade-leave-to {
+ opacity: 0;
+}
+
+.sidebar-logo-container {
+ position: relative;
+ height: 50px;
+ line-height: 50px;
+ background: #2b2f3a;
+ text-align: center;
+ overflow: hidden;
+
+ & .sidebar-logo-link {
+ height: 100%;
+ width: 100%;
+
+ & .sidebar-logo {
+ width: 32px;
+ height: 32px;
+ vertical-align: middle;
+ margin-right: 12px;
+ }
+
+ & .sidebar-title {
+ display: inline-block;
+ margin: 0;
+ color: #fff;
+ font-weight: 600;
+ line-height: 50px;
+ font-size: 14px;
+ font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+ vertical-align: middle;
+ }
+ }
+
+ &.collapse {
+ .sidebar-logo {
+ margin-right: 0px;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/layout/components/Sidebar/SidebarItem.vue b/sgd-ui/src/layout/components/Sidebar/SidebarItem.vue
new file mode 100644
index 0000000..bddb65f
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/SidebarItem.vue
@@ -0,0 +1,99 @@
+<template>
+ <div v-if="!item.hidden">
+ <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
+ <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
+ <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+ <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
+ </el-menu-item>
+ </app-link>
+ </template>
+
+ <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+ <template slot="title">
+ <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+ </template>
+ <sidebar-item
+ v-for="(child, index) in item.children"
+ :key="child.path + index"
+ :is-nest="true"
+ :item="child"
+ :base-path="resolvePath(child.path)"
+ class="nest-menu"
+ />
+ </el-submenu>
+ </div>
+</template>
+
+<script>
+import path from 'path'
+import { isExternal } from '@/utils/validate'
+import Item from './Item'
+import AppLink from './Link'
+import FixiOSBug from './FixiOSBug'
+
+export default {
+ name: 'SidebarItem',
+ components: { Item, AppLink },
+ mixins: [FixiOSBug],
+ props: {
+ // route object
+ item: {
+ type: Object,
+ required: true
+ },
+ isNest: {
+ type: Boolean,
+ default: false
+ },
+ basePath: {
+ type: String,
+ default: ''
+ }
+ },
+ data() {
+ this.onlyOneChild = null
+ return {}
+ },
+ methods: {
+ hasOneShowingChild(children = [], parent) {
+ if (!children) {
+ children = []
+ }
+ const showingChildren = children.filter(item => {
+ if (item.hidden) {
+ return false
+ }
+ // Temp set(will be used if only has one showing child)
+ this.onlyOneChild = item
+ return true
+ })
+
+ // When there is only one child router, the child router is displayed by default
+ if (showingChildren.length === 1) {
+ return true
+ }
+
+ // Show parent if there are no child router to display
+ if (showingChildren.length === 0) {
+ this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
+ return true
+ }
+
+ return false
+ },
+ resolvePath(routePath, routeQuery) {
+ if (isExternal(routePath)) {
+ return routePath
+ }
+ if (isExternal(this.basePath)) {
+ return this.basePath
+ }
+ if (routeQuery) {
+ let query = JSON.parse(routeQuery)
+ return { path: path.resolve(this.basePath, routePath), query: query }
+ }
+ return path.resolve(this.basePath, routePath)
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/Sidebar/index.vue b/sgd-ui/src/layout/components/Sidebar/index.vue
new file mode 100644
index 0000000..817694f
--- /dev/null
+++ b/sgd-ui/src/layout/components/Sidebar/index.vue
@@ -0,0 +1,57 @@
+<template>
+ <div :class="['sidebar-theme-wrapper', {'has-logo':showLogo}, settings.sideTheme]" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
+ <logo v-if="showLogo" :collapse="isCollapse" />
+ <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
+ <el-menu
+ :default-active="activeMenu"
+ :collapse="isCollapse"
+ :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
+ :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
+ :unique-opened="true"
+ :active-text-color="settings.theme"
+ :collapse-transition="false"
+ mode="vertical"
+ >
+ <sidebar-item
+ v-for="(route, index) in sidebarRouters"
+ :key="route.path + index"
+ :item="route"
+ :base-path="route.path"
+ />
+ </el-menu>
+ </el-scrollbar>
+ </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex"
+import Logo from "./Logo"
+import SidebarItem from "./SidebarItem"
+import variables from "@/assets/styles/variables.scss"
+
+export default {
+ components: { SidebarItem, Logo },
+ computed: {
+ ...mapState(["settings"]),
+ ...mapGetters(["sidebarRouters", "sidebar"]),
+ activeMenu() {
+ const route = this.$route
+ const { meta, path } = route
+ // if set path, the sidebar will highlight the path you set
+ if (meta.activeMenu) {
+ return meta.activeMenu
+ }
+ return path
+ },
+ showLogo() {
+ return this.$store.state.settings.sidebarLogo
+ },
+ variables() {
+ return variables
+ },
+ isCollapse() {
+ return !this.sidebar.opened
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/layout/components/TagsView/ScrollPane.vue b/sgd-ui/src/layout/components/TagsView/ScrollPane.vue
new file mode 100644
index 0000000..706fa2e
--- /dev/null
+++ b/sgd-ui/src/layout/components/TagsView/ScrollPane.vue
@@ -0,0 +1,149 @@
+<template>
+ <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
+ <slot />
+ </el-scrollbar>
+</template>
+
+<script>
+const tagAndTagSpacing = 4
+
+export default {
+ name: 'ScrollPane',
+ data() {
+ return {
+ left: 0
+ }
+ },
+ computed: {
+ scrollWrapper() {
+ return this.$refs.scrollContainer.$refs.wrap
+ }
+ },
+ mounted() {
+ this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
+ },
+ beforeDestroy() {
+ this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
+ },
+ methods: {
+ smoothScrollTo(target) {
+ const $scrollWrapper = this.scrollWrapper
+ const start = $scrollWrapper.scrollLeft
+ const distance = target - start
+ const duration = 300
+ let startTime = null
+
+ function ease(t, b, c, d) {
+ t /= d / 2
+ if (t < 1) return c / 2 * t * t + b
+ t--
+ return -c / 2 * (t * (t - 2) - 1) + b
+ }
+
+ const emit = this.$emit.bind(this)
+ function step(timestamp) {
+ if (!startTime) startTime = timestamp
+ const elapsed = timestamp - startTime
+ $scrollWrapper.scrollLeft = ease(elapsed, start, distance, duration)
+ if (elapsed < duration) {
+ requestAnimationFrame(step)
+ } else {
+ $scrollWrapper.scrollLeft = target
+ emit('updateArrows')
+ }
+ }
+
+ requestAnimationFrame(step)
+ },
+ handleScroll(e) {
+ const eventDelta = e.wheelDelta || -e.deltaY * 40
+ const $scrollWrapper = this.scrollWrapper
+ $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+ this.$emit('updateArrows')
+ },
+ emitScroll() {
+ this.$emit('scroll')
+ this.$emit('updateArrows')
+ },
+ moveToTarget(currentTag) {
+ const $container = this.$refs.scrollContainer.$el
+ const $containerWidth = $container.offsetWidth
+ const $scrollWrapper = this.scrollWrapper
+ const tagList = this.$parent.$refs.tag
+
+ let firstTag = null
+ let lastTag = null
+
+ if (tagList.length > 0) {
+ firstTag = tagList[0]
+ lastTag = tagList[tagList.length - 1]
+ }
+
+ if (firstTag === currentTag) {
+ this.smoothScrollTo(0)
+ } else if (lastTag === currentTag) {
+ this.smoothScrollTo($scrollWrapper.scrollWidth - $containerWidth)
+ } else {
+ const currentIndex = tagList.findIndex(item => item === currentTag)
+ const prevTag = tagList[currentIndex - 1]
+ const nextTag = tagList[currentIndex + 1]
+ const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+ const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+
+ if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+ this.smoothScrollTo(afterNextTagOffsetLeft - $containerWidth)
+ } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+ this.smoothScrollTo(beforePrevTagOffsetLeft)
+ }
+ }
+ },
+ // 向左滚动固定距离
+ scrollLeft() {
+ const $scrollWrapper = this.scrollWrapper
+ this.smoothScrollTo(Math.max(0, $scrollWrapper.scrollLeft - 200))
+ },
+ // 向右滚动固定距离
+ scrollRight() {
+ const $scrollWrapper = this.scrollWrapper
+ const maxScroll = $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth
+ this.smoothScrollTo(Math.min(maxScroll, $scrollWrapper.scrollLeft + 200))
+ },
+ // 直接平滑滚动到最左端
+ scrollToStart() {
+ this.smoothScrollTo(0)
+ },
+ // 直接平滑滚动到最右端
+ scrollToEnd() {
+ const $scrollWrapper = this.scrollWrapper
+ this.smoothScrollTo($scrollWrapper.scrollWidth - $scrollWrapper.clientWidth)
+ },
+ // 获取是否可以继续向左/右滚动
+ getScrollState() {
+ const $scrollWrapper = this.scrollWrapper
+ return {
+ canLeft: $scrollWrapper.scrollLeft > 0,
+ canRight: $scrollWrapper.scrollLeft < $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth - 1
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-container {
+ white-space: nowrap;
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+ ::v-deep {
+ .el-scrollbar__bar {
+ bottom: 0px;
+ }
+ .el-scrollbar__wrap {
+ height: 34px;
+ display: flex;
+ align-items: center;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/layout/components/TagsView/index.vue b/sgd-ui/src/layout/components/TagsView/index.vue
new file mode 100644
index 0000000..97947eb
--- /dev/null
+++ b/sgd-ui/src/layout/components/TagsView/index.vue
@@ -0,0 +1,760 @@
+<template>
+ <div id="tags-view-container" class="tags-view-container" :class="{ 'tags-view-container--chrome': tagsViewStyle === 'chrome' }" :style="chromeVars">
+ <!-- 左切换箭头 -->
+ <span class="tags-nav-btn tags-nav-btn--left" :class="{ disabled: !canScrollLeft }" @click="scrollLeft">
+ <i class="el-icon-arrow-left" />
+ </span>
+
+ <!-- 标签滚动区 -->
+ <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll" @updateArrows="updateArrowState">
+ <router-link
+ v-for="tag in visitedViews"
+ ref="tag"
+ :key="tag.path"
+ :class="{ 'active': isActive(tag), 'has-icon': tagsIcon }"
+ :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+ tag="span"
+ class="tags-view-item"
+ :style="tagActiveStyle(tag)"
+ @click.middle.native="!isAffix(tag) ? closeSelectedTag(tag) : ''"
+ @contextmenu.prevent.native="openMenu(tag, $event)"
+ >
+ <svg-icon v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'" :icon-class="tag.meta.icon" style="margin-right: 3px;" />
+ {{ tag.title }}
+ <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+ </router-link>
+ </scroll-pane>
+
+ <!-- 右切换箭头 -->
+ <span class="tags-nav-btn tags-nav-btn--right" :class="{ disabled: !canScrollRight }" @click="scrollRight">
+ <i class="el-icon-arrow-right" />
+ </span>
+
+ <!-- 下拉操作菜单 -->
+ <el-dropdown class="tags-action-dropdown" trigger="click" placement="bottom-end" @command="handleDropdownCommand">
+ <span class="tags-action-btn">
+ <i class="el-icon-arrow-down" />
+ </span>
+ <el-dropdown-menu slot="dropdown" class="tags-dropdown-menu">
+ <el-dropdown-item v-if="!isAffix(selectedDropdownTag)" command="close" icon="el-icon-close">关闭当前</el-dropdown-item>
+ <el-dropdown-item command="closeOthers" icon="el-icon-circle-close">关闭其他</el-dropdown-item>
+ <el-dropdown-item command="closeLeft" :disabled="isFirstView()" icon="el-icon-back">关闭左侧</el-dropdown-item>
+ <el-dropdown-item command="closeRight" :disabled="isLastView()" icon="el-icon-right">关闭右侧</el-dropdown-item>
+ <el-dropdown-item command="closeAll" icon="el-icon-circle-close">全部关闭</el-dropdown-item>
+ <el-dropdown-item command="fullscreen" divided>
+ <template v-if="!isFullscreen"><i class="el-icon-full-screen"></i>全屏显示</template>
+ <template v-else><i class="el-icon-close"></i>退出全屏</template>
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+
+ <!-- 刷新按钮 -->
+ <span class="tags-action-btn tags-refresh-btn" title="刷新页面" @click="refreshSelectedTag(selectedDropdownTag)">
+ <i class="el-icon-refresh-right" /> 刷新
+ </span>
+
+ <!-- 右键上下文菜单 -->
+ <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
+ <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>
+ <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>
+ <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li>
+ <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li>
+ <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li>
+ <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li>
+ </ul>
+ </div>
+</template>
+
+<script>
+import ScrollPane from './ScrollPane'
+import path from 'path'
+
+export default {
+ components: { ScrollPane },
+ data() {
+ return {
+ visible: false,
+ top: 0,
+ left: 0,
+ selectedTag: {},
+ affixTags: [],
+ canScrollLeft: false,
+ canScrollRight: false,
+ isFullscreen: false,
+ hiddenElements: []
+ }
+ },
+ computed: {
+ visitedViews() {
+ return this.$store.state.tagsView.visitedViews
+ },
+ routes() {
+ return this.$store.state.permission.routes
+ },
+ theme() {
+ return this.$store.state.settings.theme
+ },
+ tagsIcon() {
+ return this.$store.state.settings.tagsIcon
+ },
+ tagsViewStyle() {
+ return this.$store.state.settings.tagsViewStyle
+ },
+ selectedDropdownTag() {
+ return this.visitedViews.find(v => this.isActive(v)) || {}
+ },
+ chromeVars() {
+ if (this.tagsViewStyle !== 'chrome') return {}
+ const primary = this.theme || '#409EFF'
+ return {
+ '--chrome-tab-active-bg': this.mixHexWithWhite(primary, 0.15),
+ '--chrome-tab-text-active': primary,
+ '--chrome-wing-r': '14px'
+ }
+ }
+ },
+ watch: {
+ $route() {
+ this.addTags()
+ this.moveToCurrentTag()
+ },
+ visible(value) {
+ if (value) {
+ document.body.addEventListener('click', this.closeMenu)
+ } else {
+ document.body.removeEventListener('click', this.closeMenu)
+ }
+ },
+ visitedViews() {
+ this.$nextTick(() => {
+ this.updateArrowState()
+ })
+ }
+ },
+ mounted() {
+ this.initTags()
+ this.addTags()
+ window.addEventListener('resize', this.updateArrowState)
+ window.addEventListener('keydown', this.handleKeyDown)
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.updateArrowState)
+ window.removeEventListener('keydown', this.handleKeyDown)
+ },
+ methods: {
+ handleKeyDown(event) {
+ // 当按下Esc键且处于全屏状态时,退出全屏
+ if (event.key === 'Escape' && this.isFullscreen) {
+ this.toggleFullscreen()
+ }
+ },
+ mixHexWithWhite(hex, ratio) {
+ const clean = hex.replace('#', '')
+ const r = parseInt(clean.substring(0, 2), 16)
+ const g = parseInt(clean.substring(2, 4), 16)
+ const b = parseInt(clean.substring(4, 6), 16)
+ const mr = Math.round(r * ratio + 255 * (1 - ratio))
+ const mg = Math.round(g * ratio + 255 * (1 - ratio))
+ const mb = Math.round(b * ratio + 255 * (1 - ratio))
+ return `rgb(${mr}, ${mg}, ${mb})`
+ },
+ isActive(route) {
+ return route.path === this.$route.path
+ },
+ tagActiveStyle(tag) {
+ if (!this.isActive(tag) || this.tagsViewStyle !== 'card') return {}
+ return {
+ "background-color": this.theme,
+ "border-color": this.theme
+ }
+ },
+ isAffix(tag) {
+ return tag && tag.meta && tag.meta.affix
+ },
+ isFirstView() {
+ try {
+ const tag = this.selectedTag && this.selectedTag.fullPath ? this.selectedTag : this.selectedDropdownTag
+ return tag.fullPath === '/index' || tag.fullPath === this.visitedViews[1].fullPath
+ } catch (err) {
+ return false
+ }
+ },
+ isLastView() {
+ try {
+ const tag = this.selectedTag && this.selectedTag.fullPath ? this.selectedTag : this.selectedDropdownTag
+ return tag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
+ } catch (err) {
+ return false
+ }
+ },
+ filterAffixTags(routes, basePath = '/') {
+ let tags = []
+ routes.forEach(route => {
+ if (route.meta && route.meta.affix) {
+ const tagPath = path.resolve(basePath, route.path)
+ tags.push({
+ fullPath: tagPath,
+ path: tagPath,
+ name: route.name,
+ meta: { ...route.meta }
+ })
+ }
+ if (route.children) {
+ const tempTags = this.filterAffixTags(route.children, route.path)
+ if (tempTags.length >= 1) {
+ tags = [...tags, ...tempTags]
+ }
+ }
+ })
+ return tags
+ },
+ initTags() {
+ if (this.$store.state.settings.tagsViewPersist) {
+ this.$store.dispatch('tagsView/loadPersistedViews')
+ }
+ const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+ for (const tag of affixTags) {
+ if (tag.name) {
+ this.$store.dispatch('tagsView/addAffixView', tag)
+ }
+ }
+ },
+ addTags() {
+ const { name } = this.$route
+ if (name) {
+ this.$store.dispatch('tagsView/addView', this.$route)
+ }
+ },
+ moveToCurrentTag() {
+ const tags = this.$refs.tag
+ this.$nextTick(() => {
+ for (const tag of tags) {
+ if (tag.to.path === this.$route.path) {
+ this.$refs.scrollPane.moveToTarget(tag)
+ if (tag.to.fullPath !== this.$route.fullPath) {
+ this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+ }
+ break
+ }
+ }
+ })
+ },
+ scrollLeft() {
+ if (!this.canScrollLeft) return
+ this.$refs.scrollPane.scrollToStart()
+ },
+ scrollRight() {
+ if (!this.canScrollRight) return
+ this.$refs.scrollPane.scrollToEnd()
+ },
+ updateArrowState() {
+ this.$nextTick(() => {
+ if (this.$refs.scrollPane) {
+ const state = this.$refs.scrollPane.getScrollState()
+ this.canScrollLeft = state.canLeft
+ this.canScrollRight = state.canRight
+ }
+ })
+ },
+ toggleFullscreen() {
+ const mainContainer = document.querySelector('.main-container')
+ const navbar = document.querySelector('.navbar')
+ const sidebar = document.querySelector('.sidebar-container')
+ if (!mainContainer) return
+
+ if (!this.isFullscreen) {
+ mainContainer.classList.add('fullscreen-mode')
+ document.body.style.overflow = 'hidden'
+ const elementsToHide = [
+ { el: navbar, originalDisplay: (navbar && navbar.style.display) || '' },
+ { el: sidebar, originalDisplay: (sidebar && sidebar.style.display) || '' }
+ ]
+ elementsToHide.forEach(item => {
+ if (item.el && item.el.style.display !== 'none') {
+ item.originalDisplay = item.el.style.display
+ item.el.style.display = 'none'
+ this.hiddenElements.push(item)
+ }
+ })
+ this.isFullscreen = true
+ } else {
+ mainContainer.classList.remove('fullscreen-mode')
+ document.body.style.overflow = ''
+ this.hiddenElements.forEach(item => {
+ if (item.el) {
+ item.el.style.display = item.originalDisplay
+ }
+ })
+ this.hiddenElements = []
+ const btn = document.querySelector('.tags-action-btn')
+ if (btn) btn.blur()
+ this.isFullscreen = false
+ }
+ },
+ handleDropdownCommand(command) {
+ const tag = this.selectedDropdownTag
+ this.selectedTag = tag
+ switch (command) {
+ case 'refresh':
+ this.refreshSelectedTag(tag)
+ break
+ case 'fullscreen':
+ this.toggleFullscreen()
+ break
+ case 'close':
+ this.closeSelectedTag(tag)
+ break
+ case 'closeOthers':
+ this.closeOthersTags()
+ break
+ case 'closeLeft':
+ this.closeLeftTags()
+ break
+ case 'closeRight':
+ this.closeRightTags()
+ break
+ case 'closeAll':
+ this.closeAllTags(tag)
+ break
+ }
+ },
+ refreshSelectedTag(view) {
+ this.$tab.refreshPage(view)
+ if (this.$route.meta.link) {
+ this.$store.dispatch('tagsView/delIframeView', this.$route)
+ }
+ },
+ closeSelectedTag(view) {
+ this.$tab.closePage(view).then(({ visitedViews }) => {
+ if (this.isActive(view)) {
+ this.toLastView(visitedViews, view)
+ }
+ })
+ },
+ closeRightTags() {
+ this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
+ if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
+ this.toLastView(visitedViews)
+ }
+ })
+ },
+ closeLeftTags() {
+ this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
+ if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
+ this.toLastView(visitedViews)
+ }
+ })
+ },
+ closeOthersTags() {
+ this.$router.push(this.selectedTag.fullPath).catch(() => {})
+ this.$tab.closeOtherPage(this.selectedTag).then(() => {
+ this.moveToCurrentTag()
+ })
+ },
+ closeAllTags(view) {
+ this.$tab.closeAllPage().then(({ visitedViews }) => {
+ if (this.affixTags.some(tag => tag.path === this.$route.path)) {
+ return
+ }
+ this.toLastView(visitedViews, view)
+ })
+ },
+ toLastView(visitedViews, view) {
+ const latestView = visitedViews.slice(-1)[0]
+ if (latestView) {
+ this.$router.push(latestView.fullPath)
+ } else {
+ if (view && view.name === 'Dashboard') {
+ this.$router.replace({ path: '/redirect' + view.fullPath })
+ } else {
+ this.$router.push('/')
+ }
+ }
+ },
+ openMenu(tag, e) {
+ this.left = e.clientX
+ this.top = e.clientY
+ this.visible = true
+ this.selectedTag = tag
+ },
+ closeMenu() {
+ this.visible = false
+ },
+ handleScroll() {
+ this.closeMenu()
+ this.updateArrowState()
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+$tags-bar-height: 34px;
+
+.tags-view-container {
+ height: $tags-bar-height;
+ width: 100%;
+ background: #fff;
+ border-bottom: 1px solid #d8dce5;
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+
+ $btn-width: 28px;
+ $btn-color: #71717a;
+ $btn-hover-bg: #f0f2f5;
+ $btn-hover-color: #303133;
+ $btn-disabled-color: #c0c4cc;
+ $divider: 1px solid #d8dce5;
+
+ .tags-nav-btn {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: $btn-width;
+ height: $tags-bar-height;
+ cursor: pointer;
+ color: $btn-color;
+ font-size: 13px;
+ user-select: none;
+ transition: background 0.15s, color 0.15s;
+
+ &:hover:not(.disabled) {
+ background: $btn-hover-bg;
+ color: $btn-hover-color;
+ }
+
+ &.disabled {
+ color: $btn-disabled-color;
+ cursor: not-allowed;
+ }
+
+ &--left { border-right: $divider; }
+ &--right { border-left: $divider; }
+ }
+
+ .tags-view-wrapper {
+ flex: 1;
+ min-width: 0;
+ height: 100%;
+
+ .tags-view-item {
+ display: inline-block;
+ position: relative;
+ cursor: pointer;
+ height: 26px;
+ line-height: 26px;
+ border: 1px solid #d8dce5;
+ color: #495060;
+ background: #fff;
+ padding: 0 8px;
+ font-size: 12px;
+ margin-left: 5px;
+ border-radius: 3px;
+
+ &:first-of-type { margin-left: 6px; }
+ &:last-of-type { margin-right: 15px; }
+ }
+ }
+ &:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active {
+ background-color: #42b983;
+ color: #fff;
+ border-color: #42b983;
+ &::before {
+ content: '';
+ background: #fff;
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ position: relative;
+ margin-right: 2px;
+ }
+ }
+
+ &:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active.has-icon::before {
+ content: none !important;
+ }
+
+ .tags-action-dropdown {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ }
+
+ .tags-action-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: $btn-width;
+ height: $tags-bar-height;
+ cursor: pointer;
+ color: $btn-color;
+ font-size: 13px;
+ border-left: $divider;
+ user-select: none;
+ transition: background 0.15s, color 0.15s;
+
+ &:hover {
+ background: $btn-hover-bg;
+ color: $btn-hover-color;
+ }
+ }
+
+ .tags-refresh-btn {
+ width: 60px;
+ }
+
+ .contextmenu {
+ margin: 0;
+ background: #fff;
+ z-index: 3000;
+ position: fixed;
+ list-style-type: none;
+ padding: 5px 0;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 400;
+ color: #333;
+ box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+
+ li {
+ margin: 0;
+ padding: 7px 16px;
+ cursor: pointer;
+ &:hover {
+ background: #eee;
+ }
+ }
+ }
+ &.tags-view-container--chrome {
+ --chrome-strip-bg: #ffffff;
+ --chrome-strip-border: #e4e7ed;
+ --chrome-tab-text: #606266;
+
+ overflow: visible;
+ background: var(--chrome-strip-bg);
+ border-bottom: 1px solid var(--chrome-strip-border);
+ align-items: flex-end;
+
+ .tags-nav-btn {
+ align-self: stretch;
+ height: auto;
+ min-height: $tags-bar-height;
+ border-color: var(--chrome-strip-border);
+ }
+
+ .tags-action-btn {
+ border-color: var(--chrome-strip-border);
+ }
+
+ .tags-view-wrapper {
+ .tags-view-item {
+ display: inline-flex !important;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ z-index: 1;
+ height: 30px;
+ min-height: 30px;
+ margin: 0 0 -1px;
+ padding: 0 12px;
+ font-size: 13px;
+ font-weight: 400;
+ line-height: 1.2;
+ border: none !important;
+ border-radius: 0;
+ background: transparent !important;
+ color: var(--chrome-tab-text) !important;
+ padding-top: 0 !important;
+ box-shadow: none !important;
+ transition: background 0.12s ease, color 0.12s ease, border-radius 0.12s ease;
+
+ &::before,
+ &::after {
+ content: '' !important;
+ display: block !important;
+ position: absolute;
+ bottom: 0;
+ width: var(--chrome-wing-r);
+ height: var(--chrome-wing-r);
+ margin: 0 !important;
+ pointer-events: none;
+ background: transparent !important;
+ border-radius: 0 !important;
+ transition: box-shadow 0.12s ease;
+ }
+
+ &::before {
+ left: calc(-1 * var(--chrome-wing-r));
+ border-bottom-right-radius: var(--chrome-wing-r) !important;
+ box-shadow: none;
+ }
+
+ &::after {
+ right: calc(-1 * var(--chrome-wing-r));
+ border-bottom-left-radius: var(--chrome-wing-r) !important;
+ box-shadow: none;
+ }
+
+ &:first-of-type { margin-left: 6px; }
+ &:last-of-type { margin-right: 10px; }
+
+ &:not(.active) + .tags-view-item:not(.active) {
+ border-left: 1px solid #e4e7ed;
+ padding-left: 11px;
+ }
+
+ &:hover:not(.active) {
+ background: #f5f7fa !important;
+ border-radius: 6px 6px 0 0;
+ color: #303133 !important;
+ }
+
+ &.active {
+ height: 31px;
+ min-height: 31px;
+ padding: 0 14px;
+ color: var(--chrome-tab-text-active) !important;
+ font-weight: 500;
+ background: var(--chrome-tab-active-bg) !important;
+ border: none !important;
+ border-radius: var(--chrome-wing-r) var(--chrome-wing-r) 0 0;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
+
+ &::before {
+ box-shadow: calc(var(--chrome-wing-r) * 0.5) calc(var(--chrome-wing-r) * 0.5) 0 calc(var(--chrome-wing-r) * 0.5) var(--chrome-tab-active-bg);
+ }
+
+ &::after {
+ box-shadow: calc(var(--chrome-wing-r) * -0.5) calc(var(--chrome-wing-r) * 0.5) 0 calc(var(--chrome-wing-r) * 0.5) var(--chrome-tab-active-bg);
+ }
+ }
+ .el-icon-close {
+ margin-left: 3px;
+ &:before {
+ vertical-align: -2px;
+ }
+ }
+ }
+ }
+ }
+}
+</style>
+
+<style lang="scss">
+.tags-view-wrapper {
+ .el-scrollbar {
+ height: 100%;
+ overflow: hidden;
+ }
+
+ .el-scrollbar__wrap {
+ height: 34px !important;
+ display: flex;
+ align-items: center;
+ overflow-x: auto;
+ overflow-y: hidden;
+
+ &::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ }
+
+ .tags-view-container:hover & {
+ &::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: rgba(0, 0, 0, 0.2);
+ border-radius: 3px;
+ transition: background-color 0.2s;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.4);
+ }
+ }
+ }
+
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+
+ .el-scrollbar__bar {
+ opacity: 0;
+ transition: opacity 0.3s;
+
+ .tags-view-container:hover & {
+ opacity: 1;
+ }
+ }
+
+ .tags-view-item {
+ .el-icon-close {
+ width: 16px;
+ height: 16px;
+ vertical-align: 2px;
+ border-radius: 50%;
+ text-align: center;
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
+ transform-origin: 100% 50%;
+ &:before {
+ transform: scale(.6);
+ display: inline-block;
+ vertical-align: -3px;
+ }
+ &:hover {
+ background-color: #b4bccc;
+ color: #fff;
+ }
+ }
+ }
+}
+
+/* 页签全屏模式样式 */
+.main-container.fullscreen-mode {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ margin-left: 0 !important;
+ transition: none !important;
+}
+
+.main-container.fullscreen-mode .fixed-header {
+ display: block !important;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ width: 100% !important;
+ z-index: 1000;
+ transition: none !important;
+}
+
+.main-container.fullscreen-mode .fixed-header .navbar {
+ display: none !important;
+}
+
+.main-container.fullscreen-mode .app-main {
+ position: fixed;
+ top: 34px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: 0 !important;
+ padding: 0 !important;
+ height: calc(100vh - 34px) !important;
+ min-height: calc(100vh - 34px) !important;
+ overflow: auto;
+}
+</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/layout/components/TopBar/index.vue b/sgd-ui/src/layout/components/TopBar/index.vue
similarity index 100%
rename from ruoyi-ui/src/layout/components/TopBar/index.vue
rename to sgd-ui/src/layout/components/TopBar/index.vue
diff --git a/ruoyi-ui/src/layout/components/TopNav/index.vue b/sgd-ui/src/layout/components/TopNav/index.vue
similarity index 100%
rename from ruoyi-ui/src/layout/components/TopNav/index.vue
rename to sgd-ui/src/layout/components/TopNav/index.vue
diff --git a/sgd-ui/src/layout/components/index.js b/sgd-ui/src/layout/components/index.js
new file mode 100644
index 0000000..104bd3a
--- /dev/null
+++ b/sgd-ui/src/layout/components/index.js
@@ -0,0 +1,5 @@
+export { default as AppMain } from './AppMain'
+export { default as Navbar } from './Navbar'
+export { default as Settings } from './Settings'
+export { default as Sidebar } from './Sidebar/index.vue'
+export { default as TagsView } from './TagsView/index.vue'
diff --git a/sgd-ui/src/layout/index.vue b/sgd-ui/src/layout/index.vue
new file mode 100644
index 0000000..532edfe
--- /dev/null
+++ b/sgd-ui/src/layout/index.vue
@@ -0,0 +1,115 @@
+<template>
+ <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33'}">
+ <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
+ <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
+ <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
+ <div :class="{'fixed-header':fixedHeader}">
+ <navbar @setLayout="setLayout"/>
+ <tags-view v-if="needTagsView"/>
+ </div>
+ <app-main/>
+ <settings ref="settingRef"/>
+ </div>
+ </div>
+</template>
+
+<script>
+import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+import { mapState } from 'vuex'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+ name: 'Layout',
+ components: {
+ AppMain,
+ Navbar,
+ Settings,
+ Sidebar,
+ TagsView
+ },
+ mixins: [ResizeMixin],
+ computed: {
+ ...mapState({
+ theme: state => state.settings.theme,
+ sideTheme: state => state.settings.sideTheme,
+ sidebar: state => state.app.sidebar,
+ device: state => state.app.device,
+ needTagsView: state => state.settings.tagsView,
+ fixedHeader: state => state.settings.fixedHeader
+ }),
+ classObj() {
+ return {
+ hideSidebar: !this.sidebar.opened,
+ openSidebar: this.sidebar.opened,
+ withoutAnimation: this.sidebar.withoutAnimation,
+ mobile: this.device === 'mobile'
+ }
+ },
+ variables() {
+ return variables
+ }
+ },
+ methods: {
+ handleClickOutside() {
+ this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+ },
+ setLayout() {
+ this.$refs.settingRef.openSetting()
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+ @import "~@/assets/styles/mixin.scss";
+ @import "~@/assets/styles/variables.scss";
+
+ .app-wrapper {
+ @include clearfix;
+ position: relative;
+ height: 100%;
+ width: 100%;
+
+ &.mobile.openSidebar {
+ position: fixed;
+ top: 0;
+ }
+ }
+
+ .main-container:has(.fixed-header) {
+ height: 100vh;
+ overflow: hidden;
+ }
+
+ .drawer-bg {
+ background: #000;
+ opacity: 0.3;
+ width: 100%;
+ top: 0;
+ height: 100%;
+ position: absolute;
+ z-index: 999;
+ }
+
+ .fixed-header {
+ position: fixed;
+ top: 0;
+ right: 0;
+ z-index: 9;
+ width: calc(100% - #{$base-sidebar-width});
+ transition: width 0.28s;
+ }
+
+ .hideSidebar .fixed-header {
+ width: calc(100% - 54px);
+ }
+
+ .sidebarHide .fixed-header {
+ width: 100%;
+ }
+
+ .mobile .fixed-header {
+ width: 100%;
+ }
+</style>
diff --git a/sgd-ui/src/layout/mixin/ResizeHandler.js b/sgd-ui/src/layout/mixin/ResizeHandler.js
new file mode 100644
index 0000000..e8d0df8
--- /dev/null
+++ b/sgd-ui/src/layout/mixin/ResizeHandler.js
@@ -0,0 +1,45 @@
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+export default {
+ watch: {
+ $route(route) {
+ if (this.device === 'mobile' && this.sidebar.opened) {
+ store.dispatch('app/closeSideBar', { withoutAnimation: false })
+ }
+ }
+ },
+ beforeMount() {
+ window.addEventListener('resize', this.$_resizeHandler)
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.$_resizeHandler)
+ },
+ mounted() {
+ const isMobile = this.$_isMobile()
+ if (isMobile) {
+ store.dispatch('app/toggleDevice', 'mobile')
+ store.dispatch('app/closeSideBar', { withoutAnimation: true })
+ }
+ },
+ methods: {
+ // use $_ for mixins properties
+ // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+ $_isMobile() {
+ const rect = body.getBoundingClientRect()
+ return rect.width - 1 < WIDTH
+ },
+ $_resizeHandler() {
+ if (!document.hidden) {
+ const isMobile = this.$_isMobile()
+ store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
+
+ if (isMobile) {
+ store.dispatch('app/closeSideBar', { withoutAnimation: true })
+ }
+ }
+ }
+ }
+}
diff --git a/sgd-ui/src/main.js b/sgd-ui/src/main.js
new file mode 100644
index 0000000..da01750
--- /dev/null
+++ b/sgd-ui/src/main.js
@@ -0,0 +1,83 @@
+import Vue from 'vue'
+
+import Cookies from 'js-cookie'
+
+import Element from 'element-ui'
+import './assets/styles/element-variables.scss'
+
+import '@/assets/styles/index.scss' // global css
+import '@/assets/styles/ruoyi.scss' // ruoyi css
+import App from './App'
+import store from './store'
+import router from './router'
+import directive from './directive' // directive
+import plugins from './plugins' // plugins
+import { download } from '@/utils/request'
+
+import './assets/icons' // icon
+import './permission' // permission control
+import { getDicts } from "@/api/system/dict/data"
+import { getConfigKey } from "@/api/system/config"
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"
+// 分页组件
+import Pagination from "@/components/Pagination"
+// 自定义表格工具组件
+import RightToolbar from "@/components/RightToolbar"
+// 富文本组件
+import Editor from "@/components/Editor"
+// 文件上传组件
+import FileUpload from "@/components/FileUpload"
+// 图片上传组件
+import ImageUpload from "@/components/ImageUpload"
+// 图片预览组件
+import ImagePreview from "@/components/ImagePreview"
+// 字典标签组件
+import DictTag from '@/components/DictTag'
+// 字典数据组件
+import DictData from '@/components/DictData'
+
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
+Vue.prototype.handleTree = handleTree
+
+// 全局组件挂载
+Vue.component('DictTag', DictTag)
+Vue.component('Pagination', Pagination)
+Vue.component('RightToolbar', RightToolbar)
+Vue.component('Editor', Editor)
+Vue.component('FileUpload', FileUpload)
+Vue.component('ImageUpload', ImageUpload)
+Vue.component('ImagePreview', ImagePreview)
+
+Vue.use(directive)
+Vue.use(plugins)
+DictData.install()
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online! ! !
+ */
+
+Vue.use(Element, {
+ size: Cookies.get('size') || 'medium' // set element-ui default size
+})
+
+Vue.config.productionTip = false
+
+new Vue({
+ el: '#app',
+ router,
+ store,
+ render: h => h(App)
+})
diff --git a/sgd-ui/src/permission.js b/sgd-ui/src/permission.js
new file mode 100644
index 0000000..b818358
--- /dev/null
+++ b/sgd-ui/src/permission.js
@@ -0,0 +1,70 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { getToken } from '@/utils/auth'
+import { isPathMatch } from '@/utils/validate'
+import { isRelogin } from '@/utils/request'
+
+NProgress.configure({ showSpinner: false })
+
+const whiteList = ['/login', '/register']
+
+const isWhiteList = (path) => {
+ return whiteList.some(pattern => isPathMatch(pattern, path))
+}
+
+router.beforeEach((to, from, next) => {
+ NProgress.start()
+ if (getToken()) {
+ to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
+ const isLock = store.getters.isLock
+ /* has token*/
+ if (to.path === '/login') {
+ next({ path: '/' })
+ NProgress.done()
+ } else if (isWhiteList(to.path)) {
+ next()
+ } else if (isLock && to.path !== '/lock') {
+ next({ path: '/lock' })
+ NProgress.done()
+ } else if (!isLock && to.path === '/lock') {
+ next({ path: '/' })
+ NProgress.done()
+ } else {
+ if (store.getters.roles.length === 0) {
+ isRelogin.show = true
+ // 判断当前用户是否已拉取完user_info信息
+ store.dispatch('GetInfo').then(() => {
+ isRelogin.show = false
+ store.dispatch('GenerateRoutes').then(accessRoutes => {
+ // 根据roles权限生成可访问的路由表
+ router.addRoutes(accessRoutes) // 动态添加可访问路由表
+ next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+ })
+ }).catch(err => {
+ store.dispatch('LogOut').then(() => {
+ Message.error(err)
+ next({ path: '/' })
+ })
+ })
+ } else {
+ next()
+ }
+ }
+ } else {
+ // 没有token
+ if (isWhiteList(to.path)) {
+ // 在免登录白名单,直接进入
+ next()
+ } else {
+ next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页
+ NProgress.done()
+ }
+ }
+})
+
+router.afterEach(() => {
+ NProgress.done()
+})
diff --git a/sgd-ui/src/plugins/auth.js b/sgd-ui/src/plugins/auth.js
new file mode 100644
index 0000000..3b91c14
--- /dev/null
+++ b/sgd-ui/src/plugins/auth.js
@@ -0,0 +1,60 @@
+import store from '@/store'
+
+function authPermission(permission) {
+ const all_permission = "*:*:*"
+ const permissions = store.getters && store.getters.permissions
+ if (permission && permission.length > 0) {
+ return permissions.some(v => {
+ return all_permission === v || v === permission
+ })
+ } else {
+ return false
+ }
+}
+
+function authRole(role) {
+ const super_admin = "admin"
+ const roles = store.getters && store.getters.roles
+ if (role && role.length > 0) {
+ return roles.some(v => {
+ return super_admin === v || v === role
+ })
+ } else {
+ return false
+ }
+}
+
+export default {
+ // 验证用户是否具备某权限
+ hasPermi(permission) {
+ return authPermission(permission)
+ },
+ // 验证用户是否含有指定权限,只需包含其中一个
+ hasPermiOr(permissions) {
+ return permissions.some(item => {
+ return authPermission(item)
+ })
+ },
+ // 验证用户是否含有指定权限,必须全部拥有
+ hasPermiAnd(permissions) {
+ return permissions.every(item => {
+ return authPermission(item)
+ })
+ },
+ // 验证用户是否具备某角色
+ hasRole(role) {
+ return authRole(role)
+ },
+ // 验证用户是否含有指定角色,只需包含其中一个
+ hasRoleOr(roles) {
+ return roles.some(item => {
+ return authRole(item)
+ })
+ },
+ // 验证用户是否含有指定角色,必须全部拥有
+ hasRoleAnd(roles) {
+ return roles.every(item => {
+ return authRole(item)
+ })
+ }
+}
diff --git a/sgd-ui/src/plugins/cache.js b/sgd-ui/src/plugins/cache.js
new file mode 100644
index 0000000..ea8a53f
--- /dev/null
+++ b/sgd-ui/src/plugins/cache.js
@@ -0,0 +1,79 @@
+const sessionCache = {
+ set (key, value) {
+ if (!sessionStorage) {
+ return
+ }
+ if (key != null && value != null) {
+ sessionStorage.setItem(key, value)
+ }
+ },
+ get (key) {
+ if (!sessionStorage) {
+ return null
+ }
+ if (key == null) {
+ return null
+ }
+ return sessionStorage.getItem(key)
+ },
+ setJSON (key, jsonValue) {
+ if (jsonValue != null) {
+ this.set(key, JSON.stringify(jsonValue))
+ }
+ },
+ getJSON (key) {
+ const value = this.get(key)
+ if (value != null) {
+ return JSON.parse(value)
+ }
+ return null
+ },
+ remove (key) {
+ sessionStorage.removeItem(key)
+ }
+}
+const localCache = {
+ set (key, value) {
+ if (!localStorage) {
+ return
+ }
+ if (key != null && value != null) {
+ localStorage.setItem(key, value)
+ }
+ },
+ get (key) {
+ if (!localStorage) {
+ return null
+ }
+ if (key == null) {
+ return null
+ }
+ return localStorage.getItem(key)
+ },
+ setJSON (key, jsonValue) {
+ if (jsonValue != null) {
+ this.set(key, JSON.stringify(jsonValue))
+ }
+ },
+ getJSON (key) {
+ const value = this.get(key)
+ if (value != null) {
+ return JSON.parse(value)
+ }
+ return null
+ },
+ remove (key) {
+ localStorage.removeItem(key)
+ }
+}
+
+export default {
+ /**
+ * 会话级缓存
+ */
+ session: sessionCache,
+ /**
+ * 本地缓存
+ */
+ local: localCache
+}
diff --git a/sgd-ui/src/plugins/download.js b/sgd-ui/src/plugins/download.js
new file mode 100644
index 0000000..8b45033
--- /dev/null
+++ b/sgd-ui/src/plugins/download.js
@@ -0,0 +1,45 @@
+import axios from 'axios'
+import {Loading, Message} from 'element-ui'
+import { saveAs } from 'file-saver'
+import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
+import { blobValidate } from "@/utils/ruoyi"
+
+const baseURL = process.env.VUE_APP_BASE_API
+let downloadLoadingInstance
+
+export default {
+ zip(url, name) {
+ var url = baseURL + url
+ downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
+ axios({
+ method: 'get',
+ url: url,
+ responseType: 'blob',
+ headers: { 'Authorization': 'Bearer ' + getToken() }
+ }).then((res) => {
+ const isBlob = blobValidate(res.data)
+ if (isBlob) {
+ const blob = new Blob([res.data], { type: 'application/zip' })
+ this.saveAs(blob, name)
+ } else {
+ this.printErrMsg(res.data)
+ }
+ downloadLoadingInstance.close()
+ }).catch((r) => {
+ console.error(r)
+ Message.error('下载文件出现错误,请联系管理员!')
+ downloadLoadingInstance.close()
+ })
+ },
+ saveAs(text, name, opts) {
+ saveAs(text, name, opts)
+ },
+ async printErrMsg(data) {
+ const resText = await data.text()
+ const rspObj = JSON.parse(resText)
+ const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+ Message.error(errMsg)
+ }
+}
+
diff --git a/sgd-ui/src/plugins/index.js b/sgd-ui/src/plugins/index.js
new file mode 100644
index 0000000..d000f2d
--- /dev/null
+++ b/sgd-ui/src/plugins/index.js
@@ -0,0 +1,20 @@
+import tab from './tab'
+import auth from './auth'
+import cache from './cache'
+import modal from './modal'
+import download from './download'
+
+export default {
+ install(Vue) {
+ // 页签操作
+ Vue.prototype.$tab = tab
+ // 认证对象
+ Vue.prototype.$auth = auth
+ // 缓存对象
+ Vue.prototype.$cache = cache
+ // 模态框对象
+ Vue.prototype.$modal = modal
+ // 下载文件
+ Vue.prototype.$download = download
+ }
+}
diff --git a/sgd-ui/src/plugins/modal.js b/sgd-ui/src/plugins/modal.js
new file mode 100644
index 0000000..92bc1ef
--- /dev/null
+++ b/sgd-ui/src/plugins/modal.js
@@ -0,0 +1,83 @@
+import { Message, MessageBox, Notification, Loading } from 'element-ui'
+
+let loadingInstance
+
+export default {
+ // 消息提示
+ msg(content) {
+ Message.info(content)
+ },
+ // 错误消息
+ msgError(content) {
+ Message.error(content)
+ },
+ // 成功消息
+ msgSuccess(content) {
+ Message.success(content)
+ },
+ // 警告消息
+ msgWarning(content) {
+ Message.warning(content)
+ },
+ // 弹出提示
+ alert(content) {
+ MessageBox.alert(content, "系统提示")
+ },
+ // 错误提示
+ alertError(content) {
+ MessageBox.alert(content, "系统提示", { type: 'error' })
+ },
+ // 成功提示
+ alertSuccess(content) {
+ MessageBox.alert(content, "系统提示", { type: 'success' })
+ },
+ // 警告提示
+ alertWarning(content) {
+ MessageBox.alert(content, "系统提示", { type: 'warning' })
+ },
+ // 通知提示
+ notify(content) {
+ Notification.info(content)
+ },
+ // 错误通知
+ notifyError(content) {
+ Notification.error(content)
+ },
+ // 成功通知
+ notifySuccess(content) {
+ Notification.success(content)
+ },
+ // 警告通知
+ notifyWarning(content) {
+ Notification.warning(content)
+ },
+ // 确认窗体
+ confirm(content) {
+ return MessageBox.confirm(content, "系统提示", {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: "warning",
+ })
+ },
+ // 提交内容
+ prompt(content) {
+ return MessageBox.prompt(content, "系统提示", {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: "warning",
+ })
+ },
+ // 打开遮罩层
+ loading(content) {
+ loadingInstance = Loading.service({
+ lock: true,
+ text: content,
+ spinner: "el-icon-loading",
+ background: "rgba(0, 0, 0, 0.7)",
+ })
+ },
+ // 关闭遮罩层
+ closeLoading() {
+ loadingInstance.close()
+ }
+}
diff --git a/sgd-ui/src/plugins/tab.js b/sgd-ui/src/plugins/tab.js
new file mode 100644
index 0000000..79ca662
--- /dev/null
+++ b/sgd-ui/src/plugins/tab.js
@@ -0,0 +1,75 @@
+import store from '@/store'
+import router from '@/router'
+
+export default {
+ // 刷新当前tab页签
+ refreshPage(obj) {
+ const { path, query, matched } = router.currentRoute
+ // 防止在重定向过程中重复刷新
+ if (path.startsWith('/redirect/')) {
+ return Promise.resolve()
+ }
+ if (obj === undefined) {
+ matched.forEach((m) => {
+ if (m.components && m.components.default && m.components.default.name) {
+ if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
+ obj = { name: m.components.default.name, path: path, query: query }
+ }
+ }
+ })
+ }
+ return store.dispatch('tagsView/delCachedView', obj).then(() => {
+ const { path, query } = obj
+ router.replace({
+ path: '/redirect' + path,
+ query: query
+ })
+ })
+ },
+ // 关闭当前tab页签,打开新页签
+ closeOpenPage(obj) {
+ store.dispatch("tagsView/delView", router.currentRoute)
+ if (obj !== undefined) {
+ return router.push(obj)
+ }
+ },
+ // 关闭指定tab页签
+ closePage(obj) {
+ if (obj === undefined) {
+ return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => {
+ const latestView = visitedViews.slice(-1)[0]
+ if (latestView) {
+ return router.push(latestView.fullPath)
+ }
+ return router.push('/')
+ })
+ }
+ return store.dispatch('tagsView/delView', obj)
+ },
+ // 关闭所有tab页签
+ closeAllPage() {
+ return store.dispatch('tagsView/delAllViews')
+ },
+ // 关闭左侧tab页签
+ closeLeftPage(obj) {
+ return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute)
+ },
+ // 关闭右侧tab页签
+ closeRightPage(obj) {
+ return store.dispatch('tagsView/delRightTags', obj || router.currentRoute)
+ },
+ // 关闭其他tab页签
+ closeOtherPage(obj) {
+ return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute)
+ },
+ // 添加tab页签
+ openPage(title, url, params) {
+ const obj = { path: url, meta: { title: title } }
+ store.dispatch('tagsView/addView', obj)
+ return router.push({ path: url, query: params })
+ },
+ // 修改tab页签
+ updatePage(obj) {
+ return store.dispatch('tagsView/updateVisitedView', obj)
+ }
+}
diff --git a/sgd-ui/src/router/index.js b/sgd-ui/src/router/index.js
new file mode 100644
index 0000000..2dd6e79
--- /dev/null
+++ b/sgd-ui/src/router/index.js
@@ -0,0 +1,189 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+
+/**
+ * Note: 路由配置项
+ *
+ * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
+ * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+ * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
+ * // 若你想不管路由下面的 children 声明的个数都显示你的根路由
+ * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
+ * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+ * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
+ * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
+ * roles: ['admin', 'common'] // 访问路由的角色权限
+ * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
+ * meta : {
+ noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
+ title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
+ icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
+ breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
+ activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
+ }
+ */
+
+// 公共路由
+export const constantRoutes = [
+ {
+ path: '/redirect',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: '/redirect/:path(.*)',
+ component: () => import('@/views/redirect')
+ }
+ ]
+ },
+ {
+ path: '/login',
+ component: () => import('@/views/login'),
+ hidden: true
+ },
+ {
+ path: '/register',
+ component: () => import('@/views/register'),
+ hidden: true
+ },
+ {
+ path: '/404',
+ component: () => import('@/views/error/404'),
+ hidden: true
+ },
+ {
+ path: '/401',
+ component: () => import('@/views/error/401'),
+ hidden: true
+ },
+ {
+ path: '',
+ component: Layout,
+ redirect: 'index',
+ children: [
+ {
+ path: 'index',
+ component: () => import('@/views/index'),
+ name: 'Index',
+ meta: { title: '首页', icon: 'dashboard', affix: true }
+ }
+ ]
+ },
+ {
+ path: '/lock',
+ component: () => import('@/views/lock'),
+ hidden: true,
+ meta: { title: '锁定屏幕' }
+ },
+ {
+ path: '/user',
+ component: Layout,
+ hidden: true,
+ redirect: 'noredirect',
+ children: [
+ {
+ path: 'profile',
+ component: () => import('@/views/system/user/profile/index'),
+ name: 'Profile',
+ meta: { title: '个人中心', icon: 'user' }
+ }
+ ]
+ }
+]
+
+// 动态路由,基于用户权限动态去加载
+export const dynamicRoutes = [
+ {
+ path: '/system/user-auth',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:user:edit'],
+ children: [
+ {
+ path: 'role/:userId(\\d+)',
+ component: () => import('@/views/system/user/authRole'),
+ name: 'AuthRole',
+ meta: { title: '分配角色', activeMenu: '/system/user' }
+ }
+ ]
+ },
+ {
+ path: '/system/role-auth',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:role:edit'],
+ children: [
+ {
+ path: 'user/:roleId(\\d+)',
+ component: () => import('@/views/system/role/authUser'),
+ name: 'AuthUser',
+ meta: { title: '分配用户', activeMenu: '/system/role' }
+ }
+ ]
+ },
+ {
+ path: '/system/dict-data',
+ component: Layout,
+ hidden: true,
+ permissions: ['system:dict:list'],
+ children: [
+ {
+ path: 'index/:dictId(\\d+)',
+ component: () => import('@/views/system/dict/data'),
+ name: 'Data',
+ meta: { title: '字典数据', activeMenu: '/system/dict' }
+ }
+ ]
+ },
+ {
+ path: '/monitor/job-log',
+ component: Layout,
+ hidden: true,
+ permissions: ['monitor:job:list'],
+ children: [
+ {
+ path: 'index/:jobId(\\d+)',
+ component: () => import('@/views/monitor/job/log'),
+ name: 'JobLog',
+ meta: { title: '调度日志', activeMenu: '/monitor/job' }
+ }
+ ]
+ },
+ {
+ path: '/tool/gen-edit',
+ component: Layout,
+ hidden: true,
+ permissions: ['tool:gen:edit'],
+ children: [
+ {
+ path: 'index/:tableId(\\d+)',
+ component: () => import('@/views/tool/gen/editTable'),
+ name: 'GenEdit',
+ meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
+ }
+ ]
+ }
+]
+
+// 防止连续点击多次路由报错
+let routerPush = Router.prototype.push
+let routerReplace = Router.prototype.replace
+// push
+Router.prototype.push = function push(location) {
+ return routerPush.call(this, location).catch(err => err)
+}
+// replace
+Router.prototype.replace = function push(location) {
+ return routerReplace.call(this, location).catch(err => err)
+}
+
+export default new Router({
+ mode: 'history', // 去掉url中的#
+ scrollBehavior: () => ({ y: 0 }),
+ routes: constantRoutes
+})
diff --git a/sgd-ui/src/settings.js b/sgd-ui/src/settings.js
new file mode 100644
index 0000000..5c0fd0e
--- /dev/null
+++ b/sgd-ui/src/settings.js
@@ -0,0 +1,66 @@
+module.exports = {
+ /**
+ * 网页标题
+ */
+ title: process.env.VUE_APP_TITLE,
+
+ /**
+ * 侧边栏主题 深色主题theme-dark,浅色主题theme-light
+ */
+ sideTheme: 'theme-dark',
+
+ /**
+ * 系统布局配置
+ */
+ showSettings: true,
+
+ /**
+ * 菜单导航模式 1、纯左侧 2、混合(左侧+顶部) 3、纯顶部
+ */
+ navType: 1,
+
+ /**
+ * 是否显示 tagsView
+ */
+ tagsView: true,
+
+ /**
+ * 持久化标签页
+ */
+ tagsViewPersist: false,
+
+ /**
+ * 显示页签图标
+ */
+ tagsIcon: false,
+
+ /**
+ * 标签页样式:card 卡片(默认)、chrome 谷歌浏览器风格
+ */
+ tagsViewStyle: 'card',
+
+ /**
+ * 是否固定头部
+ */
+ fixedHeader: true,
+
+ /**
+ * 是否显示logo
+ */
+ sidebarLogo: true,
+
+ /**
+ * 是否显示动态标题
+ */
+ dynamicTitle: false,
+
+ /**
+ * 是否显示底部版权
+ */
+ footerVisible: false,
+
+ /**
+ * 底部版权文本内容
+ */
+ footerContent: 'Copyright © 2018-2026 RuoYi. All Rights Reserved.'
+}
diff --git a/sgd-ui/src/store/getters.js b/sgd-ui/src/store/getters.js
new file mode 100644
index 0000000..3b540a1
--- /dev/null
+++ b/sgd-ui/src/store/getters.js
@@ -0,0 +1,23 @@
+const getters = {
+ sidebar: state => state.app.sidebar,
+ size: state => state.app.size,
+ device: state => state.app.device,
+ dict: state => state.dict.dict,
+ isLock: state => state.lock.isLock,
+ lockPath: state => state.lock.lockPath,
+ visitedViews: state => state.tagsView.visitedViews,
+ cachedViews: state => state.tagsView.cachedViews,
+ token: state => state.user.token,
+ avatar: state => state.user.avatar,
+ id: state => state.user.id,
+ name: state => state.user.name,
+ nickName: state => state.user.nickName,
+ introduction: state => state.user.introduction,
+ roles: state => state.user.roles,
+ permissions: state => state.user.permissions,
+ permission_routes: state => state.permission.routes,
+ topbarRouters: state => state.permission.topbarRouters,
+ defaultRoutes: state => state.permission.defaultRoutes,
+ sidebarRouters: state => state.permission.sidebarRouters
+}
+export default getters
diff --git a/sgd-ui/src/store/index.js b/sgd-ui/src/store/index.js
new file mode 100644
index 0000000..a89f0ad
--- /dev/null
+++ b/sgd-ui/src/store/index.js
@@ -0,0 +1,27 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import lock from './modules/lock'
+import dict from './modules/dict'
+import user from './modules/user'
+import tagsView from './modules/tagsView'
+import permission from './modules/permission'
+import settings from './modules/settings'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+ modules: {
+ app,
+ lock,
+ dict,
+ user,
+ tagsView,
+ permission,
+ settings
+ },
+ getters
+})
+
+export default store
diff --git a/sgd-ui/src/store/modules/app.js b/sgd-ui/src/store/modules/app.js
new file mode 100644
index 0000000..9f99f39
--- /dev/null
+++ b/sgd-ui/src/store/modules/app.js
@@ -0,0 +1,66 @@
+import Cookies from 'js-cookie'
+
+const state = {
+ sidebar: {
+ opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+ withoutAnimation: false,
+ hide: false
+ },
+ device: 'desktop',
+ size: Cookies.get('size') || 'medium'
+}
+
+const mutations = {
+ TOGGLE_SIDEBAR: state => {
+ if (state.sidebar.hide) {
+ return false
+ }
+ state.sidebar.opened = !state.sidebar.opened
+ state.sidebar.withoutAnimation = false
+ if (state.sidebar.opened) {
+ Cookies.set('sidebarStatus', 1)
+ } else {
+ Cookies.set('sidebarStatus', 0)
+ }
+ },
+ CLOSE_SIDEBAR: (state, withoutAnimation) => {
+ Cookies.set('sidebarStatus', 0)
+ state.sidebar.opened = false
+ state.sidebar.withoutAnimation = withoutAnimation
+ },
+ TOGGLE_DEVICE: (state, device) => {
+ state.device = device
+ },
+ SET_SIZE: (state, size) => {
+ state.size = size
+ Cookies.set('size', size)
+ },
+ SET_SIDEBAR_HIDE: (state, status) => {
+ state.sidebar.hide = status
+ }
+}
+
+const actions = {
+ toggleSideBar({ commit }) {
+ commit('TOGGLE_SIDEBAR')
+ },
+ closeSideBar({ commit }, { withoutAnimation }) {
+ commit('CLOSE_SIDEBAR', withoutAnimation)
+ },
+ toggleDevice({ commit }, device) {
+ commit('TOGGLE_DEVICE', device)
+ },
+ setSize({ commit }, size) {
+ commit('SET_SIZE', size)
+ },
+ toggleSideBarHide({ commit }, status) {
+ commit('SET_SIDEBAR_HIDE', status)
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/sgd-ui/src/store/modules/dict.js b/sgd-ui/src/store/modules/dict.js
new file mode 100644
index 0000000..7a1b2f0
--- /dev/null
+++ b/sgd-ui/src/store/modules/dict.js
@@ -0,0 +1,50 @@
+const state = {
+ dict: new Array()
+}
+const mutations = {
+ SET_DICT: (state, { key, value }) => {
+ if (key !== null && key !== "") {
+ state.dict.push({
+ key: key,
+ value: value
+ })
+ }
+ },
+ REMOVE_DICT: (state, key) => {
+ try {
+ for (let i = 0; i < state.dict.length; i++) {
+ if (state.dict[i].key == key) {
+ state.dict.splice(i, 1)
+ return true
+ }
+ }
+ } catch (e) {
+ }
+ },
+ CLEAN_DICT: (state) => {
+ state.dict = new Array()
+ }
+}
+
+const actions = {
+ // 设置字典
+ setDict({ commit }, data) {
+ commit('SET_DICT', data)
+ },
+ // 删除字典
+ removeDict({ commit }, key) {
+ commit('REMOVE_DICT', key)
+ },
+ // 清空字典
+ cleanDict({ commit }) {
+ commit('CLEAN_DICT')
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
+
diff --git a/ruoyi-ui/src/store/modules/lock.js b/sgd-ui/src/store/modules/lock.js
similarity index 100%
rename from ruoyi-ui/src/store/modules/lock.js
rename to sgd-ui/src/store/modules/lock.js
diff --git a/sgd-ui/src/store/modules/permission.js b/sgd-ui/src/store/modules/permission.js
new file mode 100644
index 0000000..b549ef0
--- /dev/null
+++ b/sgd-ui/src/store/modules/permission.js
@@ -0,0 +1,122 @@
+import auth from '@/plugins/auth'
+import router, { constantRoutes, dynamicRoutes } from '@/router'
+import { getRouters } from '@/api/menu'
+import Layout from '@/layout/index'
+import ParentView from '@/components/ParentView'
+import InnerLink from '@/layout/components/InnerLink'
+
+const permission = {
+ state: {
+ routes: [],
+ addRoutes: [],
+ defaultRoutes: [],
+ topbarRouters: [],
+ sidebarRouters: []
+ },
+ mutations: {
+ SET_ROUTES: (state, routes) => {
+ state.addRoutes = routes
+ state.routes = constantRoutes.concat(routes)
+ },
+ SET_DEFAULT_ROUTES: (state, routes) => {
+ state.defaultRoutes = constantRoutes.concat(routes)
+ },
+ SET_TOPBAR_ROUTES: (state, routes) => {
+ state.topbarRouters = routes
+ },
+ SET_SIDEBAR_ROUTERS: (state, routes) => {
+ state.sidebarRouters = routes
+ },
+ },
+ actions: {
+ // 生成路由
+ GenerateRoutes({ commit }) {
+ return new Promise(resolve => {
+ // 向后端请求路由数据
+ getRouters().then(res => {
+ const sdata = JSON.parse(JSON.stringify(res.data))
+ const rdata = JSON.parse(JSON.stringify(res.data))
+ const sidebarRoutes = filterAsyncRouter(sdata)
+ const rewriteRoutes = filterAsyncRouter(rdata, false, true)
+ const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
+ rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
+ router.addRoutes(asyncRoutes)
+ commit('SET_ROUTES', rewriteRoutes)
+ commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
+ commit('SET_DEFAULT_ROUTES', sidebarRoutes)
+ commit('SET_TOPBAR_ROUTES', sidebarRoutes)
+ resolve(rewriteRoutes)
+ })
+ })
+ }
+ }
+}
+
+// 遍历后台传来的路由字符串,转换为组件对象
+function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
+ return asyncRouterMap.filter(route => {
+ if (type && route.children) {
+ route.children = filterChildren(route.children)
+ }
+ if (route.component) {
+ // Layout ParentView 组件特殊处理
+ if (route.component === 'Layout') {
+ route.component = Layout
+ } else if (route.component === 'ParentView') {
+ route.component = ParentView
+ } else if (route.component === 'InnerLink') {
+ route.component = InnerLink
+ } else {
+ route.component = loadView(route.component)
+ }
+ }
+ if (route.children != null && route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children, route, type)
+ } else {
+ delete route['children']
+ delete route['redirect']
+ }
+ return true
+ })
+}
+
+function filterChildren(childrenMap, lastRouter = false) {
+ var children = []
+ childrenMap.forEach(el => {
+ el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path
+ if (el.children && el.children.length && el.component === 'ParentView') {
+ children = children.concat(filterChildren(el.children, el))
+ } else {
+ children.push(el)
+ }
+ })
+ return children
+}
+
+// 动态路由遍历,验证是否具备权限
+export function filterDynamicRoutes(routes) {
+ const res = []
+ routes.forEach(route => {
+ if (route.permissions) {
+ if (auth.hasPermiOr(route.permissions)) {
+ res.push(route)
+ }
+ } else if (route.roles) {
+ if (auth.hasRoleOr(route.roles)) {
+ res.push(route)
+ }
+ }
+ })
+ return res
+}
+
+export const loadView = (view) => {
+ if (process.env.NODE_ENV === 'development') {
+ return (resolve) => require([`@/views/${view}`], resolve)
+ } else {
+ // 使用 import 实现生产环境的路由懒加载
+ return () => import(`@/views/${view}`)
+ }
+}
+
+export default permission
diff --git a/sgd-ui/src/store/modules/settings.js b/sgd-ui/src/store/modules/settings.js
new file mode 100644
index 0000000..c9bb3cc
--- /dev/null
+++ b/sgd-ui/src/store/modules/settings.js
@@ -0,0 +1,52 @@
+import defaultSettings from '@/settings'
+import { useDynamicTitle } from '@/utils/dynamicTitle'
+
+const { sideTheme, showSettings, navType, tagsView, tagsViewPersist, tagsIcon, tagsViewStyle, fixedHeader, sidebarLogo, dynamicTitle, footerVisible, footerContent } = defaultSettings
+
+const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
+const state = {
+ title: '',
+ theme: storageSetting.theme || '#409EFF',
+ sideTheme: storageSetting.sideTheme || sideTheme,
+ showSettings: showSettings,
+ navType: storageSetting.navType === undefined ? navType : storageSetting.navType,
+ tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
+ tagsViewPersist: storageSetting.tagsViewPersist === undefined ? tagsViewPersist : storageSetting.tagsViewPersist,
+ tagsIcon: storageSetting.tagsIcon === undefined ? tagsIcon : storageSetting.tagsIcon,
+ tagsViewStyle: storageSetting.tagsViewStyle === undefined ? tagsViewStyle : storageSetting.tagsViewStyle,
+ fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
+ sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
+ dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle,
+ footerVisible: storageSetting.footerVisible === undefined ? footerVisible : storageSetting.footerVisible,
+ footerContent: footerContent
+}
+const mutations = {
+ CHANGE_SETTING: (state, { key, value }) => {
+ if (state.hasOwnProperty(key)) {
+ state[key] = value
+ }
+ },
+ SET_TITLE: (state, title) => {
+ state.title = title
+ }
+}
+
+const actions = {
+ // 修改布局设置
+ changeSetting({ commit }, data) {
+ commit('CHANGE_SETTING', data)
+ },
+ // 设置网页标题
+ setTitle({ commit }, title) {
+ commit('SET_TITLE', title)
+ useDynamicTitle()
+ }
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
+
diff --git a/sgd-ui/src/store/modules/tagsView.js b/sgd-ui/src/store/modules/tagsView.js
new file mode 100644
index 0000000..a72ed23
--- /dev/null
+++ b/sgd-ui/src/store/modules/tagsView.js
@@ -0,0 +1,275 @@
+import store from '@/store'
+import cache from '@/plugins/cache'
+
+const PERSIST_KEY = 'tags-view-visited'
+
+function isPersistEnabled() {
+ return store.state.settings.tagsViewPersist
+}
+
+function saveVisitedViews(views) {
+ if (!isPersistEnabled()) return
+ const toSave = views.filter(v => !(v.meta && v.meta.affix)).map(v => ({ path: v.path, fullPath: v.fullPath, name: v.name, title: v.title, query: v.query, meta: v.meta }))
+ cache.local.setJSON(PERSIST_KEY, toSave)
+}
+
+function loadVisitedViews() {
+ return cache.local.getJSON(PERSIST_KEY) || []
+}
+
+function clearVisitedViews() {
+ cache.local.remove(PERSIST_KEY)
+}
+
+const state = {
+ visitedViews: [],
+ cachedViews: [],
+ iframeViews: []
+}
+
+const mutations = {
+ ADD_IFRAME_VIEW: (state, view) => {
+ if (state.iframeViews.some(v => v.path === view.path)) return
+ state.iframeViews.push(
+ Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ })
+ )
+ },
+ ADD_VISITED_VIEW: (state, view) => {
+ if (state.visitedViews.some(v => v.path === view.path)) return
+ state.visitedViews.push(
+ Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ })
+ )
+ saveVisitedViews(state.visitedViews)
+ },
+ ADD_VISITED_VIEW_FIRST: (state, view) => {
+ if (state.visitedViews.some(v => v.path === view.path)) return
+ state.visitedViews.unshift(
+ Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ })
+ )
+ },
+ ADD_CACHED_VIEW: (state, view) => {
+ if (state.cachedViews.includes(view.name)) return
+ if (view.meta && !view.meta.noCache) {
+ state.cachedViews.push(view.name)
+ }
+ },
+ DEL_VISITED_VIEW: (state, view) => {
+ for (const [i, v] of state.visitedViews.entries()) {
+ if (v.path === view.path) {
+ state.visitedViews.splice(i, 1)
+ break
+ }
+ }
+ state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
+ saveVisitedViews(state.visitedViews)
+ },
+ DEL_IFRAME_VIEW: (state, view) => {
+ state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
+ },
+ DEL_CACHED_VIEW: (state, view) => {
+ const index = state.cachedViews.indexOf(view.name)
+ index > -1 && state.cachedViews.splice(index, 1)
+ },
+
+ DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+ state.visitedViews = state.visitedViews.filter(v => {
+ return v.meta.affix || v.path === view.path
+ })
+ state.iframeViews = state.iframeViews.filter(item => item.path === view.path)
+ saveVisitedViews(state.visitedViews)
+ },
+ DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+ const index = state.cachedViews.indexOf(view.name)
+ if (index > -1) {
+ state.cachedViews = state.cachedViews.slice(index, index + 1)
+ } else {
+ state.cachedViews = []
+ }
+ },
+ DEL_ALL_VISITED_VIEWS: state => {
+ // keep affix tags
+ const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+ state.visitedViews = affixTags
+ state.iframeViews = []
+ clearVisitedViews()
+ },
+ DEL_ALL_CACHED_VIEWS: state => {
+ state.cachedViews = []
+ },
+ UPDATE_VISITED_VIEW: (state, view) => {
+ for (let v of state.visitedViews) {
+ if (v.path === view.path) {
+ v = Object.assign(v, view)
+ break
+ }
+ }
+ },
+ DEL_RIGHT_VIEWS: (state, view) => {
+ const index = state.visitedViews.findIndex(v => v.path === view.path)
+ if (index === -1) {
+ return
+ }
+ state.visitedViews = state.visitedViews.filter((item, idx) => {
+ if (idx <= index || (item.meta && item.meta.affix)) {
+ return true
+ }
+ const i = state.cachedViews.indexOf(item.name)
+ if (i > -1) {
+ state.cachedViews.splice(i, 1)
+ }
+ if(item.meta.link) {
+ const fi = state.iframeViews.findIndex(v => v.path === item.path)
+ state.iframeViews.splice(fi, 1)
+ }
+ return false
+ })
+ saveVisitedViews(state.visitedViews)
+ },
+ DEL_LEFT_VIEWS: (state, view) => {
+ const index = state.visitedViews.findIndex(v => v.path === view.path)
+ if (index === -1) {
+ return
+ }
+ state.visitedViews = state.visitedViews.filter((item, idx) => {
+ if (idx >= index || (item.meta && item.meta.affix)) {
+ return true
+ }
+ const i = state.cachedViews.indexOf(item.name)
+ if (i > -1) {
+ state.cachedViews.splice(i, 1)
+ }
+ if(item.meta.link) {
+ const fi = state.iframeViews.findIndex(v => v.path === item.path)
+ state.iframeViews.splice(fi, 1)
+ }
+ return false
+ })
+ saveVisitedViews(state.visitedViews)
+ }
+}
+
+const actions = {
+ addView({ dispatch }, view) {
+ dispatch('addVisitedView', view)
+ dispatch('addCachedView', view)
+ },
+ addIframeView({ commit }, view) {
+ commit('ADD_IFRAME_VIEW', view)
+ },
+ addVisitedView({ commit }, view) {
+ commit('ADD_VISITED_VIEW', view)
+ },
+ addAffixView({ commit }, view) {
+ commit('ADD_VISITED_VIEW_FIRST', view)
+ },
+ addCachedView({ commit }, view) {
+ commit('ADD_CACHED_VIEW', view)
+ },
+ delView({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delVisitedView', view)
+ dispatch('delCachedView', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delVisitedView({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_VISITED_VIEW', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delIframeView({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_IFRAME_VIEW', view)
+ resolve([...state.iframeViews])
+ })
+ },
+ delCachedView({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_CACHED_VIEW', view)
+ resolve([...state.cachedViews])
+ })
+ },
+ delOthersViews({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delOthersVisitedViews', view)
+ dispatch('delOthersCachedViews', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delOthersVisitedViews({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_OTHERS_VISITED_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delOthersCachedViews({ commit, state }, view) {
+ return new Promise(resolve => {
+ commit('DEL_OTHERS_CACHED_VIEWS', view)
+ resolve([...state.cachedViews])
+ })
+ },
+ delAllViews({ dispatch, state }, view) {
+ return new Promise(resolve => {
+ dispatch('delAllVisitedViews', view)
+ dispatch('delAllCachedViews', view)
+ resolve({
+ visitedViews: [...state.visitedViews],
+ cachedViews: [...state.cachedViews]
+ })
+ })
+ },
+ delAllVisitedViews({ commit, state }) {
+ return new Promise(resolve => {
+ commit('DEL_ALL_VISITED_VIEWS')
+ resolve([...state.visitedViews])
+ })
+ },
+ delAllCachedViews({ commit, state }) {
+ return new Promise(resolve => {
+ commit('DEL_ALL_CACHED_VIEWS')
+ resolve([...state.cachedViews])
+ })
+ },
+ updateVisitedView({ commit }, view) {
+ commit('UPDATE_VISITED_VIEW', view)
+ },
+ delRightTags({ commit }, view) {
+ return new Promise(resolve => {
+ commit('DEL_RIGHT_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delLeftTags({ commit }, view) {
+ return new Promise(resolve => {
+ commit('DEL_LEFT_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ // 恢复持久化的 tags
+ loadPersistedViews({ commit }) {
+ const views = loadVisitedViews()
+ views.forEach(view => {
+ commit('ADD_VISITED_VIEW', view)
+ })
+ },
+}
+
+export default {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+}
diff --git a/sgd-ui/src/store/modules/user.js b/sgd-ui/src/store/modules/user.js
new file mode 100644
index 0000000..85c08ca
--- /dev/null
+++ b/sgd-ui/src/store/modules/user.js
@@ -0,0 +1,145 @@
+import store from '@/store'
+import router from '@/router'
+import cache from '@/plugins/cache'
+import { MessageBox, } from 'element-ui'
+import { login, logout, getInfo, refreshToken } from '@/api/login'
+import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth'
+import { isEmpty } from "@/utils/validate"
+import defAva from '@/assets/images/profile.jpg'
+
+const user = {
+ state: {
+ token: getToken(),
+ id: '',
+ name: '',
+ nickName: '',
+ avatar: '',
+ roles: [],
+ permissions: []
+ },
+
+ mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_EXPIRES_IN: (state, time) => {
+ state.expires_in = time
+ },
+ SET_ID: (state, id) => {
+ state.id = id
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ },
+ SET_NICK_NAME: (state, nickName) => {
+ state.nickName = nickName
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ },
+ SET_PERMISSIONS: (state, permissions) => {
+ state.permissions = permissions
+ }
+ },
+
+ actions: {
+ // 登录
+ Login({ commit }, userInfo) {
+ const username = userInfo.username.trim()
+ const password = userInfo.password
+ const code = userInfo.code
+ const uuid = userInfo.uuid
+ return new Promise((resolve, reject) => {
+ login(username, password, code, uuid).then(res => {
+ let data = res.data
+ setToken(data.access_token)
+ commit('SET_TOKEN', data.access_token)
+ setExpiresIn(data.expires_in)
+ commit('SET_EXPIRES_IN', data.expires_in)
+ store.dispatch('lock/unlockScreen')
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 获取用户信息
+ GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo().then(res => {
+ const user = res.user
+ const avatar = (isEmpty(user.avatar)) ? defAva : user.avatar
+ if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
+ commit('SET_ROLES', res.roles)
+ commit('SET_PERMISSIONS', res.permissions)
+ } else {
+ commit('SET_ROLES', ['ROLE_DEFAULT'])
+ }
+ commit('SET_ID', user.userId)
+ commit('SET_NAME', user.userName)
+ commit('SET_NICK_NAME', user.nickName)
+ commit('SET_AVATAR', avatar)
+ cache.session.set('pwrChrtype', res.pwdChrtype)
+ /* 初始密码提示 */
+ if(res.isDefaultModifyPwd) {
+ MessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
+ }).catch(() => {})
+ }
+ /* 过期密码提示 */
+ if(!res.isDefaultModifyPwd && res.isPasswordExpired) {
+ MessageBox.confirm('您的密码已过期,请尽快修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
+ }).catch(() => {})
+ }
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 刷新token
+ RefreshToken({commit, state}) {
+ return new Promise((resolve, reject) => {
+ refreshToken(state.token).then(res => {
+ setExpiresIn(res.data)
+ commit('SET_EXPIRES_IN', res.data)
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 退出系统
+ LogOut({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ logout(state.token).then(() => {
+ commit('SET_TOKEN', '')
+ commit('SET_ROLES', [])
+ commit('SET_PERMISSIONS', [])
+ removeToken()
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 前端 登出
+ FedLogOut({ commit }) {
+ return new Promise(resolve => {
+ commit('SET_TOKEN', '')
+ removeToken()
+ resolve()
+ })
+ }
+ }
+}
+
+export default user
diff --git a/sgd-ui/src/utils/auth.js b/sgd-ui/src/utils/auth.js
new file mode 100644
index 0000000..a673d22
--- /dev/null
+++ b/sgd-ui/src/utils/auth.js
@@ -0,0 +1,29 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+const ExpiresInKey = 'Admin-Expires-In'
+
+export function getToken() {
+ return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+ return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+ return Cookies.remove(TokenKey)
+}
+
+export function getExpiresIn() {
+ return Cookies.get(ExpiresInKey) || -1
+}
+
+export function setExpiresIn(time) {
+ return Cookies.set(ExpiresInKey, time)
+}
+
+export function removeExpiresIn() {
+ return Cookies.remove(ExpiresInKey)
+}
diff --git a/sgd-ui/src/utils/dict/Dict.js b/sgd-ui/src/utils/dict/Dict.js
new file mode 100644
index 0000000..994f6f7
--- /dev/null
+++ b/sgd-ui/src/utils/dict/Dict.js
@@ -0,0 +1,82 @@
+import Vue from 'vue'
+import { mergeRecursive } from "@/utils/ruoyi"
+import DictMeta from './DictMeta'
+import DictData from './DictData'
+
+const DEFAULT_DICT_OPTIONS = {
+ types: [],
+}
+
+/**
+ * @classdesc 字典
+ * @property {Object} label 标签对象,内部属性名为字典类型名称
+ * @property {Object} dict 字段数组,内部属性名为字典类型名称
+ * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
+ */
+export default class Dict {
+ constructor() {
+ this.owner = null
+ this.label = {}
+ this.type = {}
+ }
+
+ init(options) {
+ if (options instanceof Array) {
+ options = { types: options }
+ }
+ const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
+ if (opts.types === undefined) {
+ throw new Error('need dict types')
+ }
+ const ps = []
+ this._dictMetas = opts.types.map(t => DictMeta.parse(t))
+ this._dictMetas.forEach(dictMeta => {
+ const type = dictMeta.type
+ Vue.set(this.label, type, {})
+ Vue.set(this.type, type, [])
+ if (dictMeta.lazy) {
+ return
+ }
+ ps.push(loadDict(this, dictMeta))
+ })
+ return Promise.all(ps)
+ }
+
+ /**
+ * 重新加载字典
+ * @param {String} type 字典类型
+ */
+ reloadDict(type) {
+ const dictMeta = this._dictMetas.find(e => e.type === type)
+ if (dictMeta === undefined) {
+ return Promise.reject(`the dict meta of ${type} was not found`)
+ }
+ return loadDict(this, dictMeta)
+ }
+}
+
+/**
+ * 加载字典
+ * @param {Dict} dict 字典
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {Promise}
+ */
+function loadDict(dict, dictMeta) {
+ return dictMeta.request(dictMeta)
+ .then(response => {
+ const type = dictMeta.type
+ let dicts = dictMeta.responseConverter(response, dictMeta)
+ if (!(dicts instanceof Array)) {
+ console.error('the return of responseConverter must be Array.<DictData>')
+ dicts = []
+ } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
+ console.error('the type of elements in dicts must be DictData')
+ dicts = []
+ }
+ dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
+ dicts.forEach(d => {
+ Vue.set(dict.label[type], d.value, d.label)
+ })
+ return dicts
+ })
+}
diff --git a/sgd-ui/src/utils/dict/DictConverter.js b/sgd-ui/src/utils/dict/DictConverter.js
new file mode 100644
index 0000000..0cf5df8
--- /dev/null
+++ b/sgd-ui/src/utils/dict/DictConverter.js
@@ -0,0 +1,17 @@
+import DictOptions from './DictOptions'
+import DictData from './DictData'
+
+export default function(dict, dictMeta) {
+ const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
+ const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
+ return new DictData(dict[label], dict[value], dict)
+}
+
+/**
+ * 确定字典字段
+ * @param {DictData} dict
+ * @param {...String} fields
+ */
+function determineDictField(dict, ...fields) {
+ return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
+}
diff --git a/sgd-ui/src/utils/dict/DictData.js b/sgd-ui/src/utils/dict/DictData.js
new file mode 100644
index 0000000..afc763e
--- /dev/null
+++ b/sgd-ui/src/utils/dict/DictData.js
@@ -0,0 +1,13 @@
+/**
+ * @classdesc 字典数据
+ * @property {String} label 标签
+ * @property {*} value 标签
+ * @property {Object} raw 原始数据
+ */
+export default class DictData {
+ constructor(label, value, raw) {
+ this.label = label
+ this.value = value
+ this.raw = raw
+ }
+}
diff --git a/sgd-ui/src/utils/dict/DictMeta.js b/sgd-ui/src/utils/dict/DictMeta.js
new file mode 100644
index 0000000..617cc00
--- /dev/null
+++ b/sgd-ui/src/utils/dict/DictMeta.js
@@ -0,0 +1,38 @@
+import { mergeRecursive } from "@/utils/ruoyi"
+import DictOptions from './DictOptions'
+
+/**
+ * @classdesc 字典元数据
+ * @property {String} type 类型
+ * @property {Function} request 请求
+ * @property {String} label 标签字段
+ * @property {String} value 值字段
+ */
+export default class DictMeta {
+ constructor(options) {
+ this.type = options.type
+ this.request = options.request
+ this.responseConverter = options.responseConverter
+ this.labelField = options.labelField
+ this.valueField = options.valueField
+ this.lazy = options.lazy === true
+ }
+}
+
+
+/**
+ * 解析字典元数据
+ * @param {Object} options
+ * @returns {DictMeta}
+ */
+DictMeta.parse= function(options) {
+ let opts = null
+ if (typeof options === 'string') {
+ opts = DictOptions.metas[options] || {}
+ opts.type = options
+ } else if (typeof options === 'object') {
+ opts = options
+ }
+ opts = mergeRecursive(DictOptions.metas['*'], opts)
+ return new DictMeta(opts)
+}
diff --git a/sgd-ui/src/utils/dict/DictOptions.js b/sgd-ui/src/utils/dict/DictOptions.js
new file mode 100644
index 0000000..5fd1425
--- /dev/null
+++ b/sgd-ui/src/utils/dict/DictOptions.js
@@ -0,0 +1,51 @@
+import { mergeRecursive } from "@/utils/ruoyi"
+import dictConverter from './DictConverter'
+
+export const options = {
+ metas: {
+ '*': {
+ /**
+ * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
+ */
+ request: (dictMeta) => {
+ console.log(`load dict ${dictMeta.type}`)
+ return Promise.resolve([])
+ },
+ /**
+ * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
+ */
+ responseConverter,
+ labelField: 'label',
+ valueField: 'value',
+ },
+ },
+ /**
+ * 默认标签字段
+ */
+ DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
+ /**
+ * 默认值字段
+ */
+ DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
+}
+
+/**
+ * 映射字典
+ * @param {Object} response 字典数据
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {DictData}
+ */
+function responseConverter(response, dictMeta) {
+ const dicts = response.content instanceof Array ? response.content : response
+ if (dicts === undefined) {
+ console.warn(`no dict data of "${dictMeta.type}" found in the response`)
+ return []
+ }
+ return dicts.map(d => dictConverter(d, dictMeta))
+}
+
+export function mergeOptions(src) {
+ mergeRecursive(options, src)
+}
+
+export default options
diff --git a/sgd-ui/src/utils/dict/index.js b/sgd-ui/src/utils/dict/index.js
new file mode 100644
index 0000000..215eb9e
--- /dev/null
+++ b/sgd-ui/src/utils/dict/index.js
@@ -0,0 +1,33 @@
+import Dict from './Dict'
+import { mergeOptions } from './DictOptions'
+
+export default function(Vue, options) {
+ mergeOptions(options)
+ Vue.mixin({
+ data() {
+ if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
+ return {}
+ }
+ const dict = new Dict()
+ dict.owner = this
+ return {
+ dict
+ }
+ },
+ created() {
+ if (!(this.dict instanceof Dict)) {
+ return
+ }
+ options.onCreated && options.onCreated(this.dict)
+ this.dict.init(this.$options.dicts).then(() => {
+ options.onReady && options.onReady(this.dict)
+ this.$nextTick(() => {
+ this.$emit('dictReady', this.dict)
+ if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
+ this.$options.methods.onDictReady.call(this, this.dict)
+ }
+ })
+ })
+ },
+ })
+}
diff --git a/ruoyi-ui/src/utils/dynamicTitle.js b/sgd-ui/src/utils/dynamicTitle.js
similarity index 100%
rename from ruoyi-ui/src/utils/dynamicTitle.js
rename to sgd-ui/src/utils/dynamicTitle.js
diff --git a/sgd-ui/src/utils/errorCode.js b/sgd-ui/src/utils/errorCode.js
new file mode 100644
index 0000000..d2111ee
--- /dev/null
+++ b/sgd-ui/src/utils/errorCode.js
@@ -0,0 +1,6 @@
+export default {
+ '401': '认证失败,无法访问系统资源',
+ '403': '当前操作没有权限',
+ '404': '访问资源不存在',
+ 'default': '系统未知错误,请反馈给管理员'
+}
diff --git a/sgd-ui/src/utils/generator/config.js b/sgd-ui/src/utils/generator/config.js
new file mode 100644
index 0000000..7abf227
--- /dev/null
+++ b/sgd-ui/src/utils/generator/config.js
@@ -0,0 +1,438 @@
+export const formConf = {
+ formRef: 'elForm',
+ formModel: 'formData',
+ size: 'medium',
+ labelPosition: 'right',
+ labelWidth: 100,
+ formRules: 'rules',
+ gutter: 15,
+ disabled: false,
+ span: 24,
+ formBtns: true
+}
+
+export const inputComponents = [
+ {
+ label: '单行文本',
+ tag: 'el-input',
+ tagIcon: 'input',
+ placeholder: '请输入',
+ defaultValue: undefined,
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ clearable: true,
+ prepend: '',
+ append: '',
+ 'prefix-icon': '',
+ 'suffix-icon': '',
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ {
+ label: '多行文本',
+ tag: 'el-input',
+ tagIcon: 'textarea',
+ type: 'textarea',
+ placeholder: '请输入',
+ defaultValue: undefined,
+ span: 24,
+ labelWidth: null,
+ autosize: {
+ minRows: 4,
+ maxRows: 4
+ },
+ style: { width: '100%' },
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ {
+ label: '密码',
+ tag: 'el-input',
+ tagIcon: 'password',
+ placeholder: '请输入',
+ defaultValue: undefined,
+ span: 24,
+ 'show-password': true,
+ labelWidth: null,
+ style: { width: '100%' },
+ clearable: true,
+ prepend: '',
+ append: '',
+ 'prefix-icon': '',
+ 'suffix-icon': '',
+ maxlength: null,
+ 'show-word-limit': false,
+ readonly: false,
+ disabled: false,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input'
+ },
+ {
+ label: '计数器',
+ tag: 'el-input-number',
+ tagIcon: 'number',
+ placeholder: '',
+ defaultValue: undefined,
+ span: 24,
+ labelWidth: null,
+ min: undefined,
+ max: undefined,
+ step: undefined,
+ 'step-strictly': false,
+ precision: undefined,
+ 'controls-position': '',
+ disabled: false,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
+ }
+]
+
+export const selectComponents = [
+ {
+ label: '下拉选择',
+ tag: 'el-select',
+ tagIcon: 'select',
+ placeholder: '请选择',
+ defaultValue: undefined,
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ clearable: true,
+ disabled: false,
+ required: true,
+ filterable: false,
+ multiple: false,
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }],
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/select'
+ },
+ {
+ label: '级联选择',
+ tag: 'el-cascader',
+ tagIcon: 'cascader',
+ placeholder: '请选择',
+ defaultValue: [],
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ props: {
+ props: {
+ multiple: false
+ }
+ },
+ 'show-all-levels': true,
+ disabled: false,
+ clearable: true,
+ filterable: false,
+ required: true,
+ options: [{
+ id: 1,
+ value: 1,
+ label: '选项1',
+ children: [{
+ id: 2,
+ value: 2,
+ label: '选项1-1'
+ }]
+ }],
+ dataType: 'dynamic',
+ labelKey: 'label',
+ valueKey: 'value',
+ childrenKey: 'children',
+ separator: '/',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
+ },
+ {
+ label: '单选框组',
+ tag: 'el-radio-group',
+ tagIcon: 'radio',
+ defaultValue: undefined,
+ span: 24,
+ labelWidth: null,
+ style: {},
+ optionType: 'default',
+ border: false,
+ size: 'medium',
+ disabled: false,
+ required: true,
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }],
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/radio'
+ },
+ {
+ label: '多选框组',
+ tag: 'el-checkbox-group',
+ tagIcon: 'checkbox',
+ defaultValue: [],
+ span: 24,
+ labelWidth: null,
+ style: {},
+ optionType: 'default',
+ border: false,
+ size: 'medium',
+ disabled: false,
+ required: true,
+ options: [{
+ label: '选项一',
+ value: 1
+ }, {
+ label: '选项二',
+ value: 2
+ }],
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
+ },
+ {
+ label: '开关',
+ tag: 'el-switch',
+ tagIcon: 'switch',
+ defaultValue: false,
+ span: 24,
+ labelWidth: null,
+ style: {},
+ disabled: false,
+ required: true,
+ 'active-text': '',
+ 'inactive-text': '',
+ 'active-color': null,
+ 'inactive-color': null,
+ 'active-value': true,
+ 'inactive-value': false,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/switch'
+ },
+ {
+ label: '滑块',
+ tag: 'el-slider',
+ tagIcon: 'slider',
+ defaultValue: null,
+ span: 24,
+ labelWidth: null,
+ disabled: false,
+ required: true,
+ min: 0,
+ max: 100,
+ step: 1,
+ 'show-stops': false,
+ range: false,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/slider'
+ },
+ {
+ label: '时间选择',
+ tag: 'el-time-picker',
+ tagIcon: 'time',
+ placeholder: '请选择',
+ defaultValue: null,
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ disabled: false,
+ clearable: true,
+ required: true,
+ 'picker-options': {
+ selectableRange: '00:00:00-23:59:59'
+ },
+ format: 'HH:mm:ss',
+ 'value-format': 'HH:mm:ss',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
+ {
+ label: '时间范围',
+ tag: 'el-time-picker',
+ tagIcon: 'time-range',
+ defaultValue: null,
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ disabled: false,
+ clearable: true,
+ required: true,
+ 'is-range': true,
+ 'range-separator': '至',
+ 'start-placeholder': '开始时间',
+ 'end-placeholder': '结束时间',
+ format: 'HH:mm:ss',
+ 'value-format': 'HH:mm:ss',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+ },
+ {
+ label: '日期选择',
+ tag: 'el-date-picker',
+ tagIcon: 'date',
+ placeholder: '请选择',
+ defaultValue: null,
+ type: 'date',
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ disabled: false,
+ clearable: true,
+ required: true,
+ format: 'yyyy-MM-dd',
+ 'value-format': 'yyyy-MM-dd',
+ readonly: false,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
+ {
+ label: '日期范围',
+ tag: 'el-date-picker',
+ tagIcon: 'date-range',
+ defaultValue: null,
+ span: 24,
+ labelWidth: null,
+ style: { width: '100%' },
+ type: 'daterange',
+ 'range-separator': '至',
+ 'start-placeholder': '开始日期',
+ 'end-placeholder': '结束日期',
+ disabled: false,
+ clearable: true,
+ required: true,
+ format: 'yyyy-MM-dd',
+ 'value-format': 'yyyy-MM-dd',
+ readonly: false,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+ },
+ {
+ label: '评分',
+ tag: 'el-rate',
+ tagIcon: 'rate',
+ defaultValue: 0,
+ span: 24,
+ labelWidth: null,
+ style: {},
+ max: 5,
+ 'allow-half': false,
+ 'show-text': false,
+ 'show-score': false,
+ disabled: false,
+ required: true,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/rate'
+ },
+ {
+ label: '颜色选择',
+ tag: 'el-color-picker',
+ tagIcon: 'color',
+ defaultValue: null,
+ labelWidth: null,
+ 'show-alpha': false,
+ 'color-format': '',
+ disabled: false,
+ required: true,
+ size: 'medium',
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
+ },
+ {
+ label: '上传',
+ tag: 'el-upload',
+ tagIcon: 'upload',
+ action: 'https://jsonplaceholder.typicode.com/posts/',
+ defaultValue: null,
+ labelWidth: null,
+ disabled: false,
+ required: true,
+ accept: '',
+ name: 'file',
+ 'auto-upload': true,
+ showTip: false,
+ buttonText: '点击上传',
+ fileSize: 2,
+ sizeUnit: 'MB',
+ 'list-type': 'text',
+ multiple: false,
+ regList: [],
+ changeTag: true,
+ document: 'https://element.eleme.cn/#/zh-CN/component/upload'
+ }
+]
+
+export const layoutComponents = [
+ {
+ layout: 'rowFormItem',
+ tagIcon: 'row',
+ type: 'default',
+ justify: 'start',
+ align: 'top',
+ label: '行容器',
+ layoutTree: true,
+ children: [],
+ document: 'https://element.eleme.cn/#/zh-CN/component/layout'
+ },
+ {
+ layout: 'colFormItem',
+ label: '按钮',
+ changeTag: true,
+ labelWidth: null,
+ tag: 'el-button',
+ tagIcon: 'button',
+ span: 24,
+ default: '主要按钮',
+ type: 'primary',
+ icon: 'el-icon-search',
+ size: 'medium',
+ disabled: false,
+ document: 'https://element.eleme.cn/#/zh-CN/component/button'
+ }
+]
+
+// 组件rule的触发方式,无触发方式的组件不生成rule
+export const trigger = {
+ 'el-input': 'blur',
+ 'el-input-number': 'blur',
+ 'el-select': 'change',
+ 'el-radio-group': 'change',
+ 'el-checkbox-group': 'change',
+ 'el-cascader': 'change',
+ 'el-time-picker': 'change',
+ 'el-date-picker': 'change',
+ 'el-rate': 'change'
+}
diff --git a/sgd-ui/src/utils/generator/css.js b/sgd-ui/src/utils/generator/css.js
new file mode 100644
index 0000000..c1c62e6
--- /dev/null
+++ b/sgd-ui/src/utils/generator/css.js
@@ -0,0 +1,18 @@
+const styles = {
+ 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}',
+ 'el-upload': '.el-upload__tip{line-height: 1.2;}'
+}
+
+function addCss(cssList, el) {
+ const css = styles[el.tag]
+ css && cssList.indexOf(css) === -1 && cssList.push(css)
+ if (el.children) {
+ el.children.forEach(el2 => addCss(cssList, el2))
+ }
+}
+
+export function makeUpCss(conf) {
+ const cssList = []
+ conf.fields.forEach(el => addCss(cssList, el))
+ return cssList.join('\n')
+}
diff --git a/sgd-ui/src/utils/generator/drawingDefault.js b/sgd-ui/src/utils/generator/drawingDefault.js
new file mode 100644
index 0000000..18017a2
--- /dev/null
+++ b/sgd-ui/src/utils/generator/drawingDefault.js
@@ -0,0 +1,37 @@
+export const drawingDefaultValue = []
+
+export function initDrawingDefaultValue() {
+ if (drawingDefaultValue.length === 0) {
+ drawingDefaultValue.push({
+ layout: 'colFormItem',
+ tagIcon: 'input',
+ label: '手机号',
+ vModel: 'mobile',
+ formId: 6,
+ tag: 'el-input',
+ placeholder: '请输入手机号',
+ defaultValue: '',
+ span: 24,
+ style: {width: '100%'},
+ clearable: true,
+ prepend: '',
+ append: '',
+ 'prefix-icon': 'el-icon-mobile',
+ 'suffix-icon': '',
+ maxlength: 11,
+ 'show-word-limit': true,
+ readonly: false,
+ disabled: false,
+ required: true,
+ changeTag: true,
+ regList: [{
+ pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
+ message: '手机号格式错误'
+ }]
+ })
+ }
+}
+
+export function cleanDrawingDefaultValue() {
+ drawingDefaultValue.splice(0, drawingDefaultValue.length)
+}
diff --git a/sgd-ui/src/utils/generator/html.js b/sgd-ui/src/utils/generator/html.js
new file mode 100644
index 0000000..3b3388d
--- /dev/null
+++ b/sgd-ui/src/utils/generator/html.js
@@ -0,0 +1,358 @@
+import { trigger } from './config'
+
+let confGlobal
+let someSpanIsNot24
+
+export function dialogWrapper(str) {
+ return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Title">
+ ${str}
+ <div slot="footer">
+ <el-button @click="close">取消</el-button>
+ <el-button type="primary" @click="handleConfirm">确定</el-button>
+ </div>
+ </el-dialog>`
+}
+
+export function vueTemplate(str) {
+ return `<template>
+ <div>
+ ${str}
+ </div>
+ </template>`
+}
+
+export function vueScript(str) {
+ return `<script>
+ ${str}
+ </script>`
+}
+
+export function cssStyle(cssStr) {
+ return `<style>
+ ${cssStr}
+ </style>`
+}
+
+function buildFormTemplate(conf, child, type) {
+ let labelPosition = ''
+ if (conf.labelPosition !== 'right') {
+ labelPosition = `label-position="${conf.labelPosition}"`
+ }
+ const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
+ let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>
+ ${child}
+ ${buildFromBtns(conf, type)}
+ </el-form>`
+ if (someSpanIsNot24) {
+ str = `<el-row :gutter="${conf.gutter}">
+ ${str}
+ </el-row>`
+ }
+ return str
+}
+
+function buildFromBtns(conf, type) {
+ let str = ''
+ if (conf.formBtns && type === 'file') {
+ str = `<el-form-item size="large">
+ <el-button type="primary" @click="submitForm">提交</el-button>
+ <el-button @click="resetForm">重置</el-button>
+ </el-form-item>`
+ if (someSpanIsNot24) {
+ str = `<el-col :span="24">
+ ${str}
+ </el-col>`
+ }
+ }
+ return str
+}
+
+// span不为24的用el-col包裹
+function colWrapper(element, str) {
+ if (someSpanIsNot24 || element.span !== 24) {
+ return `<el-col :span="${element.span}">
+ ${str}
+ </el-col>`
+ }
+ return str
+}
+
+const layouts = {
+ colFormItem(element) {
+ let labelWidth = ''
+ if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
+ labelWidth = `label-width="${element.labelWidth}px"`
+ }
+ const required = !trigger[element.tag] && element.required ? 'required' : ''
+ const tagDom = tags[element.tag] ? tags[element.tag](element) : null
+ let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>
+ ${tagDom}
+ </el-form-item>`
+ str = colWrapper(element, str)
+ return str
+ },
+ rowFormItem(element) {
+ const type = element.type === 'default' ? '' : `type="${element.type}"`
+ const justify = element.type === 'default' ? '' : `justify="${element.justify}"`
+ const align = element.type === 'default' ? '' : `align="${element.align}"`
+ const gutter = element.gutter ? `gutter="${element.gutter}"` : ''
+ const children = element.children.map(el => layouts[el.layout](el))
+ let str = `<el-row ${type} ${justify} ${align} ${gutter}>
+ ${children.join('\n')}
+ </el-row>`
+ str = colWrapper(element, str)
+ return str
+ }
+}
+
+const tags = {
+ 'el-button': el => {
+ const {
+ tag, disabled
+ } = attrBuilder(el)
+ const type = el.type ? `type="${el.type}"` : ''
+ const icon = el.icon ? `icon="${el.icon}"` : ''
+ const size = el.size ? `size="${el.size}"` : ''
+ let child = buildElButtonChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`
+ },
+ 'el-input': el => {
+ const {
+ disabled, vModel, clearable, placeholder, width
+ } = attrBuilder(el)
+ const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
+ const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
+ const readonly = el.readonly ? 'readonly' : ''
+ const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''
+ const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''
+ const showPassword = el['show-password'] ? 'show-password' : ''
+ const type = el.type ? `type="${el.type}"` : ''
+ const autosize = el.autosize && el.autosize.minRows
+ ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`
+ : ''
+ let child = buildElInputChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`
+ },
+ 'el-input-number': el => {
+ const { disabled, vModel, placeholder } = attrBuilder(el)
+ const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
+ const min = el.min ? `:min='${el.min}'` : ''
+ const max = el.max ? `:max='${el.max}'` : ''
+ const step = el.step ? `:step='${el.step}'` : ''
+ const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
+ const precision = el.precision ? `:precision='${el.precision}'` : ''
+
+ return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`
+ },
+ 'el-select': el => {
+ const {
+ disabled, vModel, clearable, placeholder, width
+ } = attrBuilder(el)
+ const filterable = el.filterable ? 'filterable' : ''
+ const multiple = el.multiple ? 'multiple' : ''
+ let child = buildElSelectChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`
+ },
+ 'el-radio-group': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const size = `size="${el.size}"`
+ let child = buildElRadioGroupChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`
+ },
+ 'el-checkbox-group': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const size = `size="${el.size}"`
+ const min = el.min ? `:min="${el.min}"` : ''
+ const max = el.max ? `:max="${el.max}"` : ''
+ let child = buildElCheckboxGroupChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`
+ },
+ 'el-switch': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
+ const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
+ const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
+ const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''
+ const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
+ const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
+
+ return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`
+ },
+ 'el-cascader': el => {
+ const {
+ disabled, vModel, clearable, placeholder, width
+ } = attrBuilder(el)
+ const options = el.options ? `:options="${el.vModel}Options"` : ''
+ const props = el.props ? `:props="${el.vModel}Props"` : ''
+ const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
+ const filterable = el.filterable ? 'filterable' : ''
+ const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
+
+ return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`
+ },
+ 'el-slider': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const min = el.min ? `:min='${el.min}'` : ''
+ const max = el.max ? `:max='${el.max}'` : ''
+ const step = el.step ? `:step='${el.step}'` : ''
+ const range = el.range ? 'range' : ''
+ const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
+
+ return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`
+ },
+ 'el-time-picker': el => {
+ const {
+ disabled, vModel, clearable, placeholder, width
+ } = attrBuilder(el)
+ const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
+ const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
+ const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
+ const isRange = el['is-range'] ? 'is-range' : ''
+ const format = el.format ? `format="${el.format}"` : ''
+ const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
+ const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
+
+ return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`
+ },
+ 'el-date-picker': el => {
+ const {
+ disabled, vModel, clearable, placeholder, width
+ } = attrBuilder(el)
+ const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
+ const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
+ const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
+ const format = el.format ? `format="${el.format}"` : ''
+ const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
+ const type = el.type === 'date' ? '' : `type="${el.type}"`
+ const readonly = el.readonly ? 'readonly' : ''
+
+ return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`
+ },
+ 'el-rate': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const max = el.max ? `:max='${el.max}'` : ''
+ const allowHalf = el['allow-half'] ? 'allow-half' : ''
+ const showText = el['show-text'] ? 'show-text' : ''
+ const showScore = el['show-score'] ? 'show-score' : ''
+
+ return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`
+ },
+ 'el-color-picker': el => {
+ const { disabled, vModel } = attrBuilder(el)
+ const size = `size="${el.size}"`
+ const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
+ const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
+
+ return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`
+ },
+ 'el-upload': el => {
+ const disabled = el.disabled ? ':disabled=\'true\'' : ''
+ const action = el.action ? `:action="${el.vModel}Action"` : ''
+ const multiple = el.multiple ? 'multiple' : ''
+ const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''
+ const accept = el.accept ? `accept="${el.accept}"` : ''
+ const name = el.name !== 'file' ? `name="${el.name}"` : ''
+ const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''
+ const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`
+ const fileList = `:file-list="${el.vModel}fileList"`
+ const ref = `ref="${el.vModel}"`
+ let child = buildElUploadChild(el)
+
+ if (child) child = `\n${child}\n` // 换行
+ return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`
+ }
+}
+
+function attrBuilder(el) {
+ return {
+ vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
+ clearable: el.clearable ? 'clearable' : '',
+ placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
+ width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
+ disabled: el.disabled ? ':disabled=\'true\'' : ''
+ }
+}
+
+// el-buttin 子级
+function buildElButtonChild(conf) {
+ const children = []
+ if (conf.default) {
+ children.push(conf.default)
+ }
+ return children.join('\n')
+}
+
+// el-input innerHTML
+function buildElInputChild(conf) {
+ const children = []
+ if (conf.prepend) {
+ children.push(`<template slot="prepend">${conf.prepend}</template>`)
+ }
+ if (conf.append) {
+ children.push(`<template slot="append">${conf.append}</template>`)
+ }
+ return children.join('\n')
+}
+
+function buildElSelectChild(conf) {
+ const children = []
+ if (conf.options && conf.options.length) {
+ children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)
+ }
+ return children.join('\n')
+}
+
+function buildElRadioGroupChild(conf) {
+ const children = []
+ if (conf.options && conf.options.length) {
+ const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
+ const border = conf.border ? 'border' : ''
+ children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
+ }
+ return children.join('\n')
+}
+
+function buildElCheckboxGroupChild(conf) {
+ const children = []
+ if (conf.options && conf.options.length) {
+ const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
+ const border = conf.border ? 'border' : ''
+ children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
+ }
+ return children.join('\n')
+}
+
+function buildElUploadChild(conf) {
+ const list = []
+ if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')
+ else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)
+ if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件</div>`)
+ return list.join('\n')
+}
+
+export function makeUpHtml(conf, type) {
+ const htmlList = []
+ confGlobal = conf
+ someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
+ conf.fields.forEach(el => {
+ htmlList.push(layouts[el.layout](el))
+ })
+ const htmlStr = htmlList.join('\n')
+
+ let temp = buildFormTemplate(conf, htmlStr, type)
+ if (type === 'dialog') {
+ temp = dialogWrapper(temp)
+ }
+ confGlobal = null
+ return temp
+}
diff --git a/ruoyi-ui/src/utils/generator/icon.json b/sgd-ui/src/utils/generator/icon.json
similarity index 100%
rename from ruoyi-ui/src/utils/generator/icon.json
rename to sgd-ui/src/utils/generator/icon.json
diff --git a/sgd-ui/src/utils/generator/js.js b/sgd-ui/src/utils/generator/js.js
new file mode 100644
index 0000000..ee8668d
--- /dev/null
+++ b/sgd-ui/src/utils/generator/js.js
@@ -0,0 +1,235 @@
+import { exportDefault, titleCase } from '@/utils/index'
+import { trigger } from './config'
+
+const units = {
+ KB: '1024',
+ MB: '1024 / 1024',
+ GB: '1024 / 1024 / 1024'
+}
+let confGlobal
+const inheritAttrs = {
+ file: '',
+ dialog: 'inheritAttrs: false,'
+}
+
+
+export function makeUpJs(conf, type) {
+ confGlobal = conf = JSON.parse(JSON.stringify(conf))
+ const dataList = []
+ const ruleList = []
+ const optionsList = []
+ const propsList = []
+ const methodList = mixinMethod(type)
+ const uploadVarList = []
+
+ conf.fields.forEach(el => {
+ buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
+ })
+
+ const script = buildexport(
+ conf,
+ type,
+ dataList.join('\n'),
+ ruleList.join('\n'),
+ optionsList.join('\n'),
+ uploadVarList.join('\n'),
+ propsList.join('\n'),
+ methodList.join('\n')
+ )
+ confGlobal = null
+ return script
+}
+
+function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
+ buildData(el, dataList)
+ buildRules(el, ruleList)
+
+ if (el.options && el.options.length) {
+ buildOptions(el, optionsList)
+ if (el.dataType === 'dynamic') {
+ const model = `${el.vModel}Options`
+ const options = titleCase(model)
+ buildOptionMethod(`get${options}`, model, methodList)
+ }
+ }
+
+ if (el.props && el.props.props) {
+ buildProps(el, propsList)
+ }
+
+ if (el.action && el.tag === 'el-upload') {
+ uploadVarList.push(
+ `${el.vModel}Action: '${el.action}',
+ ${el.vModel}fileList: [],`
+ )
+ methodList.push(buildBeforeUpload(el))
+ if (!el['auto-upload']) {
+ methodList.push(buildSubmitUpload(el))
+ }
+ }
+
+ if (el.children) {
+ el.children.forEach(el2 => {
+ buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
+ })
+ }
+}
+
+function mixinMethod(type) {
+ const list = []; const
+ minxins = {
+ file: confGlobal.formBtns ? {
+ submitForm: `submitForm() {
+ this.$refs['${confGlobal.formRef}'].validate(valid => {
+ if(!valid) return
+ // TODO 提交表单
+ })
+ },`,
+ resetForm: `resetForm() {
+ this.$refs['${confGlobal.formRef}'].resetFields()
+ },`
+ } : null,
+ dialog: {
+ onOpen: 'onOpen() {},',
+ onClose: `onClose() {
+ this.$refs['${confGlobal.formRef}'].resetFields()
+ },`,
+ close: `close() {
+ this.$emit('update:visible', false)
+ },`,
+ handleConfirm: `handleConfirm() {
+ this.$refs['${confGlobal.formRef}'].validate(valid => {
+ if(!valid) return
+ this.close()
+ })
+ },`
+ }
+ }
+
+ const methods = minxins[type]
+ if (methods) {
+ Object.keys(methods).forEach(key => {
+ list.push(methods[key])
+ })
+ }
+
+ return list
+}
+
+function buildData(conf, dataList) {
+ if (conf.vModel === undefined) return
+ let defaultValue
+ if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {
+ defaultValue = `'${conf.defaultValue}'`
+ } else {
+ defaultValue = `${JSON.stringify(conf.defaultValue)}`
+ }
+ dataList.push(`${conf.vModel}: ${defaultValue},`)
+}
+
+function buildRules(conf, ruleList) {
+ if (conf.vModel === undefined) return
+ const rules = []
+ if (trigger[conf.tag]) {
+ if (conf.required) {
+ const type = Array.isArray(conf.defaultValue) ? 'type: \'array\',' : ''
+ let message = Array.isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder
+ if (message === undefined) message = `${conf.label}不能为空`
+ rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)
+ }
+ if (conf.regList && Array.isArray(conf.regList)) {
+ conf.regList.forEach(item => {
+ if (item.pattern) {
+ rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
+ }
+ })
+ }
+ ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
+ }
+}
+
+function buildOptions(conf, optionsList) {
+ if (conf.vModel === undefined) return
+ if (conf.dataType === 'dynamic') { conf.options = [] }
+ const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`
+ optionsList.push(str)
+}
+
+function buildProps(conf, propsList) {
+ if (conf.dataType === 'dynamic') {
+ conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)
+ conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)
+ conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)
+ }
+ const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`
+ propsList.push(str)
+}
+
+function buildBeforeUpload(conf) {
+ const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
+ returnList = []
+ if (conf.fileSize) {
+ rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
+ if(!isRightSize){
+ this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
+ }`
+ returnList.push('isRightSize')
+ }
+ if (conf.accept) {
+ acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
+ if(!isAccept){
+ this.$message.error('应该选择${conf.accept}类型的文件')
+ }`
+ returnList.push('isAccept')
+ }
+ const str = `${conf.vModel}BeforeUpload(file) {
+ ${rightSizeCode}
+ ${acceptCode}
+ return ${returnList.join('&&')}
+ },`
+ return returnList.length ? str : ''
+}
+
+function buildSubmitUpload(conf) {
+ const str = `submitUpload() {
+ this.$refs['${conf.vModel}'].submit()
+ },`
+ return str
+}
+
+function buildOptionMethod(methodName, model, methodList) {
+ const str = `${methodName}() {
+ // TODO 发起请求获取数据
+ this.${model}
+ },`
+ methodList.push(str)
+}
+
+function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
+ const str = `${exportDefault}{
+ ${inheritAttrs[type]}
+ components: {},
+ props: [],
+ data () {
+ return {
+ ${conf.formModel}: {
+ ${data}
+ },
+ ${conf.formRules}: {
+ ${rules}
+ },
+ ${uploadVar}
+ ${selectOptions}
+ ${props}
+ }
+ },
+ computed: {},
+ watch: {},
+ created () {},
+ mounted () {},
+ methods: {
+ ${methods}
+ }
+}`
+ return str
+}
diff --git a/sgd-ui/src/utils/generator/render.js b/sgd-ui/src/utils/generator/render.js
new file mode 100644
index 0000000..e8640f0
--- /dev/null
+++ b/sgd-ui/src/utils/generator/render.js
@@ -0,0 +1,126 @@
+import { makeMap } from '@/utils/index'
+
+// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
+const isAttr = makeMap(
+ 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
+ + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
+ + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
+ + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
+ + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
+ + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
+ + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
+ + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
+ + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
+ + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
+ + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
+ + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
+ + 'target,title,type,usemap,value,width,wrap'
+)
+
+function vModel(self, dataObject, defaultValue) {
+ dataObject.props.value = defaultValue
+
+ dataObject.on.input = val => {
+ self.$emit('input', val)
+ }
+}
+
+const componentChild = {
+ 'el-button': {
+ default(h, conf, key) {
+ return conf[key]
+ },
+ },
+ 'el-input': {
+ prepend(h, conf, key) {
+ return <template slot="prepend">{conf[key]}</template>
+ },
+ append(h, conf, key) {
+ return <template slot="append">{conf[key]}</template>
+ }
+ },
+ 'el-select': {
+ options(h, conf, key) {
+ const list = []
+ conf.options.forEach(item => {
+ list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
+ })
+ return list
+ }
+ },
+ 'el-radio-group': {
+ options(h, conf, key) {
+ const list = []
+ conf.options.forEach(item => {
+ if (conf.optionType === 'button') list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
+ else list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
+ })
+ return list
+ }
+ },
+ 'el-checkbox-group': {
+ options(h, conf, key) {
+ const list = []
+ conf.options.forEach(item => {
+ if (conf.optionType === 'button') {
+ list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
+ } else {
+ list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
+ }
+ })
+ return list
+ }
+ },
+ 'el-upload': {
+ 'list-type': (h, conf, key) => {
+ const list = []
+ if (conf['list-type'] === 'picture-card') {
+ list.push(<i class="el-icon-plus"></i>)
+ } else {
+ list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
+ }
+ if (conf.showTip) {
+ list.push(<div slot="tip" class="el-upload__tip">只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件</div>)
+ }
+ return list
+ }
+ }
+}
+
+export default {
+ render(h) {
+ const dataObject = {
+ attrs: {},
+ props: {},
+ on: {},
+ style: {}
+ }
+ const confClone = JSON.parse(JSON.stringify(this.conf))
+ const children = []
+
+ const childObjs = componentChild[confClone.tag]
+ if (childObjs) {
+ Object.keys(childObjs).forEach(key => {
+ const childFunc = childObjs[key]
+ if (confClone[key]) {
+ children.push(childFunc(h, confClone, key))
+ }
+ })
+ }
+
+ Object.keys(confClone).forEach(key => {
+ const val = confClone[key]
+ if (key === 'vModel') {
+ vModel(this, dataObject, confClone.defaultValue)
+ } else if (dataObject[key]) {
+ dataObject[key] = val
+ } else if (!isAttr(key)) {
+ dataObject.props[key] = val
+ } else {
+ dataObject.attrs[key] = val
+ }
+ })
+ return h(this.conf.tag, dataObject, children)
+ },
+ props: ['conf']
+}
diff --git a/sgd-ui/src/utils/index.js b/sgd-ui/src/utils/index.js
new file mode 100644
index 0000000..9375db7
--- /dev/null
+++ b/sgd-ui/src/utils/index.js
@@ -0,0 +1,390 @@
+import { parseTime } from './ruoyi'
+
+/**
+ * 表格时间格式化
+ */
+export function formatDate(cellValue) {
+ if (cellValue == null || cellValue == "") return ""
+ var date = new Date(cellValue)
+ var year = date.getFullYear()
+ var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+ var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
+ var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
+ var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
+ var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+ return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return (
+ d.getMonth() +
+ 1 +
+ '月' +
+ d.getDate() +
+ '日' +
+ d.getHours() +
+ '时' +
+ d.getMinutes() +
+ '分'
+ )
+ }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function getQueryObject(url) {
+ url = url == null ? window.location.href : url
+ const search = url.substring(url.lastIndexOf('?') + 1)
+ const obj = {}
+ const reg = /([^?&=]+)=([^?&=]*)/g
+ search.replace(reg, (rs, $1, $2) => {
+ const name = decodeURIComponent($1)
+ let val = decodeURIComponent($2)
+ val = String(val)
+ obj[name] = val
+ return rs
+ })
+ return obj
+}
+
+/**
+ * @param {string} input value
+ * @returns {number} output value
+ */
+export function byteLength(str) {
+ // returns the byte length of an utf8 string
+ let s = str.length
+ for (var i = str.length - 1; i >= 0; i--) {
+ const code = str.charCodeAt(i)
+ if (code > 0x7f && code <= 0x7ff) s++
+ else if (code > 0x7ff && code <= 0xffff) s += 2
+ if (code >= 0xDC00 && code <= 0xDFFF) i--
+ }
+ return s
+}
+
+/**
+ * @param {Array} actual
+ * @returns {Array}
+ */
+export function cleanArray(actual) {
+ const newArray = []
+ for (let i = 0; i < actual.length; i++) {
+ if (actual[i]) {
+ newArray.push(actual[i])
+ }
+ }
+ return newArray
+}
+
+/**
+ * @param {Object} json
+ * @returns {Array}
+ */
+export function param(json) {
+ if (!json) return ''
+ return cleanArray(
+ Object.keys(json).map(key => {
+ if (json[key] === undefined) return ''
+ return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
+ })
+ ).join('&')
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+ const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+ if (!search) {
+ return {}
+ }
+ const obj = {}
+ const searchArr = search.split('&')
+ searchArr.forEach(v => {
+ const index = v.indexOf('=')
+ if (index !== -1) {
+ const name = v.substring(0, index)
+ const val = v.substring(index + 1, v.length)
+ obj[name] = val
+ }
+ })
+ return obj
+}
+
+/**
+ * @param {string} val
+ * @returns {string}
+ */
+export function html2Text(val) {
+ const div = document.createElement('div')
+ div.innerHTML = val
+ return div.textContent || div.innerText
+}
+
+/**
+ * Merges two objects, giving the last one precedence
+ * @param {Object} target
+ * @param {(Object|Array)} source
+ * @returns {Object}
+ */
+export function objectMerge(target, source) {
+ if (typeof target !== 'object') {
+ target = {}
+ }
+ if (Array.isArray(source)) {
+ return source.slice()
+ }
+ Object.keys(source).forEach(property => {
+ const sourceProperty = source[property]
+ if (typeof sourceProperty === 'object') {
+ target[property] = objectMerge(target[property], sourceProperty)
+ } else {
+ target[property] = sourceProperty
+ }
+ })
+ return target
+}
+
+/**
+ * @param {HTMLElement} element
+ * @param {string} className
+ */
+export function toggleClass(element, className) {
+ if (!element || !className) {
+ return
+ }
+ let classString = element.className
+ const nameIndex = classString.indexOf(className)
+ if (nameIndex === -1) {
+ classString += '' + className
+ } else {
+ classString =
+ classString.substr(0, nameIndex) +
+ classString.substr(nameIndex + className.length)
+ }
+ element.className = classString
+}
+
+/**
+ * @param {string} type
+ * @returns {Date}
+ */
+export function getTime(type) {
+ if (type === 'start') {
+ return new Date().getTime() - 3600 * 1000 * 24 * 90
+ } else {
+ return new Date(new Date().toDateString())
+ }
+}
+
+/**
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {*}
+ */
+export function debounce(func, wait, immediate) {
+ let timeout, args, context, timestamp, result
+
+ const later = function() {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp
+
+ // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last)
+ } else {
+ timeout = null
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args)
+ if (!timeout) context = args = null
+ }
+ }
+ }
+
+ return function(...args) {
+ context = this
+ timestamp = +new Date()
+ const callNow = immediate && !timeout
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait)
+ if (callNow) {
+ result = func.apply(context, args)
+ context = args = null
+ }
+
+ return result
+ }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+ if (!source && typeof source !== 'object') {
+ throw new Error('error arguments', 'deepClone')
+ }
+ const targetObj = source.constructor === Array ? [] : {}
+ Object.keys(source).forEach(keys => {
+ if (source[keys] && typeof source[keys] === 'object') {
+ targetObj[keys] = deepClone(source[keys])
+ } else {
+ targetObj[keys] = source[keys]
+ }
+ })
+ return targetObj
+}
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+ return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+ const timestamp = +new Date() + ''
+ const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+ return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+ return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+ if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+ if (hasClass(ele, cls)) {
+ const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+ ele.className = ele.className.replace(reg, ' ')
+ }
+}
+
+export function makeMap(str, expectsLowerCase) {
+ const map = Object.create(null)
+ const list = str.split(',')
+ for (let i = 0; i < list.length; i++) {
+ map[list[i]] = true
+ }
+ return expectsLowerCase
+ ? val => map[val.toLowerCase()]
+ : val => map[val]
+}
+
+export const exportDefault = 'export default '
+
+export const beautifierConf = {
+ html: {
+ indent_size: '2',
+ indent_char: ' ',
+ max_preserve_newlines: '-1',
+ preserve_newlines: false,
+ keep_array_indentation: false,
+ break_chained_methods: false,
+ indent_scripts: 'separate',
+ brace_style: 'end-expand',
+ space_before_conditional: true,
+ unescape_strings: false,
+ jslint_happy: false,
+ end_with_newline: true,
+ wrap_line_length: '110',
+ indent_inner_html: true,
+ comma_first: false,
+ e4x: true,
+ indent_empty_lines: true
+ },
+ js: {
+ indent_size: '2',
+ indent_char: ' ',
+ max_preserve_newlines: '-1',
+ preserve_newlines: false,
+ keep_array_indentation: false,
+ break_chained_methods: false,
+ indent_scripts: 'normal',
+ brace_style: 'end-expand',
+ space_before_conditional: true,
+ unescape_strings: false,
+ jslint_happy: true,
+ end_with_newline: true,
+ wrap_line_length: '110',
+ indent_inner_html: true,
+ comma_first: false,
+ e4x: true,
+ indent_empty_lines: true
+ }
+}
+
+// 首字母大小
+export function titleCase(str) {
+ return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
+}
+
+// 下划转驼峰
+export function camelCase(str) {
+ return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
+}
+
+export function isNumberStr(str) {
+ return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
+}
+
diff --git a/sgd-ui/src/utils/jsencrypt.js b/sgd-ui/src/utils/jsencrypt.js
new file mode 100644
index 0000000..78d9523
--- /dev/null
+++ b/sgd-ui/src/utils/jsencrypt.js
@@ -0,0 +1,30 @@
+import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
+
+// 密钥对生成 http://web.chacuo.net/netrsakeypair
+
+const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' +
+ 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+
+const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
+ '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
+ 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
+ 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
+ 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
+ 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
+ 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
+ 'UP8iWi1Qw0Y='
+
+// 加密
+export function encrypt(txt) {
+ const encryptor = new JSEncrypt()
+ encryptor.setPublicKey(publicKey) // 设置公钥
+ return encryptor.encrypt(txt) // 对数据进行加密
+}
+
+// 解密
+export function decrypt(txt) {
+ const encryptor = new JSEncrypt()
+ encryptor.setPrivateKey(privateKey) // 设置私钥
+ return encryptor.decrypt(txt) // 对数据进行解密
+}
+
diff --git a/ruoyi-ui/src/utils/passwordRule.js b/sgd-ui/src/utils/passwordRule.js
similarity index 100%
rename from ruoyi-ui/src/utils/passwordRule.js
rename to sgd-ui/src/utils/passwordRule.js
diff --git a/sgd-ui/src/utils/permission.js b/sgd-ui/src/utils/permission.js
new file mode 100644
index 0000000..0263bbc
--- /dev/null
+++ b/sgd-ui/src/utils/permission.js
@@ -0,0 +1,47 @@
+import store from '@/store'
+
+/**
+ * 字符权限校验
+ * @param {Array} value 校验值
+ * @returns {Boolean}
+ */
+export function checkPermi(value) {
+ if (value && value instanceof Array && value.length > 0) {
+ const permissions = store.getters && store.getters.permissions
+ const permissionDatas = value
+ const all_permission = "*:*:*"
+
+ const hasPermission = permissions.some(permission => {
+ return all_permission === permission || permissionDatas.includes(permission)
+ })
+
+ return hasPermission
+
+ } else {
+ console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
+ return false
+ }
+}
+
+/**
+ * 角色权限校验
+ * @param {Array} value 校验值
+ * @returns {Boolean}
+ */
+export function checkRole(value) {
+ if (value && value instanceof Array && value.length > 0) {
+ const roles = store.getters && store.getters.roles
+ const permissionRoles = value
+ const super_admin = "admin"
+
+ const hasRole = roles.some(role => {
+ return super_admin === role || permissionRoles.includes(role)
+ })
+
+ return hasRole
+
+ } else {
+ console.error(`need roles! Like checkRole="['admin','editor']"`)
+ return false
+ }
+}
\ No newline at end of file
diff --git a/sgd-ui/src/utils/request.js b/sgd-ui/src/utils/request.js
new file mode 100644
index 0000000..8695801
--- /dev/null
+++ b/sgd-ui/src/utils/request.js
@@ -0,0 +1,153 @@
+import axios from 'axios'
+import { Notification, MessageBox, Message, Loading } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
+import { tansParams, blobValidate } from "@/utils/ruoyi"
+import cache from '@/plugins/cache'
+import { saveAs } from 'file-saver'
+
+let downloadLoadingInstance
+// 是否显示重新登录
+export let isRelogin = { show: false }
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+// 创建axios实例
+const service = axios.create({
+ // axios中请求配置有baseURL选项,表示请求URL公共部分
+ baseURL: process.env.VUE_APP_BASE_API,
+ // 超时
+ timeout: 10000
+})
+
+// request拦截器
+service.interceptors.request.use(config => {
+ // 是否需要设置 token
+ const isToken = (config.headers || {}).isToken === false
+ // 是否需要防止数据重复提交
+ const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
+ // 间隔时间(ms),小于此时间视为重复提交
+ const interval = (config.headers || {}).interval || 1000
+ if (getToken() && !isToken) {
+ config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+ }
+ // get请求映射params参数
+ if (config.method === 'get' && config.params) {
+ let url = config.url + '?' + tansParams(config.params)
+ url = url.slice(0, -1)
+ config.params = {}
+ config.url = url
+ }
+ if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
+ const requestObj = {
+ url: config.url,
+ data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
+ time: new Date().getTime()
+ }
+ const requestSize = Object.keys(JSON.stringify(requestObj)).length // 请求数据大小
+ const limitSize = 5 * 1024 * 1024 // 限制存放数据5M
+ if (requestSize >= limitSize) {
+ console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
+ return config
+ }
+ const sessionObj = cache.session.getJSON('sessionObj')
+ if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
+ cache.session.setJSON('sessionObj', requestObj)
+ } else {
+ const s_url = sessionObj.url // 请求地址
+ const s_data = sessionObj.data // 请求数据
+ const s_time = sessionObj.time // 请求时间
+ if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
+ const message = '数据正在处理,请勿重复提交'
+ console.warn(`[${s_url}]: ` + message)
+ return Promise.reject(new Error(message))
+ } else {
+ cache.session.setJSON('sessionObj', requestObj)
+ }
+ }
+ }
+ return config
+}, error => {
+ console.log(error)
+ Promise.reject(error)
+})
+
+// 响应拦截器
+service.interceptors.response.use(res => {
+ // 未设置状态码则默认成功状态
+ const code = res.data.code || 200
+ // 获取错误信息
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
+ // 二进制数据则直接返回
+ if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+ return res.data
+ }
+ if (code === 401) {
+ if (!isRelogin.show) {
+ isRelogin.show = true
+ MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ isRelogin.show = false
+ store.dispatch('LogOut').then(() => {
+ location.href = '/index'
+ })
+ }).catch(() => {
+ isRelogin.show = false
+ })
+ }
+ return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+ } else if (code === 500) {
+ Message({ message: msg, type: 'error' })
+ return Promise.reject(new Error(msg))
+ } else if (code === 601) {
+ Message({ message: msg, type: 'warning' })
+ return Promise.reject('error')
+ } else if (code !== 200) {
+ Notification.error({ title: msg })
+ return Promise.reject('error')
+ } else {
+ return res.data
+ }
+ },
+ error => {
+ console.log('err' + error)
+ let { message } = error
+ if (message == "Network Error") {
+ message = "后端接口连接异常"
+ } else if (message.includes("timeout")) {
+ message = "系统接口请求超时"
+ } else if (message.includes("Request failed with status code")) {
+ message = "系统接口" + message.slice(-3) + "异常"
+ }
+ Message({ message: message, type: 'error', duration: 5 * 1000 })
+ return Promise.reject(error)
+ }
+)
+
+// 通用下载方法
+export function download(url, params, filename, config) {
+ downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
+ return service.post(url, params, {
+ transformRequest: [(params) => { return tansParams(params) }],
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ responseType: 'blob',
+ ...config
+ }).then(async (data) => {
+ const isBlob = blobValidate(data)
+ if (isBlob) {
+ const blob = new Blob([data])
+ saveAs(blob, filename)
+ } else {
+ const resText = await data.text()
+ const rspObj = JSON.parse(resText)
+ const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+ Message.error(errMsg)
+ }
+ downloadLoadingInstance.close()
+ }).catch((r) => {
+ console.error(r)
+ Message.error('下载文件出现错误,请联系管理员!')
+ downloadLoadingInstance.close()
+ })
+}
+
+export default service
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/sgd-ui/src/utils/ruoyi.js
similarity index 100%
rename from ruoyi-ui/src/utils/ruoyi.js
rename to sgd-ui/src/utils/ruoyi.js
diff --git a/sgd-ui/src/utils/scroll-to.js b/sgd-ui/src/utils/scroll-to.js
new file mode 100644
index 0000000..c5d8e04
--- /dev/null
+++ b/sgd-ui/src/utils/scroll-to.js
@@ -0,0 +1,58 @@
+Math.easeInOutQuad = function(t, b, c, d) {
+ t /= d / 2
+ if (t < 1) {
+ return c / 2 * t * t + b
+ }
+ t--
+ return -c / 2 * (t * (t - 2) - 1) + b
+}
+
+// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
+var requestAnimFrame = (function() {
+ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
+})()
+
+/**
+ * Because it's so fucking difficult to detect the scrolling element, just move them all
+ * @param {number} amount
+ */
+function move(amount) {
+ document.documentElement.scrollTop = amount
+ document.body.parentNode.scrollTop = amount
+ document.body.scrollTop = amount
+}
+
+function position() {
+ return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
+}
+
+/**
+ * @param {number} to
+ * @param {number} duration
+ * @param {Function} callback
+ */
+export function scrollTo(to, duration, callback) {
+ const start = position()
+ const change = to - start
+ const increment = 20
+ let currentTime = 0
+ duration = (typeof (duration) === 'undefined') ? 500 : duration
+ var animateScroll = function() {
+ // increment the time
+ currentTime += increment
+ // find the value with the quadratic in-out easing function
+ var val = Math.easeInOutQuad(currentTime, start, change, duration)
+ // move the document.body
+ move(val)
+ // do the animation unless its over
+ if (currentTime < duration) {
+ requestAnimFrame(animateScroll)
+ } else {
+ if (callback && typeof (callback) === 'function') {
+ // the animation is done so lets callback
+ callback()
+ }
+ }
+ }
+ animateScroll()
+}
diff --git a/sgd-ui/src/utils/validate.js b/sgd-ui/src/utils/validate.js
new file mode 100644
index 0000000..d159859
--- /dev/null
+++ b/sgd-ui/src/utils/validate.js
@@ -0,0 +1,119 @@
+/**
+ * 路径匹配器
+ * @param {string} pattern
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isPathMatch(pattern, path) {
+ const regexPattern = pattern
+ .replace(/([.+^${}()|\[\]\\])/g, '\\$1')
+ .replace(/\*\*/g, '__DOUBLE_STAR__')
+ .replace(/\*/g, '[^/]*')
+ .replace(/__DOUBLE_STAR__/g, '.*')
+ .replace(/\?/g, '[^/]')
+ const regex = new RegExp(`^${regexPattern}$`)
+ return regex.test(path)
+}
+
+/**
+ * 判断value字符串是否为空
+ * @param {string} value
+ * @returns {Boolean}
+ */
+export function isEmpty(value) {
+ if (value == null || value == "" || value == undefined || value == "undefined") {
+ return true
+ }
+ return false
+}
+
+/**
+ * 判断url是否是http或https
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function isHttp(url) {
+ return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+}
+
+/**
+ * 判断path是否为外链
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path) {
+ return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername(str) {
+ const valid_map = ['admin', 'editor']
+ return valid_map.indexOf(str.trim()) >= 0
+}
+
+/**
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function validURL(url) {
+ const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+ return reg.test(url)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validLowerCase(str) {
+ const reg = /^[a-z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUpperCase(str) {
+ const reg = /^[A-Z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validAlphabets(str) {
+ const reg = /^[A-Za-z]+$/
+ return reg.test(str)
+}
+
+/**
+ * @param {string} email
+ * @returns {Boolean}
+ */
+export function validEmail(email) {
+ const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+ return reg.test(email)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function isString(str) {
+ return typeof str === 'string' || str instanceof String
+}
+
+/**
+ * @param {Array} arg
+ * @returns {Boolean}
+ */
+export function isArray(arg) {
+ if (typeof Array.isArray === 'undefined') {
+ return Object.prototype.toString.call(arg) === '[object Array]'
+ }
+ return Array.isArray(arg)
+}
diff --git a/sgd-ui/src/views/dashboard/BarChart.vue b/sgd-ui/src/views/dashboard/BarChart.vue
new file mode 100644
index 0000000..88e7ef6
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/BarChart.vue
@@ -0,0 +1,102 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 6000
+
+export default {
+ mixins: [resize],
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.initChart()
+ })
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: { // 坐标轴指示器,坐标轴触发有效
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+ }
+ },
+ grid: {
+ top: 10,
+ left: '2%',
+ right: '2%',
+ bottom: '3%',
+ containLabel: true
+ },
+ xAxis: [{
+ type: 'category',
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+ axisTick: {
+ alignWithLabel: true
+ }
+ }],
+ yAxis: [{
+ type: 'value',
+ axisTick: {
+ show: false
+ }
+ }],
+ series: [{
+ name: 'pageA',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [79, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }, {
+ name: 'pageB',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [80, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }, {
+ name: 'pageC',
+ type: 'bar',
+ stack: 'vistors',
+ barWidth: '60%',
+ data: [30, 52, 200, 334, 390, 330, 220],
+ animationDuration
+ }]
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/dashboard/LineChart.vue b/sgd-ui/src/views/dashboard/LineChart.vue
new file mode 100644
index 0000000..702ff73
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/LineChart.vue
@@ -0,0 +1,135 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+ mixins: [resize],
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '350px'
+ },
+ autoResize: {
+ type: Boolean,
+ default: true
+ },
+ chartData: {
+ type: Object,
+ required: true
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ watch: {
+ chartData: {
+ deep: true,
+ handler(val) {
+ this.setOptions(val)
+ }
+ }
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.initChart()
+ })
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+ this.setOptions(this.chartData)
+ },
+ setOptions({ expectedData, actualData } = {}) {
+ this.chart.setOption({
+ xAxis: {
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+ boundaryGap: false,
+ axisTick: {
+ show: false
+ }
+ },
+ grid: {
+ left: 10,
+ right: 10,
+ bottom: 20,
+ top: 30,
+ containLabel: true
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'cross'
+ },
+ padding: [5, 10]
+ },
+ yAxis: {
+ axisTick: {
+ show: false
+ }
+ },
+ legend: {
+ data: ['expected', 'actual']
+ },
+ series: [{
+ name: 'expected', itemStyle: {
+ normal: {
+ color: '#FF005A',
+ lineStyle: {
+ color: '#FF005A',
+ width: 2
+ }
+ }
+ },
+ smooth: true,
+ type: 'line',
+ data: expectedData,
+ animationDuration: 2800,
+ animationEasing: 'cubicInOut'
+ },
+ {
+ name: 'actual',
+ smooth: true,
+ type: 'line',
+ itemStyle: {
+ normal: {
+ color: '#3888fa',
+ lineStyle: {
+ color: '#3888fa',
+ width: 2
+ },
+ areaStyle: {
+ color: '#f3f8ff'
+ }
+ }
+ },
+ data: actualData,
+ animationDuration: 2800,
+ animationEasing: 'quadraticOut'
+ }]
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/dashboard/PanelGroup.vue b/sgd-ui/src/views/dashboard/PanelGroup.vue
new file mode 100644
index 0000000..1a1081f
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/PanelGroup.vue
@@ -0,0 +1,181 @@
+<template>
+ <el-row :gutter="40" class="panel-group">
+ <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
+ <div class="card-panel-icon-wrapper icon-people">
+ <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">
+ 访客
+ </div>
+ <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel" @click="handleSetLineChartData('messages')">
+ <div class="card-panel-icon-wrapper icon-message">
+ <svg-icon icon-class="message" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">
+ 消息
+ </div>
+ <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel" @click="handleSetLineChartData('purchases')">
+ <div class="card-panel-icon-wrapper icon-money">
+ <svg-icon icon-class="money" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">
+ 金额
+ </div>
+ <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
+ </div>
+ </div>
+ </el-col>
+ <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+ <div class="card-panel" @click="handleSetLineChartData('shoppings')">
+ <div class="card-panel-icon-wrapper icon-shopping">
+ <svg-icon icon-class="shopping" class-name="card-panel-icon" />
+ </div>
+ <div class="card-panel-description">
+ <div class="card-panel-text">
+ 订单
+ </div>
+ <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+</template>
+
+<script>
+import CountTo from 'vue-count-to'
+
+export default {
+ components: {
+ CountTo
+ },
+ methods: {
+ handleSetLineChartData(type) {
+ this.$emit('handleSetLineChartData', type)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.panel-group {
+ margin-top: 18px;
+
+ .card-panel-col {
+ margin-bottom: 32px;
+ }
+
+ .card-panel {
+ height: 108px;
+ cursor: pointer;
+ font-size: 12px;
+ position: relative;
+ overflow: hidden;
+ color: #666;
+ background: #fff;
+ box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+ border-color: rgba(0, 0, 0, .05);
+
+ &:hover {
+ .card-panel-icon-wrapper {
+ color: #fff;
+ }
+
+ .icon-people {
+ background: #40c9c6;
+ }
+
+ .icon-message {
+ background: #36a3f7;
+ }
+
+ .icon-money {
+ background: #f4516c;
+ }
+
+ .icon-shopping {
+ background: #34bfa3
+ }
+ }
+
+ .icon-people {
+ color: #40c9c6;
+ }
+
+ .icon-message {
+ color: #36a3f7;
+ }
+
+ .icon-money {
+ color: #f4516c;
+ }
+
+ .icon-shopping {
+ color: #34bfa3
+ }
+
+ .card-panel-icon-wrapper {
+ float: left;
+ margin: 14px 0 0 14px;
+ padding: 16px;
+ transition: all 0.38s ease-out;
+ border-radius: 6px;
+ }
+
+ .card-panel-icon {
+ float: left;
+ font-size: 48px;
+ }
+
+ .card-panel-description {
+ float: right;
+ font-weight: bold;
+ margin: 26px;
+ margin-left: 0px;
+
+ .card-panel-text {
+ line-height: 18px;
+ color: rgba(0, 0, 0, 0.45);
+ font-size: 16px;
+ margin-bottom: 12px;
+ }
+
+ .card-panel-num {
+ font-size: 20px;
+ }
+ }
+ }
+}
+
+@media (max-width:550px) {
+ .card-panel-description {
+ display: none;
+ }
+
+ .card-panel-icon-wrapper {
+ float: none !important;
+ width: 100%;
+ height: 100%;
+ margin: 0 !important;
+
+ .svg-icon {
+ display: block;
+ margin: 14px auto !important;
+ float: none !important;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/views/dashboard/PieChart.vue b/sgd-ui/src/views/dashboard/PieChart.vue
new file mode 100644
index 0000000..63f0d84
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/PieChart.vue
@@ -0,0 +1,79 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+ mixins: [resize],
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.initChart()
+ })
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ tooltip: {
+ trigger: 'item',
+ formatter: '{a} <br/>{b} : {c} ({d}%)'
+ },
+ legend: {
+ left: 'center',
+ bottom: '10',
+ data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
+ },
+ series: [
+ {
+ name: 'WEEKLY WRITE ARTICLES',
+ type: 'pie',
+ roseType: 'radius',
+ radius: [15, 95],
+ center: ['50%', '38%'],
+ data: [
+ { value: 320, name: 'Industries' },
+ { value: 240, name: 'Technology' },
+ { value: 149, name: 'Forex' },
+ { value: 100, name: 'Gold' },
+ { value: 59, name: 'Forecasts' }
+ ],
+ animationEasing: 'cubicInOut',
+ animationDuration: 2600
+ }
+ ]
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/dashboard/RaddarChart.vue b/sgd-ui/src/views/dashboard/RaddarChart.vue
new file mode 100644
index 0000000..312e018
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/RaddarChart.vue
@@ -0,0 +1,116 @@
+<template>
+ <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 3000
+
+export default {
+ mixins: [resize],
+ props: {
+ className: {
+ type: String,
+ default: 'chart'
+ },
+ width: {
+ type: String,
+ default: '100%'
+ },
+ height: {
+ type: String,
+ default: '300px'
+ }
+ },
+ data() {
+ return {
+ chart: null
+ }
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.initChart()
+ })
+ },
+ beforeDestroy() {
+ if (!this.chart) {
+ return
+ }
+ this.chart.dispose()
+ this.chart = null
+ },
+ methods: {
+ initChart() {
+ this.chart = echarts.init(this.$el, 'macarons')
+
+ this.chart.setOption({
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: { // 坐标轴指示器,坐标轴触发有效
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+ }
+ },
+ radar: {
+ radius: '66%',
+ center: ['50%', '42%'],
+ splitNumber: 8,
+ splitArea: {
+ areaStyle: {
+ color: 'rgba(127,95,132,.3)',
+ opacity: 1,
+ shadowBlur: 45,
+ shadowColor: 'rgba(0,0,0,.5)',
+ shadowOffsetX: 0,
+ shadowOffsetY: 15
+ }
+ },
+ indicator: [
+ { name: 'Sales', max: 10000 },
+ { name: 'Administration', max: 20000 },
+ { name: 'Information Techology', max: 20000 },
+ { name: 'Customer Support', max: 20000 },
+ { name: 'Development', max: 20000 },
+ { name: 'Marketing', max: 20000 }
+ ]
+ },
+ legend: {
+ left: 'center',
+ bottom: '10',
+ data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
+ },
+ series: [{
+ type: 'radar',
+ symbolSize: 0,
+ areaStyle: {
+ normal: {
+ shadowBlur: 13,
+ shadowColor: 'rgba(0,0,0,.2)',
+ shadowOffsetX: 0,
+ shadowOffsetY: 10,
+ opacity: 1
+ }
+ },
+ data: [
+ {
+ value: [5000, 7000, 12000, 11000, 15000, 14000],
+ name: 'Allocated Budget'
+ },
+ {
+ value: [4000, 9000, 15000, 15000, 13000, 11000],
+ name: 'Expected Spending'
+ },
+ {
+ value: [5500, 11000, 12000, 15000, 12000, 12000],
+ name: 'Actual Spending'
+ }
+ ],
+ animationDuration: animationDuration
+ }]
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/dashboard/mixins/resize.js b/sgd-ui/src/views/dashboard/mixins/resize.js
new file mode 100644
index 0000000..b1e76e9
--- /dev/null
+++ b/sgd-ui/src/views/dashboard/mixins/resize.js
@@ -0,0 +1,56 @@
+import { debounce } from '@/utils'
+
+export default {
+ data() {
+ return {
+ $_sidebarElm: null,
+ $_resizeHandler: null
+ }
+ },
+ mounted() {
+ this.initListener()
+ },
+ activated() {
+ if (!this.$_resizeHandler) {
+ // avoid duplication init
+ this.initListener()
+ }
+
+ // when keep-alive chart activated, auto resize
+ this.resize()
+ },
+ beforeDestroy() {
+ this.destroyListener()
+ },
+ deactivated() {
+ this.destroyListener()
+ },
+ methods: {
+ // use $_ for mixins properties
+ // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+ $_sidebarResizeHandler(e) {
+ if (e.propertyName === 'width') {
+ this.$_resizeHandler()
+ }
+ },
+ initListener() {
+ this.$_resizeHandler = debounce(() => {
+ this.resize()
+ }, 100)
+ window.addEventListener('resize', this.$_resizeHandler)
+
+ this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
+ this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
+ },
+ destroyListener() {
+ window.removeEventListener('resize', this.$_resizeHandler)
+ this.$_resizeHandler = null
+
+ this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
+ },
+ resize() {
+ const { chart } = this
+ chart && chart.resize()
+ }
+ }
+}
diff --git a/sgd-ui/src/views/error/401.vue b/sgd-ui/src/views/error/401.vue
new file mode 100644
index 0000000..448b6ec
--- /dev/null
+++ b/sgd-ui/src/views/error/401.vue
@@ -0,0 +1,88 @@
+<template>
+ <div class="errPage-container">
+ <el-button icon="arrow-left" class="pan-back-btn" @click="back">
+ 返回
+ </el-button>
+ <el-row>
+ <el-col :span="12">
+ <h1 class="text-jumbo text-ginormous">
+ 401错误!
+ </h1>
+ <h2>您没有访问权限!</h2>
+ <h6>对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面</h6>
+ <ul class="list-unstyled">
+ <li class="link-type">
+ <router-link to="/">
+ 回首页
+ </router-link>
+ </li>
+ </ul>
+ </el-col>
+ <el-col :span="12">
+ <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script>
+import errGif from '@/assets/401_images/401.gif'
+
+export default {
+ name: 'Page401',
+ data() {
+ return {
+ errGif: errGif + '?' + +new Date()
+ }
+ },
+ methods: {
+ back() {
+ if (this.$route.query.noGoBack) {
+ this.$router.push({ path: '/' })
+ } else {
+ this.$router.go(-1)
+ }
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+ .errPage-container {
+ width: 800px;
+ max-width: 100%;
+ margin: 100px auto;
+ .pan-back-btn {
+ background: #008489;
+ color: #fff;
+ border: none!important;
+ }
+ .pan-gif {
+ margin: 0 auto;
+ display: block;
+ }
+ .pan-img {
+ display: block;
+ margin: 0 auto;
+ width: 100%;
+ }
+ .text-jumbo {
+ font-size: 60px;
+ font-weight: 700;
+ color: #484848;
+ }
+ .list-unstyled {
+ font-size: 14px;
+ li {
+ padding-bottom: 5px;
+ }
+ a {
+ color: #008489;
+ text-decoration: none;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+ }
+</style>
diff --git a/sgd-ui/src/views/error/404.vue b/sgd-ui/src/views/error/404.vue
new file mode 100644
index 0000000..96f075c
--- /dev/null
+++ b/sgd-ui/src/views/error/404.vue
@@ -0,0 +1,233 @@
+<template>
+ <div class="wscn-http404-container">
+ <div class="wscn-http404">
+ <div class="pic-404">
+ <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
+ <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
+ <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
+ <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
+ </div>
+ <div class="bullshit">
+ <div class="bullshit__oops">
+ 404错误!
+ </div>
+ <div class="bullshit__headline">
+ {{ message }}
+ </div>
+ <div class="bullshit__info">
+ 对不起,您正在寻找的页面不存在。尝试检查URL的错误,然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。
+ </div>
+ <router-link to="/" class="bullshit__return-home">
+ 返回首页
+ </router-link>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: 'Page404',
+ computed: {
+ message() {
+ return '找不到网页!'
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.wscn-http404-container{
+ transform: translate(-50%,-50%);
+ position: absolute;
+ top: 40%;
+ left: 50%;
+}
+.wscn-http404 {
+ position: relative;
+ width: 1200px;
+ padding: 0 50px;
+ overflow: hidden;
+ .pic-404 {
+ position: relative;
+ float: left;
+ width: 600px;
+ overflow: hidden;
+ &__parent {
+ width: 100%;
+ }
+ &__child {
+ position: absolute;
+ &.left {
+ width: 80px;
+ top: 17px;
+ left: 220px;
+ opacity: 0;
+ animation-name: cloudLeft;
+ animation-duration: 2s;
+ animation-timing-function: linear;
+ animation-fill-mode: forwards;
+ animation-delay: 1s;
+ }
+ &.mid {
+ width: 46px;
+ top: 10px;
+ left: 420px;
+ opacity: 0;
+ animation-name: cloudMid;
+ animation-duration: 2s;
+ animation-timing-function: linear;
+ animation-fill-mode: forwards;
+ animation-delay: 1.2s;
+ }
+ &.right {
+ width: 62px;
+ top: 100px;
+ left: 500px;
+ opacity: 0;
+ animation-name: cloudRight;
+ animation-duration: 2s;
+ animation-timing-function: linear;
+ animation-fill-mode: forwards;
+ animation-delay: 1s;
+ }
+ @keyframes cloudLeft {
+ 0% {
+ top: 17px;
+ left: 220px;
+ opacity: 0;
+ }
+ 20% {
+ top: 33px;
+ left: 188px;
+ opacity: 1;
+ }
+ 80% {
+ top: 81px;
+ left: 92px;
+ opacity: 1;
+ }
+ 100% {
+ top: 97px;
+ left: 60px;
+ opacity: 0;
+ }
+ }
+ @keyframes cloudMid {
+ 0% {
+ top: 10px;
+ left: 420px;
+ opacity: 0;
+ }
+ 20% {
+ top: 40px;
+ left: 360px;
+ opacity: 1;
+ }
+ 70% {
+ top: 130px;
+ left: 180px;
+ opacity: 1;
+ }
+ 100% {
+ top: 160px;
+ left: 120px;
+ opacity: 0;
+ }
+ }
+ @keyframes cloudRight {
+ 0% {
+ top: 100px;
+ left: 500px;
+ opacity: 0;
+ }
+ 20% {
+ top: 120px;
+ left: 460px;
+ opacity: 1;
+ }
+ 80% {
+ top: 180px;
+ left: 340px;
+ opacity: 1;
+ }
+ 100% {
+ top: 200px;
+ left: 300px;
+ opacity: 0;
+ }
+ }
+ }
+ }
+ .bullshit {
+ position: relative;
+ float: left;
+ width: 300px;
+ padding: 30px 0;
+ overflow: hidden;
+ &__oops {
+ font-size: 32px;
+ font-weight: bold;
+ line-height: 40px;
+ color: #1482f0;
+ opacity: 0;
+ margin-bottom: 20px;
+ animation-name: slideUp;
+ animation-duration: 0.5s;
+ animation-fill-mode: forwards;
+ }
+ &__headline {
+ font-size: 20px;
+ line-height: 24px;
+ color: #222;
+ font-weight: bold;
+ opacity: 0;
+ margin-bottom: 10px;
+ animation-name: slideUp;
+ animation-duration: 0.5s;
+ animation-delay: 0.1s;
+ animation-fill-mode: forwards;
+ }
+ &__info {
+ font-size: 13px;
+ line-height: 21px;
+ color: grey;
+ opacity: 0;
+ margin-bottom: 30px;
+ animation-name: slideUp;
+ animation-duration: 0.5s;
+ animation-delay: 0.2s;
+ animation-fill-mode: forwards;
+ }
+ &__return-home {
+ display: block;
+ float: left;
+ width: 110px;
+ height: 36px;
+ background: #1482f0;
+ border-radius: 100px;
+ text-align: center;
+ color: #ffffff;
+ opacity: 0;
+ font-size: 14px;
+ line-height: 36px;
+ cursor: pointer;
+ animation-name: slideUp;
+ animation-duration: 0.5s;
+ animation-delay: 0.3s;
+ animation-fill-mode: forwards;
+ }
+ @keyframes slideUp {
+ 0% {
+ transform: translateY(60px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/views/index.vue b/sgd-ui/src/views/index.vue
new file mode 100644
index 0000000..f5beeb5
--- /dev/null
+++ b/sgd-ui/src/views/index.vue
@@ -0,0 +1,1099 @@
+<template>
+ <div class="app-container home">
+ <el-row :gutter="20">
+ <el-col :sm="24" :lg="12" style="padding-left: 20px">
+ <h2>若依后台管理框架</h2>
+ <p>
+ 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
+ </p>
+ <p>
+ <b>当前版本:</b> <span>v{{ version }}</span>
+ </p>
+ <p>
+ <el-tag type="danger">¥免费开源</el-tag>
+ </p>
+ <p>
+ <el-button
+ type="primary"
+ size="mini"
+ icon="el-icon-cloudy"
+ plain
+ @click="goTarget('https://gitee.com/y_project/RuoYi-Cloud')"
+ >访问码云</el-button
+ >
+ <el-button
+ size="mini"
+ icon="el-icon-s-home"
+ plain
+ @click="goTarget('http://ruoyi.vip')"
+ >访问主页</el-button
+ >
+ </p>
+ </el-col>
+
+ <el-col :sm="24" :lg="12" style="padding-left: 50px">
+ <el-row>
+ <el-col :span="12">
+ <h2>技术选型</h2>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="6">
+ <h4>后端技术</h4>
+ <ul>
+ <li>SpringBoot</li>
+ <li>SpringCloud</li>
+ <li>Nacos</li>
+ <li>Sentinel</li>
+ <li>Seata</li>
+ <li>Minio</li>
+ <li>...</li>
+ </ul>
+ </el-col>
+ <el-col :span="6">
+ <h4>前端技术</h4>
+ <ul>
+ <li>Vue</li>
+ <li>Vuex</li>
+ <li>Element-ui</li>
+ <li>Axios</li>
+ <li>Echarts</li>
+ <li>Quill</li>
+ <li>...</li>
+ </ul>
+ </el-col>
+ </el-row>
+ </el-col>
+ </el-row>
+ <el-divider />
+ <el-row :gutter="20">
+ <el-col :xs="24" :sm="24" :md="12" :lg="8">
+ <el-card class="update-log">
+ <div slot="header" class="clearfix">
+ <span>联系信息</span>
+ </div>
+ <div class="body">
+ <p>
+ <i class="el-icon-s-promotion"></i> 官网:<el-link
+ href="http://www.ruoyi.vip"
+ target="_blank"
+ >http://www.ruoyi.vip</el-link
+ >
+ </p>
+ <p>
+ <i class="el-icon-user-solid"></i> QQ群: <s> 满42799195 </s> <s> 满170157040 </s>
+ <s> 满130643120 </s> <s> 满225920371 </s> <s> 满201705537 </s> <s> 满236543183 </s>
+ <s> 满213618602 </s> <s> 满148794840 </s> <s> 满118752664 </s> <s> 满101038945 </s>
+ <s> 满128355254 </s> <s> 满179219821 </s> <s> 满158753145 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=jR7HqTiLzuLocIH6aNNtTW3LlCV8UQ6d&authKey=GJZj%2Bnwmsvk6j%2FWrX7FKstAaRjgUC1WL%2F%2B8aVTaPbHX5wOimH5q9igaOSXP7cF9L&noverify=0&group_code=112869560" target="_blank">112869560</a>
+ </p>
+ <p>
+ <i class="el-icon-chat-dot-round"></i> 微信:<a
+ href="javascript:;"
+ >/ *若依</a
+ >
+ </p>
+ <p>
+ <i class="el-icon-money"></i> 支付宝:<a
+ href="javascript:;"
+ class="支付宝信息"
+ >/ *若依</a
+ >
+ </p>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="12" :lg="8">
+ <el-card class="update-log">
+ <div slot="header" class="clearfix">
+ <span>更新日志</span>
+ </div>
+ <el-collapse accordion>
+ <el-collapse-item title="v3.6.8 - 2026-03-30">
+ <ol>
+ <li>新增锁定屏幕功能</li>
+ <li>首页新增通知公告消息提醒</li>
+ <li>添加持久化标签页开关功能</li>
+ <li>菜单搜索支持文本高亮&数量提示</li>
+ <li>添加菜单路由地址和名称的校验规则</li>
+ <li>字典类型列表新增抽屉效果详细信息</li>
+ <li>升级axios到最新版本0.30.3</li>
+ <li>升级spring-cloud到最新版2025.1.0</li>
+ <li>升级spring-cloud-alibaba到最新版2025.1.0.0</li>
+ <li>升级spring-boot-admin到最新版4.0.2</li>
+ <li>升级dynamic-ds到最新版本4.5.0</li>
+ <li>升级springdoc到最新版本3.0.2</li>
+ <li>升级transmittable-thread-local到最新版本2.14.5</li>
+ <li>升级spring-boot到最新版本4.0.3</li>
+ <li>升级druid到最新版本1.2.28</li>
+ <li>升级pagehelper到最新版2.1.1</li>
+ <li>优化操作日志详细页面</li>
+ <li>部门管理支持批量保存排序</li>
+ <li>菜单管理支持批量保存排序</li>
+ <li>菜单管理列表新增类型显示</li>
+ <li>代码生成模板支持TypeScript版本</li>
+ <li>优化菜单主题风格显示</li>
+ <li>优化点击任务名称查看详细</li>
+ <li>优化字典类型属性提醒说明</li>
+ <li>优化防重提交间隔时间可自定义</li>
+ <li>优化页签功能&支持全屏按钮操作</li>
+ <li>优化RightToolbar搜索栏切换动画</li>
+ <li>修复Excel自定义格式样式污染问题</li>
+ <li>优化isAdmin方法统一到SecurityUtils</li>
+ <li>优化定时任务详情页展示&补充执行时间字段</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.7 - 2025-12-22">
+ <ol>
+ <li>支持防盗链功能</li>
+ <li>菜单导航设置支持纯顶部</li>
+ <li>用户头像更换后移除旧头像文件</li>
+ <li>支持Excel导出对象的多个子列表</li>
+ <li>升级druid到最新版本1.2.27</li>
+ <li>升级fastjson到最新版2.0.60</li>
+ <li>升级tomcat到最新版本9.0.112</li>
+ <li>升级commons.io到最新版本2.21.0</li>
+ <li>用户导入添加验证提示</li>
+ <li>显示列信息支持对象格式</li>
+ <li>网页标题设置新增SET_TITLE方法</li>
+ <li>自动识别json对象白名单配置范围缩小</li>
+ <li>登录/注册页面底部版权信息修改为读取配置</li>
+ <li>修复用户归属部门无法修改为空问题</li>
+ <li>修复固定头部时出现的导航栏偏移问题</li>
+ <li>修复v3时间控件between选择后清空报错问题</li>
+ <li>修复comboReadDict属性下多个sheet出现的报错</li>
+ <li>修复表单构建移除所有控件后切换路由回来空白问题</li>
+ <li>优化布局设置显示</li>
+ <li>优化字典组件值宽松匹配</li>
+ <li>优化生成代码下载的zip文件名</li>
+ <li>优化日志记录参数拼装提升效率</li>
+ <li>优化导入文件检查标题行不能为空</li>
+ <li>优化表单构建关闭页签销毁复制插件</li>
+ <li>优化Excel统计行数值的单元格样式显示</li>
+ <li>优化数据权限控制逻辑,放开permission限制</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.6 - 2025-05-30">
+ <ol>
+ <li>优化菜单搜索查询页</li>
+ <li>导航栏显示昵称&设置</li>
+ <li>用户管理支持分栏拖动</li>
+ <li>修改主题样式本地读取</li>
+ <li>菜单管理新增路由名称</li>
+ <li>添加底部版权信息&开关</li>
+ <li>分配角色禁用不允许勾选</li>
+ <li>添加页签图标显示开关功能</li>
+ <li>用户管理过滤掉已禁用部门</li>
+ <li>上传组件新增拖动排序属性</li>
+ <li>显隐列组件支持全选/全不选</li>
+ <li>白名单支持对通配符路径匹配</li>
+ <li>初始密码支持自定义修改策略</li>
+ <li>账号密码支持自定义更新周期</li>
+ <li>菜单面包屑导航支持多层级显示</li>
+ <li>支持富文本复制粘贴图片上传至url</li>
+ <li>支持文件&图片组件自定义地址&参数</li>
+ <li>更新ry-config的nacos表结构到最新版本</li>
+ <li>代码生成新增配置是否允许文件覆盖到本地</li>
+ <li>使用CacheRequestBody代替CacheRequestFilter</li>
+ <li>升级tomcat到最新版本9.0.105</li>
+ <li>升级fastjson到最新版2.0.57</li>
+ <li>升级commons.io到最新版本2.19.0</li>
+ <li>package.json移除runjs&eslint&vue-meta依赖</li>
+ <li>修复导出子列表对象只能在最后的问题</li>
+ <li>修复TopNav无法正确获取active的问题</li>
+ <li>修复默认关闭Tags-Views内链页面打不开</li>
+ <li>Excel注解支持wrapText是否允许内容换行</li>
+ <li>优化文件上传组件新增类型</li>
+ <li>优化导入带标题文件关闭清理</li>
+ <li>优化参数键值更换为多行文本</li>
+ <li>优化特殊字符密码修改失败问题</li>
+ <li>优化代码生成列表支持按时间排序</li>
+ <li>优化TopNav内链菜单点击没有高亮</li>
+ <li>优化文件异常输入流未关闭的问题</li>
+ <li>优化菜单管理切换Mini布局错乱问题</li>
+ <li>优化空指针异常时无法获取错误信息问题</li>
+ <li>优化文件&图片上传组件新增disabled属性</li>
+ <li>优化isAdmin方法,避免脱敏模块security依赖</li>
+ <li>优化定时任务字符包含多个括号导致数据错误</li>
+ <li>优化登录&注册页表头使用VUE_APP_TITLE配置值</li>
+ <li>优化导出Excel日期格式双击离开后与设定的格式不一致问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.5 - 2024-11-13">
+ <ol>
+ <li>使用SpringDoc代替Swagger</li>
+ <li>菜单管理新增路由名称</li>
+ <li>新增数据脱敏过滤注解</li>
+ <li>限制用户操作数据权限范围</li>
+ <li>支持自定义显示Excel属性列</li>
+ <li>操作日志记录DELETE请求参数</li>
+ <li>用户登录后记录最后登录IP&时间</li>
+ <li>升级druid到最新版本1.2.23</li>
+ <li>升级fastjson到最新版2.0.53</li>
+ <li>升级dynamic-ds到最新版本4.3.1</li>
+ <li>升级spring-cloud到最新版2021.0.9</li>
+ <li>升级spring-boot-admin到最新版2.7.16</li>
+ <li>升级spring-cloud-alibaba到最新版2021.0.6.1</li>
+ <li>升级quill到最新版本2.0.2</li>
+ <li>升级axios到最新版本0.28.1</li>
+ <li>升级core-js到最新版本3.37.1</li>
+ <li>升级其他依赖到安全版本,防止漏洞风险</li>
+ <li>修复角色禁用权限不失效问题</li>
+ <li>优化身份证脱敏正则</li>
+ <li>优化权限更新后同步缓存</li>
+ <li>优化查询时间范围日期格式</li>
+ <li>优化代码生成上级菜单字段类型</li>
+ <li>优化无用户编号不校验数据权限</li>
+ <li>优化代码生成主子表关联查询方式</li>
+ <li>优化校检文件名是否包含特殊字符</li>
+ <li>优化查表特殊字符使用反斜杠进行转义</li>
+ <li>优化多个自定数据权限使用in查询,避免多次拼接</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.4 - 2024-04-01">
+ <ol>
+ <li>全局数据存储用户编号</li>
+ <li>用户密码新增非法字符验证</li>
+ <li>代码生成支持选择前端模板类型</li>
+ <li>操作日志列表新增IP地址查询</li>
+ <li>显隐列组件支持复选框弹出类型</li>
+ <li>Excel注解ColumnType类型新增文本</li>
+ <li>Excel自定义数据处理器增加单元格/工作簿对象</li>
+ <li>升级element-ui到最新版本2.15.14</li>
+ <li>升级compression-webpack-plugin到6.1.2以兼容node18+</li>
+ <li>升级druid到最新版本1.2.20</li>
+ <li>升级fastjson到最新版2.0.43</li>
+ <li>升级pagehelper到最新版2.0.0</li>
+ <li>升级dynamic-ds到最新版本4.2.0</li>
+ <li>升级commons.io到最新版本2.13.0</li>
+ <li>升级spring-boot到最新版本2.7.18</li>
+ <li>升级spring-boot-admin到最新版2.7.15</li>
+ <li>升级transmittable-thread-local到最新版本2.14.4</li>
+ <li>修复五级路由缓存无效问题</li>
+ <li>修复外链带端口出现的异常</li>
+ <li>修复内链iframe没有传递参数问题</li>
+ <li>修复自定义字典样式不生效的问题</li>
+ <li>修复字典缓存删除方法参数错误问题</li>
+ <li>修复Excel导入数据临时文件无法删除问题</li>
+ <li>修复未登录带参数访问成功后参数丢失问题</li>
+ <li>修复HeaderSearch组件跳转query参数丢失问题</li>
+ <li>修复数据字典列表页重置后标签值无法输入问题</li>
+ <li>修复Excels导入时无法获取到readConverterExp内容转表达式问题</li>
+ <li>优化Xss注解匹配方式</li>
+ <li>优化权限字符匹配方式</li>
+ <li>优化下载zip方法新增遮罩层</li>
+ <li>优化头像上传参数新增文件名称</li>
+ <li>优化字典标签支持自定义分隔符</li>
+ <li>优化定时任务白名单配置范围缩小</li>
+ <li>优化菜单管理类型为按钮状态可选</li>
+ <li>优化前端防重复提交数据大小限制</li>
+ <li>优化TopNav菜单没有图标svg不显示</li>
+ <li>优化富文本Editor组件检验图片格式</li>
+ <li>优化数字金额大写转换精度丢失问题</li>
+ <li>优化个人中心/基本资料修改时数据显示问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.3 - 2023-07-07">
+ <ol>
+ <li>支持登录IP黑名单限制</li>
+ <li>操作日志新增消耗时间属性</li>
+ <li>屏蔽定时任务bean违规的字符</li>
+ <li>日志管理使用索引提升查询性能</li>
+ <li>日志注解支持排除指定的请求参数</li>
+ <li>支持自定义隐藏属性列过滤子对象</li>
+ <li>升级spring-boot到最新版本2.7.13</li>
+ <li>升级spring-cloud到最新版2021.0.8</li>
+ <li>升级spring-cloud-alibaba到最新版2021.0.5.0</li>
+ <li>升级druid到最新版本1.2.16</li>
+ <li>升级fastjson到最新版2.0.34</li>
+ <li>升级pagehelper到最新版1.4.7</li>
+ <li>升级transmittable-thread-local到最新版本2.14.3</li>
+ <li>升级element-ui到最新版本2.15.13</li>
+ <li>移除apache/commons-fileupload依赖</li>
+ <li>修复页面切换时布局错乱的问题</li>
+ <li>修复用户多角色数据权限可能出现权限抬升的情况</li>
+ <li>修复导入用户时无法更新存在用户数据的问题</li>
+ <li>修复开启TopNav后一级菜单路由参数设置无效问题</li>
+ <li>优化文件下载出现的异常</li>
+ <li>优化选择图标组件高亮回显</li>
+ <li>优化修改密码日志存储明文问题</li>
+ <li>优化排序属性orderBy参数限制长度</li>
+ <li>优化页签栏关闭其他出现的异常问题</li>
+ <li>优化页签关闭左侧选项排除首页选项</li>
+ <li>优化关闭当前tab页跳转最右侧tab页</li>
+ <li>优化文件上传服务关闭InputStream</li>
+ <li>优化页签在Firefox浏览器被遮挡的问题</li>
+ <li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li>
+ <li>优化DictTag组件value没有匹配的值时则展示value</li>
+ <li>优化去除@EnableCustomSwagger注解后会启动失败问题</li>
+ <li>优化upload接口在文件过大和文件名过长的情况返回提示信息</li>
+ <li>优化异步保存日志发生报错不进RemoteLogFallbackFactory问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.2 - 2023-01-16">
+ <ol>
+ <li>重置时取消部门选中</li>
+ <li>新增返回警告消息提示</li>
+ <li>忽略不必要的属性数据返回</li>
+ <li>修改参数键名时移除前缓存配置</li>
+ <li>开启TopNav没有子菜单隐藏侧边栏</li>
+ <li>删除fuse无效选项maxPatternLength</li>
+ <li>兼容Excel下拉框内容过多无法显示的问题</li>
+ <li>修复文件上传组件格式验证问题</li>
+ <li>修复回显数据字典数组异常问题</li>
+ <li>修复sheet超出最大行数异常问题</li>
+ <li>修复Log注解GET请求记录不到参数问题</li>
+ <li>修复gateway流控规则生效但不显示问题</li>
+ <li>修复主题颜色在Drawer组件不会加载问题</li>
+ <li>修复调度日志点击多次数据不变化的问题</li>
+ <li>修复用户编辑时角色和部门存在无法修改情况</li>
+ <li>修复使用透明底png图片时,自动填充黑色背景</li>
+ <li>修复table中更多按钮切换主题色未生效修复问题</li>
+ <li>修复某些特性的环境生成代码变乱码TXT文件问题</li>
+ <li>修复代码生成图片/文件/单选时选择必填无法校验问题</li>
+ <li>升级spring-cloud到最新版2021.0.5</li>
+ <li>升级spring-boot到最新版本2.7.7</li>
+ <li>升级spring-boot-admin到最新版2.7.10</li>
+ <li>升级kaptcha到最新版2.3.3</li>
+ <li>升级druid到最新版本1.2.15</li>
+ <li>升级fastjson到最新版2.0.22</li>
+ <li>升级pagehelper到最新版1.4.6</li>
+ <li>升级transmittable-thread-local到最新版本2.14.2</li>
+ <li>升级echarts到最新版本5.4.0</li>
+ <li>升级core-js到最新版本3.25.3</li>
+ <li>升级element-ui到最新版本2.15.12</li>
+ <li>移除commons-collections多余的依赖</li>
+ <li>优化弹窗内容过多展示不全问题</li>
+ <li>优化导出对象的子列表为空会出现[]问题</li>
+ <li>优化字符未使用下划线不进行驼峰式处理</li>
+ <li>优化nacos修改xss开关时同步过滤器验证</li>
+ <li>优化修改头像在小屏幕上页面布局错位的问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.1 - 2022-10-01">
+ <ol>
+ <li>数据逻辑删除不进行唯一验证</li>
+ <li>支持多权限字符匹配角色数据权限</li>
+ <li>页面内嵌iframe切换tab不刷新数据</li>
+ <li>新增密码最大错误次数/锁定时间</li>
+ <li>登录日志新增解锁账户功能</li>
+ <li>通用下载方法新增config配置选项</li>
+ <li>操作日志记录支持排除敏感属性字段</li>
+ <li>Excel注解支持导出对象的子列表方法</li>
+ <li>Excel注解支持自定义隐藏属性列</li>
+ <li>Excel注解支持backgroundColor属性设置背景色</li>
+ <li>升级spring-cloud-alibaba到最新版2021.0.4.0</li>
+ <li>升级spring-cloud到最新版2021.0.4</li>
+ <li>升级spring-boot到最新版本2.7.3</li>
+ <li>升级spring-boot-admin到最新版2.7.5</li>
+ <li>升级seata到最新版1.5.2</li>
+ <li>升级druid到最新版本1.2.12</li>
+ <li>升级fastjson到最新版2.0.14</li>
+ <li>升级pagehelper到最新版1.4.5</li>
+ <li>升级core-js到最新版本3.25.2</li>
+ <li>升级dynamic-ds到最新版本3.5.2</li>
+ <li>升级element-ui到最新版本2.15.10</li>
+ <li>修复多文件上传报错出现的异常问题</li>
+ <li>修复图片预览组件src属性为null值控制台报错问题</li>
+ <li>修复使用FastDFS上传头像失败提示文件名没有后缀问题</li>
+ <li>优化seata单独依赖模块</li>
+ <li>优化任务过期不执行调度</li>
+ <li>优化字典数据使用store存取</li>
+ <li>优化代码生成同步后值NULL问题</li>
+ <li>优化定时任务支持执行父类方法</li>
+ <li>优化修改资料头像被覆盖的问题</li>
+ <li>优化修改用户登录账号重复验证</li>
+ <li>优化用户个人信息接口防止修改部门</li>
+ <li>优化布局设置使用el-drawer抽屉显示</li>
+ <li>优化日志注解记录限制请求地址的长度</li>
+ <li>优化导入更新用户数据前校验数据权限</li>
+ <li>优化excel/scale属性导出单元格数值类型</li>
+ <li>优化日志操作中重置按钮时重复查询的问题</li>
+ <li>优化多个相同角色数据导致权限SQL重复问题</li>
+ <li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.6.0 - 2022-07-16">
+ <ol>
+ <li>Excel注解支持color字体颜色</li>
+ <li>用户头像上传限制只能为图片格式</li>
+ <li>检查定时任务bean所在包名是否为白名单配置</li>
+ <li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
+ <li>升级spring-cloud-alibaba到最新版2021.0.1.0</li>
+ <li>升级spring-cloud到最新版2021.0.3</li>
+ <li>升级spring-boot到最新版本2.7.1</li>
+ <li>升级spring-boot-admin到最新版2.7.2</li>
+ <li>升级seata到最新版1.5.1</li>
+ <li>升级pagehelper到最新版1.4.3</li>
+ <li>升级dynamic-ds到最新版本3.5.1</li>
+ <li>升级fastjson到最新版2.0.9</li>
+ <li>升级druid到最新版本1.2.11</li>
+ <li>升级transmittable-thread-local到最新版本2.13.2</li>
+ <li>升级element-ui到最新版本2.15.9</li>
+ <li>修复字典数据显示不全问题</li>
+ <li>修复操作日志查询类型条件为0时会查到所有数据</li>
+ <li>优化验证码开关变量名</li>
+ <li>优化设置分页参数默认值</li>
+ <li>优化对空字符串参数处理的过滤</li>
+ <li>优化Maven使用阿里云镜像站加速</li>
+ <li>优化用户列表查询不显示密码字段</li>
+ <li>优化表单构建按钮不显示正则校验</li>
+ <li>优化字典类型删除多余的mapper注解</li>
+ <li>优化字典数据回显样式下拉框显示值</li>
+ <li>优化用户管理左侧树型组件增加选中高亮保持</li>
+ <li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
+ <li>优化数据监控Spring Security权限认证过时代码</li>
+ <li>优化岗位长主键溢出问题将查询返回类型改为Long</li>
+ <li>优化删除无用admin-client依赖声明,避免造成误解</li>
+ <li>优化默认不启用压缩文件缓存防止node_modules过大</li>
+ <li>优化获取body请求数据缓存过滤器CacheRequestFilter</li>
+ <li>优化网关通过注解解决循环引用及Bean重复问题删除allow配置</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.5.0 - 2022-04-11">
+ <ol>
+ <li>开启TopNav没有子菜单情况隐藏侧边栏</li>
+ <li>侧边栏菜单名称过长悬停显示标题</li>
+ <li>用户访问控制时校验数据权限,防止越权</li>
+ <li>导出Excel时屏蔽公式,防止CSV注入风险</li>
+ <li>组件ImageUpload支持多图同时选择上传</li>
+ <li>组件FileUpload支持多文件同时选择上传</li>
+ <li>代码生成树表新增(展开/折叠)</li>
+ <li>代码生成子表支持日期/字典配置</li>
+ <li>代码生成编辑修改打开新页签</li>
+ <li>添加页签openPage支持传递参数</li>
+ <li>添加清理分页的线程变量方法</li>
+ <li>修改npm即将过期的注册源地址</li>
+ <li>用户缓存信息添加部门ancestors祖级列表</li>
+ <li>升级spring-cloud到最新版2021.0.1</li>
+ <li>升级spring-boot到最新版本2.6.6</li>
+ <li>升级spring-boot-admin到最新版2.6.6</li>
+ <li>升级spring-boot-mybatis到最新版2.2.2</li>
+ <li>降级jsencrypt版本兼容IE浏览器</li>
+ <li>修复分页组件请求两次问题</li>
+ <li>修复表单清除元素位置未垂直居中问题</li>
+ <li>修复Excel注解prompt/combo同时使用不生效问题</li>
+ <li>修复导入Excel时字典字段类型为Long转义为空问题</li>
+ <li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
+ <li>修复Xss注解字段值为空时的异常问题</li>
+ <li>优化IP地址获取到多个的问题</li>
+ <li>优化文件上传兼容Weblogic环境</li>
+ <li>代码生成同步保留必填/类型选项</li>
+ <li>优化Excel格式化不同类型的日期对象</li>
+ <li>优化菜单表关键字导致的插件报错问题</li>
+ <li>优化Oracle用户头像列为空时不显示问题</li>
+ <li>优化页面若未匹配到字典标签则返回原字典值</li>
+ <li>优化修复登录失效后多次请求提示多次弹窗问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.4.0 - 2022-01-24">
+ <ol>
+ <li>新增Vue3前端代码生成模板</li>
+ <li>新增图片预览组件</li>
+ <li>新增压缩插件实现打包Gzip</li>
+ <li>新增docker一键复制的脚本</li>
+ <li>自定义xss校验注解实现</li>
+ <li>路由支持单独配置菜单或角色权限</li>
+ <li>前端支持设置是否需要防止数据重复提交</li>
+ <li>预览组件支持多图显示</li>
+ <li>代码生成列表图片支持预览</li>
+ <li>代码生成新增Java类型Boolean</li>
+ <li>定时任务目标字符串过滤特殊字符</li>
+ <li>定时任务目标字符串验证包名白名单</li>
+ <li>升级nacos到最新版2.0.4</li>
+ <li>升级spring-cloud到最新版2021.0.0</li>
+ <li>升级spring-boot到最新版本2.6.3</li>
+ <li>升级spring-boot-admin到最新版2.6.1</li>
+ <li>升级pagehelper到最新版1.4.1</li>
+ <li>升级fastjson到最新版1.2.79</li>
+ <li>SQL工具类新增检查关键字方法</li>
+ <li>修复打包后字体图标偶现的乱码问题</li>
+ <li>修复版本差异导致的懒加载报错问题</li>
+ <li>修复选项卡点击右键刷新丢失参数问题</li>
+ <li>修复登录失效后多次请求提示多次弹窗问题</li>
+ <li>优化加载字典缓存数据</li>
+ <li>优化代码生成同步更新字段</li>
+ <li>优化代码生成字典组重复问题</li>
+ <li>优化空值不进行回显数据字典</li>
+ <li>优化用户导入提示溢出则显示滚动条</li>
+ <li>优化定时任务cron表达式小时设置24</li>
+ <li>优化部门修改缩放后出现的错位问题</li>
+ <li>优化分页方法设置成通用方便灵活调用</li>
+ <li>优化用户管理部门查询选择节点后分页参数初始</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.3.0 - 2021-12-13">
+ <ol>
+ <li>新增配套并同步的Vue3前端版本</li>
+ <li>新增认证对象简化权限验证</li>
+ <li>新增tab对象简化页签操作</li>
+ <li>修改获取缓存信息方式</li>
+ <li>修改权限认证注解实现</li>
+ <li>自定义文字复制剪贴指令</li>
+ <li>升级axios到最新版本0.24.0</li>
+ <li>升级core-js到最新版本3.19.1</li>
+ <li>升级jsencrypt到最新版本3.2.1</li>
+ <li>升级js-cookie到最新版本3.0.1</li>
+ <li>升级clipboard到最新版本2.0.8</li>
+ <li>升级velocity到最新版本2.3</li>
+ <li>升级spring-boot到最新版本2.5.6</li>
+ <li>升级spring-boot-admin到最新版2.5.4</li>
+ <li>升级dynamic-ds到最新版本3.5.0</li>
+ <li>代码生成预览支持复制内容</li>
+ <li>修复五级以上菜单出现的404问题</li>
+ <li>生产环境使用路由懒加载提升页面响应速度</li>
+ <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
+ <li>优化用户个人信息接口防止修改用户名</li>
+ <li>优化登录/验证码请求headers不设置token</li>
+ <li>优化注册成功提示消息类型success</li>
+ <li>优化下载解析blob响应是否登录失效</li>
+ <li>修复字符串无法被反转义问题</li>
+ <li>修复响应体过大出现的乱码问题</li>
+ <li>修复回显数据字典组的键值错误</li>
+ <li>修复代码生成复选框字典遗漏问题</li>
+ <li>修复代码生成模板主子表删除缺少事务</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.2.0 - 2021-10-12">
+ <ol>
+ <li>菜单管理支持配置路由参数</li>
+ <li>定时任务支持在线生成cron表达式</li>
+ <li>自定义弹层溢出滚动样式</li>
+ <li>自定义可拖动弹窗宽度指令</li>
+ <li>自定义可拖动弹窗高度指令</li>
+ <li>修改时检查用户数据权限范围</li>
+ <li>修复保存配置主题颜色失效问题</li>
+ <li>新增暗色菜单风格主题</li>
+ <li>菜单&部门新增展开/折叠功能</li>
+ <li>页签新增关闭左侧&添加图标</li>
+ <li>代码生成主子表多选行数据</li>
+ <li>日期范围支持添加多组</li>
+ <li>Excel导入支持@Excels注解</li>
+ <li>Excel注解支持导入导出标题信息</li>
+ <li>Excel注解支持自定义数据处理器</li>
+ <li>日志注解新增是否保存响应参数</li>
+ <li>定时任务对检查异常进行事务回滚</li>
+ <li>补充定时任务表字段注释</li>
+ <li>定时任务屏蔽ldap远程调用</li>
+ <li>新增通用方法简化下载使用</li>
+ <li>新增通用方法简化模态/缓存使用</li>
+ <li>新增data-dict组件简化数据字典使用</li>
+ <li>禁用dict-tag组件的渐变动画</li>
+ <li>默认首页使用keep-alive缓存</li>
+ <li>升级springcloud到最新版2020.0.4</li>
+ <li>升级spring-boot到最新版本2.5.5</li>
+ <li>升级spring-boot-admin到最新版2.5.2</li>
+ <li>升级pagehelper到最新版1.4.0</li>
+ <li>升级fastjson到最新版1.2.78</li>
+ <li>升级druid到最新版1.2.8</li>
+ <li>升级element-ui到最新版本2.15.6</li>
+ <li>升级sass-loader到最新版本10.1.1</li>
+ <li>升级dart-sass到版本1.32.13</li>
+ <li>升级file-saver到最新版本2.0.5</li>
+ <li>优化异常处理信息</li>
+ <li>验证码默认20s超时</li>
+ <li>优化代码生成导入表按创建时间排序</li>
+ <li>优化代码生成点击预览重置激活tab</li>
+ <li>修复主子表代码模板方法名错误问题</li>
+ <li>修复xss过滤后格式出现的异常</li>
+ <li>修复多图组件验证失败被删除问题</li>
+ <li>请求参数新增reasonable分页合理化属性</li>
+ <li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
+ <li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.1.0 - 2021-08-02">
+ <ol>
+ <li>支持配置XSS跨站脚本过滤</li>
+ <li>支持配置验证码开关&类型</li>
+ <li>新增是否开启用户注册功能</li>
+ <li>用户管理新增分配角色功能</li>
+ <li>角色管理新增分配用户功能</li>
+ <li>系统布局配置支持动态标题开关</li>
+ <li>增加字典标签样式回显dict组件</li>
+ <li>FileUpload组件支持多文件上传</li>
+ <li>ImageUpload组件支持多图片上传</li>
+ <li>封装通用iframe组件</li>
+ <li>菜单路由配置支持内链访问</li>
+ <li>全局注册通用组件</li>
+ <li>富文本默认上传返回url类型</li>
+ <li>富文本新增上传文件大小限制</li>
+ <li>增加自定义弹窗拖拽指令</li>
+ <li>顶部菜单排除隐藏的默认路由</li>
+ <li>跳转路由高亮相对应的菜单栏</li>
+ <li>日志列表支持排序操作</li>
+ <li>分页组件新增pagerCount属性</li>
+ <li>定时任务屏蔽http(s)远程调用</li>
+ <li>文件服务本地资源允许跨域访问</li>
+ <li>升级spring-boot到最新版本2.5.3</li>
+ <li>升级spring-boot-admin到最新版2.4.3</li>
+ <li>升级spring-boot-mybatis到最新版2.2.0</li>
+ <li>升级nacos到最新版2.0.3</li>
+ <li>升级pagehelper到最新版1.3.1</li>
+ <li>升级minio到最新版本8.2.2</li>
+ <li>升级tobato到最新版本1.27.2</li>
+ <li>升级dynamic-ds到最新版本3.4.1</li>
+ <li>升级commons.io到最新版本v2.11.0</li>
+ <li>升级common-pool到最新版本2.10.0</li>
+ <li>升级commons.fileupload到最新版本v1.4</li>
+ <li>升级element-ui到最新版本2.15.3</li>
+ <li>优化统一网关错误码响应</li>
+ <li>修复导出含params属性对象参数问题</li>
+ <li>修复任意账户越权问题</li>
+ <li>修复定时任务日志执行状态显示</li>
+ <li>修改登录失效返回值code401</li>
+ <li>用户信息长度校验限制</li>
+ <li>角色&菜单新增字段属性提示信息</li>
+ <li>修复用户搜索分页变量错误</li>
+ <li>优化部门父级启用状态</li>
+ <li>启用部门状态排除顶级节点</li>
+ <li>定时任务新增更多操作</li>
+ <li>优化代码生成模板</li>
+ <li>优化顶部菜单显示样式</li>
+ <li>优化导入用户显示样式</li>
+ <li>优化用户不能删除自己</li>
+ <li>密码框新增显示切换密码图标</li>
+ <li>BLOB下载时清除URL对象引用</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v3.0.0 - 2021-06-10">
+ <ol>
+ <li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li>
+ <li>布局设置支持保存&重置配置</li>
+ <li>富文本编辑器支持自定义上传地址</li>
+ <li>富文本编辑组件新增readOnly属性</li>
+ <li>优化参数&字典缓存操作</li>
+ <li>新增IE浏览器版本过低提示页面</li>
+ <li>页签TagsView新增关闭右侧功能</li>
+ <li>显隐列组件加载初始默认隐藏列</li>
+ <li>关闭头像上传窗口还原默认图片</li>
+ <li>个人信息添加手机&邮箱重复验证</li>
+ <li>代码生成模板树表操作列添加新增按钮</li>
+ <li>代码生成模板修复主子表字段重名问题</li>
+ <li>支持docker部署项目</li>
+ <li>升级springcloud到最新版2020.0.3</li>
+ <li>升级spring-boot-alibaba到最新版2021.1</li>
+ <li>升级nacos到最新版2.0.1 性能提升</li>
+ <li>升级spring-boot到最新版本2.5.0</li>
+ <li>升级spring-boot-admin到最新版2.4.1</li>
+ <li>升级swagger到最新版本3.0.0</li>
+ <li>升级mybatis到最新版3.5.6</li>
+ <li>升级dynamic-ds到最新版本3.3.2</li>
+ <li>升级minio到最新版本8.2.1</li>
+ <li>升级fastjson到最新版1.2.76</li>
+ <li>升级druid到最新版本v1.2.6</li>
+ <li>修复四级菜单无法显示问题</li>
+ <li>修复树表数据显示不全&加载慢问题</li>
+ <li>修复关闭confirm提示框控制台报错问题</li>
+ <li>上传媒体类型添加视频格式</li>
+ <li>增加feign客户端IP头部信息</li>
+ <li>修复两处存在SQL注入漏洞问题</li>
+ <li>优化图片工具类读取文件,防止异常</li>
+ <li>修复导出角色数据范围翻译缺少仅本人</li>
+ <li>修复表单构建选择下拉选择控制台报错问题</li>
+ <li>修复请求形参未传值记录日志异常问题</li>
+ <li>调整sql默认为当前时间</li>
+ <li>修改ip字段长度防止ipv6地址长度不够</li>
+ <li>删除操作日志记录信息</li>
+ <li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
+ <li>用户&角色单条删除时使其逻辑删除</li>
+ <li>优化树表代码生成模板</li>
+ <li>修正通知公告日志记录类型</li>
+ <li>修正后端导入表权限标识</li>
+ <li>过滤BindingResult对象,防止异常</li>
+ <li>Redis设置HashKey序列化</li>
+ <li>优化Excel导入增加空行判断</li>
+ <li>树级结构更新子节点使用replaceFirst</li>
+ <li>富文本工具栏配置视频</li>
+ <li>修正模板字符编码</li>
+ <li>优化通用下载完成后删除节点</li>
+ <li>角色非自定义权限范围清空选择值</li>
+ <li>修改主题后mini类型按钮无效问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v2.5.0 - 2021-02-02">
+ <ol>
+ <li>增加分布式事务seata支持</li>
+ <li>代码生成模板支持主子表</li>
+ <li>表格右侧工具栏组件支持显隐列</li>
+ <li>图片组件添加预览&移除功能</li>
+ <li>Excel注解支持Image图片导出</li>
+ <li>操作按钮组调整为朴素按钮样式</li>
+ <li>代码生成支持文件上传组件</li>
+ <li>代码生成日期控件区分范围</li>
+ <li>代码生成数据库文本类型生成表单文本域</li>
+ <li>用户手机邮箱&菜单组件修改允许空字符串</li>
+ <li>修复header获取username中文情况下乱码</li>
+ <li>修复角色管理-编辑角色-功能权限显示异常</li>
+ <li>修正操作日志删除接口路径</li>
+ <li>修复IE11浏览器报错问题</li>
+ <li>修复sentinel流量告警前端不响应</li>
+ <li>修正侧边栏静态路由丢失问题</li>
+ <li>修复导入数据为负浮点数时丢失精度问题</li>
+ <li>修复Get请求参数特殊值无法正确的传参</li>
+ <li>更换过期的共享配置属性</li>
+ <li>添加启动执行脚本</li>
+ <li>升级element-ui到最新版本2.15.0</li>
+ <li>升级spring-boot到最新版本2.3.7</li>
+ <li>升级spring-cloud到Hoxton.SR9</li>
+ <li>升级spring-boot-alibaba到最新版2.2.5</li>
+ <li>升级spring-boot-admin到最新版2.3.1</li>
+ <li>升级druid到最新版本v1.2.4</li>
+ <li>升级fastjson到最新版1.2.75</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v2.4.0 - 2020-12-22">
+ <ol>
+ <li>增加分布式文件Minio支持</li>
+ <li>支持多数据源切换</li>
+ <li>修复多级菜单之间切换无法缓存的问题</li>
+ <li>三级菜单自动配置组件</li>
+ <li>支持主题风格配置</li>
+ <li>服务之间feign调用传递用户信息</li>
+ <li>删除用户和角色解绑关联</li>
+ <li>去除用户手机邮箱部门必填验证</li>
+ <li>代码生成预览支持高亮显示</li>
+ <li>获取请求token方法移至权限工具类</li>
+ <li>代码生成预览提供滚动机制</li>
+ <li>权限工具类增加管理员判断</li>
+ <li>日志记录增加过滤多文件场景</li>
+ <li>修改用户头像预览宽高</li>
+ <li>Excel支持注解align对齐方式</li>
+ <li>项目添加robots.txt 防止系统被搜索引擎收录</li>
+ <li>移除path-to-regexp正则匹配插件</li>
+ <li>修改Set可能导致嵌套的问题</li>
+ <li>调整代码生成页列宽</li>
+ <li>回显数据字典防止空值报错</li>
+ <li>支持get请求映射params参数</li>
+ <li>登录后push添加catch防止出现检查错误</li>
+ <li>防止安全扫描YUI出现的风险提示</li>
+ <li>代码生成删除多余的数字float类型</li>
+ <li>Excel支持导入Boolean型数据</li>
+ <li>修正转换字符串的目标字符集属性</li>
+ <li>删除多余的依赖</li>
+ <li>修改node-sass为dart-sass</li>
+ <li>升级poi到最新版本4.1.2</li>
+ <li>升级axios到最新版本0.21.0</li>
+ <li>升级element-ui到最新版本2.14.1</li>
+ <li>升级vue到最新版本2.6.12</li>
+ <li>升级vuex到最新版本3.6.0</li>
+ <li>升级vue-cli到版本4.5.9</li>
+ <li>升级vue-router到最新版本3.4.9</li>
+ <li>升级vue-cli到最新版本4.4.6</li>
+ <li>升级vue-cropper到最新版本0.5.5</li>
+ <li>升级clipboard到最新版本2.0.6</li>
+ <li>升级core-js到最新版本3.8.1</li>
+ <li>升级echarts到最新版本4.9.0</li>
+ <li>升级file-saver到最新版本2.0.4</li>
+ <li>升级fuse.js到最新版本6.4.3</li>
+ <li>升级js-beautify到最新版本1.13.0</li>
+ <li>升级js-cookie到最新版本2.2.1</li>
+ <li>升级path-to-regexp到最新版本6.2.0</li>
+ <li>升级quill到最新版本1.3.7</li>
+ <li>升级screenfull到最新版本5.0.2</li>
+ <li>升级sortablejs到最新版本1.10.2</li>
+ <li>升级vuedraggable到最新版本2.24.3</li>
+ <li>升级chalk到最新版本4.1.0</li>
+ <li>升级eslint到最新版本7.15.0</li>
+ <li>升级eslint-plugin-vue到最新版本7.2.0</li>
+ <li>升级lint-staged到最新版本10.5.3</li>
+ <li>升级runjs到最新版本4.4.2</li>
+ <li>升级sass-loader到最新版本10.1.0</li>
+ <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
+ <li>升级svg-sprite-loader到最新版本5.1.1</li>
+ <li>升级vue-template-compiler到最新版本2.6.12</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v2.3.0 - 2020-11-20">
+ <ol>
+ <li>新增文件服务应用(支持本地、FastDFS)</li>
+ <li>优化头像样式,鼠标移入悬停遮罩</li>
+ <li>AjaxResult重写put方法,以方便链式调用</li>
+ <li>代码生成支持上传控件</li>
+ <li>新增图片上传组件</li>
+ <li>支持用户头像更新</li>
+ <li>调整默认首页</li>
+ <li>角色权限验证hasRole匹配改为equals</li>
+ <li>修正数组权限为空判断</li>
+ <li>修正注释选中节点和半选节点获取</li>
+ <li>升级pagehelper到最新版1.3.0</li>
+ <li>升级fastjson到最新版1.2.74</li>
+ <li>修正定时任务执行一次权限标识</li>
+ <li>修复页签关闭所有固定标签路由不刷新问题</li>
+ <li>表单构建布局型组件新增按钮</li>
+ <li>调整日志路径到模块目录</li>
+ <li>修正菜单提示信息错误</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v2.2.0 - 2020-10-10">
+ <ol>
+ <li>移除 OAuth2 改为 Redis</li>
+ <li>升级SpringCloud到最新版本Hoxton.SR8</li>
+ <li>升级SpringCloud Alibaba到最新版本2.2.3</li>
+ <li>升级SpringBoot Admin到最新版本2.3.0</li>
+ <li>升级Fastjson到最新版1.2.73</li>
+ <li>新增在线用户会话管理</li>
+ <li>修改用户个人资料/密码同步缓存信息</li>
+ <li>修复前端通用导出方法参数传值请求方式问题</li>
+ <li>菜单新增是否缓存keep-alive</li>
+ <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
+ <li>Job与Gen模块增加Redis默认配置</li>
+ <li>新增表格右侧工具栏组件right-toolbar</li>
+ <li>代码生成支持同步数据库</li>
+ <li>代码生成支持富文本控件</li>
+ <li>代码生成树模板去掉多余双引号</li>
+ <li>代码生成添加select必填选项</li>
+ <li>代码生成页面时不忽略remark属性</li>
+ <li>修复代码生成下载路径错误</li>
+ <li>左侧菜单文字过长显示省略号</li>
+ <li>表格操作列间距调整</li>
+ <li>Excel注解支持自动统计数据总和</li>
+ <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
+ <li>导入Excel整形值校验优化</li>
+ <li>导出Excel类型NUMERIC支持精度浮点类型</li>
+ <li>导出Excel调整targetAttr获取值方法,防止get方法不规范</li>
+ <li>Token续期调整为后端刷新</li>
+ <li>Token设置默认有效期时长12小时</li>
+ <li>网关白名单放入nacos配置&支持模糊匹配</li>
+ <li>修复富文本工具栏样式不对齐问题</li>
+ <li>Editor组件优化,支持自定义高度&图片冲突问题</li>
+ <li>修复富文本空格和缩进保存后不生效问题&删除重复的placeholder</li>
+ <li>限制系统内置参数不允许删除</li>
+ <li>修正调用目标字符串最大长度</li>
+ <li>修改自定义权限实现</li>
+ <li>优化递归菜单&部门子节点</li>
+ <li>修改sass为node-sass,避免el-icon图标乱码</li>
+ <li>修复根节点为子部门时,树状结构显示问题</li>
+ <li>全局异常状态汉化拦截处理</li>
+ <li>唯一限制条件只返回单条数据</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+
+ <el-collapse-item title="v2.1.0 - 2020-08-02">
+ <ol>
+ <li>表格工具栏右侧添加刷新&显隐查询栏</li>
+ <li>OAuth自动刷新续签Token</li>
+ <li>网关支持黑名单配置</li>
+ <li>权限配置自动注册</li>
+ <li>Feign配置自动注册</li>
+ <li>代码生成支持选择上级菜单</li>
+ <li>代码生成支持复选框</li>
+ <li>代码生成支持自定义路径</li>
+ <li>验证码类型支持(数组计算、字符验证)</li>
+ <li>Excel支持sort导出排序</li>
+ <li>Excel支持分割字符串组内容</li>
+ <li>excel 导入数字不需要格式化 ,导入允许列和属性个数不一致</li>
+ <li>新增菜单默认主类目</li>
+ <li>升级vue-cli版本到4.4.4</li>
+ <li>修改 node-sass 为 dart-sass</li>
+ <li>升级element-ui版本到2.13.2</li>
+ <li>删除babel,提高编译速度</li>
+ <li>修复验证码异常时network面板的中文会出现乱码问题</li>
+ <li>修复 utils/index.js 中不包含 parseTime 函数的 bug</li>
+ <li>优化selectDictLabel方法,数组迭代器换为some</li>
+ <li>修复客户端模式认证会出现错误</li>
+ <li>检查字符支持小数点&降级改成异常提醒</li>
+ <li>定时任务添加cron表达式验证</li>
+ <li>代码生成查询条件修正</li>
+ <li>修正角色管理导出权限权限字符</li>
+ <li>修正防止切换权限用户后登录出现404</li>
+ <li>终端设置安全码加密&更新缓存</li>
+ <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
+ <li>修复布局为small者mini用户表单显示错位问题</li>
+ <li>修复代码生成点击多次表修改数据不变化的问题</li>
+ <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
+ <li>修复角色权限修改时已有权限未自动勾选异常</li>
+ <li>创建用户不允许选择系统管理员角色</li>
+ <li>添加全局异常处理(网关异常&业务异常)</li>
+ <li>修复终端查询Enter键搜索时是刷新页面而不是查询列表</li>
+ <li>删除job重复表单参数</li>
+ <li>代码生成浮点型改用BigDecimal</li>
+ <li>表单类型为Integer/Long设置整形默认值</li>
+ <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
+ <li>RedisCache中所有方法参数添加final,并优化list取出效率,添加其它常用redis方法</li>
+ <li>修正定时任务日志权限字符</li>
+ <li>添加Jackson时区配置</li>
+ <li>代码生成相关问题修复</li>
+ <li>自定义oauth2返回异常信息</li>
+ <li>升级nacos到最新版1.3.0 全新内核构建</li>
+ <li>修正【代码生成】功能无法下载的问题</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+
+ <el-collapse-item title="v2.0.0 - 2019-12-02">
+ <ol>
+ <li>新增代码生成</li>
+ <li>新增@RepeatSubmit注解,防止重复提交</li>
+ <li>新增菜单主目录添加/删除操作</li>
+ <li>日志记录过滤特殊对象,防止转换异常</li>
+ <li>修改代码生成路由脚本错误</li>
+ <li>用户上传头像实时同步缓存,无需重新登录</li>
+ <li>调整切换页签后不重新加载数据</li>
+ <li>添加jsencrypt实现参数的前端加密</li>
+ <li>系统退出删除用户缓存记录</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v2.0.0 - 2020-06-10">
+ <ol>
+ <li>使用Sentinel代替Hystrix</li>
+ <li>菜单新增终端管理配置</li>
+ <li>菜单新增Nacos&Sentinel控制台</li>
+ <li>代码生成适配Cloud</li>
+ <li>记录登录退出日志信息</li>
+ <li>网关验证码过滤器添加放行校验</li>
+ <li>个性化的定制自动加载类</li>
+ <li>定时任务调整label-width,防止部署出现错位</li>
+ <li>调整表头固定列默认样式</li>
+ <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
+ <li>代码生成字典Integer/Long使用parseInt</li>
+ <li>修复退出登录重定向到登录页,登录后参数丢失。</li>
+ <li>修正岗位导出权限注解</li>
+ <li>修复首页搜索菜单外链无法点击跳转问题</li>
+ <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
+ <li>用户管理部门分支节点不可检查&显示计数</li>
+ <li>数据范围过滤属性调整</li>
+ <li>字典管理添加缓存读取</li>
+ <li>参数管理支持缓存操作</li>
+ <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
+ <li>dev启动默认打开浏览器</li>
+ <li>使用vue-cli默认source-map</li>
+ <li>slidebar eslint报错优化</li>
+ <li>当tags-view滚动关闭右键菜单</li>
+ <li>支持一级菜单(和主页同级)在main区域显示</li>
+ <li>限制外链地址必须以http(s)😕/开头</li>
+ <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
+ <li>修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序</li>
+ <li>权限部分代码调整</li>
+ <li>其他细节优化</li>
+ </ol>
+ </el-collapse-item>
+ <el-collapse-item title="v1.0.0 - 2020-05-20">
+ <ol>
+ <li>若依微服务系统正式发布</li>
+ </ol>
+ </el-collapse-item>
+ </el-collapse>
+ </el-card>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="12" :lg="8">
+ <el-card class="update-log">
+ <div slot="header" class="clearfix">
+ <span>捐赠支持</span>
+ </div>
+ <div class="body">
+ <img
+ src="@/assets/images/pay.png"
+ alt="donate"
+ width="100%"
+ />
+ <span style="display: inline-block; height: 30px; line-height: 30px"
+ >你可以请作者喝杯咖啡表示鼓励</span
+ >
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script>
+export default {
+ name: "Index",
+ data() {
+ return {
+ // 版本号
+ version: "3.6.8"
+ }
+ },
+ methods: {
+ goTarget(href) {
+ window.open(href, "_blank")
+ }
+ }
+}
+</script>
+
+<style scoped lang="scss">
+.home {
+ blockquote {
+ padding: 10px 20px;
+ margin: 0 0 20px;
+ font-size: 17.5px;
+ border-left: 5px solid #eee;
+ }
+ hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #eee;
+ }
+ .col-item {
+ margin-bottom: 20px;
+ }
+
+ ul {
+ padding: 0;
+ margin: 0;
+ }
+
+ font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ color: #676a6c;
+ overflow-x: hidden;
+
+ ul {
+ list-style-type: none;
+ }
+
+ h4 {
+ margin-top: 0px;
+ }
+
+ h2 {
+ margin-top: 10px;
+ font-size: 26px;
+ font-weight: 100;
+ }
+
+ p {
+ margin-top: 10px;
+
+ b {
+ font-weight: 700;
+ }
+ }
+
+ .update-log {
+ ol {
+ display: block;
+ list-style-type: decimal;
+ margin-block-start: 1em;
+ margin-block-end: 1em;
+ margin-inline-start: 0;
+ margin-inline-end: 0;
+ padding-inline-start: 40px;
+ }
+ }
+}
+</style>
+
diff --git a/sgd-ui/src/views/index_v1.vue b/sgd-ui/src/views/index_v1.vue
new file mode 100644
index 0000000..d2d2ec6
--- /dev/null
+++ b/sgd-ui/src/views/index_v1.vue
@@ -0,0 +1,98 @@
+<template>
+ <div class="dashboard-editor-container">
+
+ <panel-group @handleSetLineChartData="handleSetLineChartData" />
+
+ <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
+ <line-chart :chart-data="lineChartData" />
+ </el-row>
+
+ <el-row :gutter="32">
+ <el-col :xs="24" :sm="24" :lg="8">
+ <div class="chart-wrapper">
+ <raddar-chart />
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="24" :lg="8">
+ <div class="chart-wrapper">
+ <pie-chart />
+ </div>
+ </el-col>
+ <el-col :xs="24" :sm="24" :lg="8">
+ <div class="chart-wrapper">
+ <bar-chart />
+ </div>
+ </el-col>
+ </el-row>
+
+
+ </div>
+</template>
+
+<script>
+import PanelGroup from './dashboard/PanelGroup'
+import LineChart from './dashboard/LineChart'
+import RaddarChart from './dashboard/RaddarChart'
+import PieChart from './dashboard/PieChart'
+import BarChart from './dashboard/BarChart'
+
+const lineChartData = {
+ newVisitis: {
+ expectedData: [100, 120, 161, 134, 105, 160, 165],
+ actualData: [120, 82, 91, 154, 162, 140, 145]
+ },
+ messages: {
+ expectedData: [200, 192, 120, 144, 160, 130, 140],
+ actualData: [180, 160, 151, 106, 145, 150, 130]
+ },
+ purchases: {
+ expectedData: [80, 100, 121, 104, 105, 90, 100],
+ actualData: [120, 90, 100, 138, 142, 130, 130]
+ },
+ shoppings: {
+ expectedData: [130, 140, 141, 142, 145, 150, 160],
+ actualData: [120, 82, 91, 154, 162, 140, 130]
+ }
+}
+
+export default {
+ name: 'Index',
+ components: {
+ PanelGroup,
+ LineChart,
+ RaddarChart,
+ PieChart,
+ BarChart
+ },
+ data() {
+ return {
+ lineChartData: lineChartData.newVisitis
+ }
+ },
+ methods: {
+ handleSetLineChartData(type) {
+ this.lineChartData = lineChartData[type]
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.dashboard-editor-container {
+ padding: 32px;
+ background-color: rgb(240, 242, 245);
+ position: relative;
+
+ .chart-wrapper {
+ background: #fff;
+ padding: 16px 16px 0;
+ margin-bottom: 32px;
+ }
+}
+
+@media (max-width:1024px) {
+ .chart-wrapper {
+ padding: 8px;
+ }
+}
+</style>
diff --git a/ruoyi-ui/src/views/lock.vue b/sgd-ui/src/views/lock.vue
similarity index 100%
rename from ruoyi-ui/src/views/lock.vue
rename to sgd-ui/src/views/lock.vue
diff --git a/sgd-ui/src/views/login.vue b/sgd-ui/src/views/login.vue
new file mode 100644
index 0000000..dde986d
--- /dev/null
+++ b/sgd-ui/src/views/login.vue
@@ -0,0 +1,223 @@
+<template>
+ <div class="login">
+ <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
+ <h3 class="title">{{title}}</h3>
+ <el-form-item prop="username">
+ <el-input
+ v-model="loginForm.username"
+ type="text"
+ auto-complete="off"
+ placeholder="账号"
+ >
+ <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+ </el-input>
+ </el-form-item>
+ <el-form-item prop="password">
+ <el-input
+ v-model="loginForm.password"
+ type="password"
+ auto-complete="off"
+ placeholder="密码"
+ @keyup.enter.native="handleLogin"
+ >
+ <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+ </el-input>
+ </el-form-item>
+ <el-form-item prop="code" v-if="captchaEnabled">
+ <el-input
+ v-model="loginForm.code"
+ auto-complete="off"
+ placeholder="验证码"
+ style="width: 63%"
+ @keyup.enter.native="handleLogin"
+ >
+ <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+ </el-input>
+ <div class="login-code">
+ <img :src="codeUrl" @click="getCode" class="login-code-img"/>
+ </div>
+ </el-form-item>
+ <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
+ <el-form-item style="width:100%;">
+ <el-button
+ :loading="loading"
+ size="medium"
+ type="primary"
+ style="width:100%;"
+ @click.native.prevent="handleLogin"
+ >
+ <span v-if="!loading">登 录</span>
+ <span v-else>登 录 中...</span>
+ </el-button>
+ <div style="float: right;" v-if="register">
+ <router-link class="link-type" :to="'/register'">立即注册</router-link>
+ </div>
+ </el-form-item>
+ </el-form>
+ <!-- 底部 -->
+ <div class="el-login-footer">
+ <span>{{ footerContent }}</span>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getCodeImg } from "@/api/login"
+import Cookies from "js-cookie"
+import { encrypt, decrypt } from '@/utils/jsencrypt'
+import defaultSettings from '@/settings'
+
+export default {
+ name: "Login",
+ data() {
+ return {
+ title: process.env.VUE_APP_TITLE,
+ footerContent: defaultSettings.footerContent,
+ codeUrl: "",
+ loginForm: {
+ username: "admin",
+ password: "admin123",
+ rememberMe: false,
+ code: "",
+ uuid: ""
+ },
+ loginRules: {
+ username: [
+ { required: true, trigger: "blur", message: "请输入您的账号" }
+ ],
+ password: [
+ { required: true, trigger: "blur", message: "请输入您的密码" }
+ ],
+ code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+ },
+ loading: false,
+ // 验证码开关
+ captchaEnabled: true,
+ // 注册开关
+ register: false,
+ redirect: undefined
+ }
+ },
+ watch: {
+ $route: {
+ handler: function(route) {
+ this.redirect = route.query && route.query.redirect
+ },
+ immediate: true
+ }
+ },
+ created() {
+ this.getCode()
+ this.getCookie()
+ },
+ methods: {
+ getCode() {
+ getCodeImg().then(res => {
+ this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
+ if (this.captchaEnabled) {
+ this.codeUrl = "data:image/gif;base64," + res.img
+ this.loginForm.uuid = res.uuid
+ }
+ })
+ },
+ getCookie() {
+ const username = Cookies.get("username")
+ const password = Cookies.get("password")
+ const rememberMe = Cookies.get('rememberMe')
+ this.loginForm = {
+ username: username === undefined ? this.loginForm.username : username,
+ password: password === undefined ? this.loginForm.password : decrypt(password),
+ rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
+ }
+ },
+ handleLogin() {
+ this.$refs.loginForm.validate(valid => {
+ if (valid) {
+ this.loading = true
+ if (this.loginForm.rememberMe) {
+ Cookies.set("username", this.loginForm.username, { expires: 30 })
+ Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
+ Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
+ } else {
+ Cookies.remove("username")
+ Cookies.remove("password")
+ Cookies.remove('rememberMe')
+ }
+ this.$store.dispatch("Login", this.loginForm).then(() => {
+ this.$router.push({ path: this.redirect || "/" }).catch(()=>{})
+ }).catch(() => {
+ this.loading = false
+ if (this.captchaEnabled) {
+ this.getCode()
+ }
+ })
+ }
+ })
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.login {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ background-image: url("../assets/images/login-background.jpg");
+ background-size: cover;
+}
+.title {
+ margin: 0px auto 30px auto;
+ text-align: center;
+ color: #707070;
+}
+
+.login-form {
+ border-radius: 6px;
+ background: #ffffff;
+ width: 400px;
+ padding: 25px 25px 5px 25px;
+ z-index: 1;
+ .el-input {
+ height: 38px;
+ input {
+ height: 38px;
+ }
+ }
+ .input-icon {
+ height: 39px;
+ width: 14px;
+ margin-left: 2px;
+ }
+}
+.login-tip {
+ font-size: 13px;
+ text-align: center;
+ color: #bfbfbf;
+}
+.login-code {
+ width: 33%;
+ height: 38px;
+ float: right;
+ img {
+ cursor: pointer;
+ vertical-align: middle;
+ }
+}
+.el-login-footer {
+ height: 40px;
+ line-height: 40px;
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ text-align: center;
+ color: #fff;
+ font-family: Arial;
+ font-size: 12px;
+ letter-spacing: 1px;
+}
+.login-code-img {
+ height: 38px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/monitor/job/detail.vue b/sgd-ui/src/views/monitor/job/detail.vue
similarity index 100%
rename from ruoyi-ui/src/views/monitor/job/detail.vue
rename to sgd-ui/src/views/monitor/job/detail.vue
diff --git a/sgd-ui/src/views/monitor/job/index.vue b/sgd-ui/src/views/monitor/job/index.vue
new file mode 100644
index 0000000..c7e264f
--- /dev/null
+++ b/sgd-ui/src/views/monitor/job/index.vue
@@ -0,0 +1,471 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="任务名称" prop="jobName">
+ <el-input
+ v-model="queryParams.jobName"
+ placeholder="请输入任务名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="任务组名" prop="jobGroup">
+ <el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_job_group"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="任务状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_job_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['monitor:job:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['monitor:job:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['monitor:job:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['monitor:job:export']"
+ >导出</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="info"
+ plain
+ icon="el-icon-s-operation"
+ size="mini"
+ @click="handleJobLog"
+ v-hasPermi="['monitor:job:query']"
+ >日志</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="任务编号" width="100" align="center" prop="jobId" />
+ <el-table-column label="任务名称" align="center" :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <a class="link-type" style="cursor:pointer" @click="handleView(scope.row)">{{ scope.row.jobName }}</a>
+ </template>
+ </el-table-column>
+ <el-table-column label="任务组名" align="center" prop="jobGroup">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+ <el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
+ <el-table-column label="状态" align="center">
+ <template slot-scope="scope">
+ <el-switch
+ v-model="scope.row.status"
+ active-value="0"
+ inactive-value="1"
+ @change="handleStatusChange(scope.row)"
+ ></el-switch>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['monitor:job:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['monitor:job:remove']"
+ >删除</el-button>
+ <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['monitor:job:changeStatus', 'monitor:job:query']">
+ <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item command="handleRun" icon="el-icon-caret-right"
+ v-hasPermi="['monitor:job:changeStatus']">执行一次</el-dropdown-item>
+ <el-dropdown-item command="handleJobLog" icon="el-icon-s-operation"
+ v-hasPermi="['monitor:job:query']">调度日志</el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改定时任务对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="任务名称" prop="jobName">
+ <el-input v-model="form.jobName" placeholder="请输入任务名称" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="任务分组" prop="jobGroup">
+ <el-select v-model="form.jobGroup" placeholder="请选择任务分组">
+ <el-option
+ v-for="dict in dict.type.sys_job_group"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item prop="invokeTarget">
+ <span slot="label">
+ 调用方法
+ <el-tooltip placement="top">
+ <div slot="content">
+ Bean调用示例:ryTask.ryParams('ry')
+ <br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
+ <br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
+ </div>
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="cron表达式" prop="cronExpression">
+ <el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
+ <template slot="append">
+ <el-button type="primary" @click="handleShowCron">
+ 生成表达式
+ <i class="el-icon-time el-icon--right"></i>
+ </el-button>
+ </template>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24" v-if="form.jobId !== undefined">
+ <el-form-item label="状态">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_job_status"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="执行策略" prop="misfirePolicy">
+ <el-radio-group v-model="form.misfirePolicy" size="small">
+ <el-radio-button label="1">立即执行</el-radio-button>
+ <el-radio-button label="2">执行一次</el-radio-button>
+ <el-radio-button label="3">放弃执行</el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="是否并发" prop="concurrent">
+ <el-radio-group v-model="form.concurrent" size="small">
+ <el-radio-button label="0">允许</el-radio-button>
+ <el-radio-button label="1">禁止</el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+
+ <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
+ <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
+ </el-dialog>
+
+ <!-- 任务日志详细 -->
+ <job-detail :visible.sync="openView" :row="form" type="job" />
+ </div>
+</template>
+
+<script>
+import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"
+import JobDetail from './detail'
+import Crontab from '@/components/Crontab'
+
+export default {
+ components: { Crontab, JobDetail },
+ name: "Job",
+ dicts: ['sys_job_group', 'sys_job_status'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 定时任务表格数据
+ jobList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 是否显示详细弹出层
+ openView: false,
+ // 是否显示Cron表达式弹出层
+ openCron: false,
+ // 传入的表达式
+ expression: "",
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ jobName: undefined,
+ jobGroup: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ jobName: [
+ { required: true, message: "任务名称不能为空", trigger: "blur" }
+ ],
+ invokeTarget: [
+ { required: true, message: "调用目标字符串不能为空", trigger: "blur" }
+ ],
+ cronExpression: [
+ { required: true, message: "cron执行表达式不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询定时任务列表 */
+ getList() {
+ this.loading = true
+ listJob(this.queryParams).then(response => {
+ this.jobList = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ // 任务组名字典翻译
+ jobGroupFormat(row, column) {
+ return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup)
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ jobId: undefined,
+ jobName: undefined,
+ jobGroup: undefined,
+ invokeTarget: undefined,
+ cronExpression: undefined,
+ misfirePolicy: 1,
+ concurrent: 1,
+ status: "0"
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.jobId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ // 更多操作触发
+ handleCommand(command, row) {
+ switch (command) {
+ case "handleRun":
+ this.handleRun(row)
+ break
+ case "handleView":
+ this.handleView(row)
+ break
+ case "handleJobLog":
+ this.handleJobLog(row)
+ break
+ default:
+ break
+ }
+ },
+ // 任务状态修改
+ handleStatusChange(row) {
+ let text = row.status === "0" ? "启用" : "停用"
+ this.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function() {
+ return changeJobStatus(row.jobId, row.status)
+ }).then(() => {
+ this.$modal.msgSuccess(text + "成功")
+ }).catch(function() {
+ row.status = row.status === "0" ? "1" : "0"
+ })
+ },
+ /* 立即执行一次 */
+ handleRun(row) {
+ this.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function() {
+ return runJob(row.jobId, row.jobGroup)
+ }).then(() => {
+ this.$modal.msgSuccess("执行成功")
+ }).catch(() => {})
+ },
+ /** 任务详细信息 */
+ handleView(row) {
+ getJob(row.jobId).then(response => {
+ this.form = response.data
+ this.openView = true
+ })
+ },
+ /** cron表达式按钮操作 */
+ handleShowCron() {
+ this.expression = this.form.cronExpression
+ this.openCron = true
+ },
+ /** 确定后回传值 */
+ crontabFill(value) {
+ this.form.cronExpression = value
+ },
+ /** 任务日志列表查询 */
+ handleJobLog(row) {
+ const jobId = row.jobId || 0
+ this.$router.push('/monitor/job-log/index/' + jobId)
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加任务"
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const jobId = row.jobId || this.ids
+ getJob(jobId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改任务"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.jobId != undefined) {
+ updateJob(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addJob(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const jobIds = row.jobId || this.ids
+ this.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function() {
+ return delJob(jobIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('schedule/job/export', {
+ ...this.queryParams
+ }, `job_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/monitor/job/log.vue b/sgd-ui/src/views/monitor/job/log.vue
new file mode 100644
index 0000000..693260f
--- /dev/null
+++ b/sgd-ui/src/views/monitor/job/log.vue
@@ -0,0 +1,265 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="任务名称" prop="jobName">
+ <el-input
+ v-model="queryParams.jobName"
+ placeholder="请输入任务名称"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="任务组名" prop="jobGroup">
+ <el-select
+ v-model="queryParams.jobGroup"
+ placeholder="请选择任务组名"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_job_group"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="执行状态" prop="status">
+ <el-select
+ v-model="queryParams.status"
+ placeholder="请选择执行状态"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_common_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="执行时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['monitor:job:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ @click="handleClean"
+ v-hasPermi="['monitor:job:remove']"
+ >清空</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['monitor:job:export']"
+ >导出</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-close"
+ size="mini"
+ @click="handleClose"
+ >关闭</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
+ <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
+ <el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+ <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
+ <el-table-column label="执行状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="执行时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleView(scope.row)"
+ v-hasPermi="['monitor:job:query']"
+ >详细</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <job-log-detail :visible.sync="open" :row="form" type="log" />
+ </div>
+</template>
+
+<script>
+import { getJob} from "@/api/monitor/job"
+import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog"
+import JobLogDetail from './detail'
+
+export default {
+ name: "JobLog",
+ components: { JobLogDetail },
+ dicts: ['sys_common_status', 'sys_job_group'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 调度日志表格数据
+ jobLogList: [],
+ // 是否显示弹出层
+ open: false,
+ // 日期范围
+ dateRange: [],
+ // 表单参数
+ form: {},
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ jobName: undefined,
+ jobGroup: undefined,
+ status: undefined
+ }
+ }
+ },
+ created() {
+ const jobId = this.$route.params && this.$route.params.jobId
+ if (jobId !== undefined && jobId != 0) {
+ getJob(jobId).then(response => {
+ this.queryParams.jobName = response.data.jobName
+ this.queryParams.jobGroup = response.data.jobGroup
+ this.getList()
+ })
+ } else {
+ this.getList()
+ }
+ },
+ methods: {
+ /** 查询调度日志列表 */
+ getList() {
+ this.loading = true
+ listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.jobLogList = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ // 返回按钮
+ handleClose() {
+ const obj = { path: "/monitor/job" }
+ this.$tab.closeOpenPage(obj)
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.jobLogId)
+ this.multiple = !selection.length
+ },
+ /** 详细按钮操作 */
+ handleView(row) {
+ this.open = true
+ this.form = row
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const jobLogIds = this.ids
+ this.$modal.confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?').then(function() {
+ return delJobLog(jobLogIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 清空按钮操作 */
+ handleClean() {
+ this.$modal.confirm('是否确认清空所有调度日志数据项?').then(function() {
+ return cleanJobLog()
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("清空成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('schedule/job/log/export', {
+ ...this.queryParams
+ }, `log_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/monitor/online/index.vue b/sgd-ui/src/views/monitor/online/index.vue
new file mode 100644
index 0000000..ca7cc8d
--- /dev/null
+++ b/sgd-ui/src/views/monitor/online/index.vue
@@ -0,0 +1,118 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
+ <el-form-item label="登录地址" prop="ipaddr">
+ <el-input
+ v-model="queryParams.ipaddr"
+ placeholder="请输入登录地址"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="用户名称" prop="userName">
+ <el-input
+ v-model="queryParams.userName"
+ placeholder="请输入用户名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+
+ </el-form>
+ <el-table
+ v-loading="loading"
+ :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
+ style="width: 100%;"
+ >
+ <el-table-column label="序号" type="index" align="center">
+ <template slot-scope="scope">
+ <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
+ <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
+ <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
+ <el-table-column label="登录时间" align="center" prop="loginTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.loginTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleForceLogout(scope.row)"
+ v-hasPermi="['monitor:online:forceLogout']"
+ >强退</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
+ </div>
+</template>
+
+<script>
+import { list, forceLogout } from "@/api/monitor/online";
+
+export default {
+ name: "Online",
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 总条数
+ total: 0,
+ // 表格数据
+ list: [],
+ pageNum: 1,
+ pageSize: 10,
+ // 查询参数
+ queryParams: {
+ ipaddr: undefined,
+ userName: undefined
+ }
+ };
+ },
+ created() {
+ this.getList();
+ },
+ methods: {
+ /** 查询登录日志列表 */
+ getList() {
+ this.loading = true;
+ list(this.queryParams).then(response => {
+ this.list = response.rows;
+ this.total = response.total;
+ this.loading = false;
+ });
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.pageNum = 1;
+ this.getList();
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm");
+ this.handleQuery();
+ },
+ /** 强退按钮操作 */
+ handleForceLogout(row) {
+ this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function() {
+ return forceLogout(row.tokenId);
+ }).then(() => {
+ this.getList();
+ this.$modal.msgSuccess("强退成功");
+ }).catch(() => {});
+ }
+ }
+};
+</script>
+
diff --git a/sgd-ui/src/views/redirect.vue b/sgd-ui/src/views/redirect.vue
new file mode 100644
index 0000000..db4c1d6
--- /dev/null
+++ b/sgd-ui/src/views/redirect.vue
@@ -0,0 +1,12 @@
+<script>
+export default {
+ created() {
+ const { params, query } = this.$route
+ const { path } = params
+ this.$router.replace({ path: '/' + path, query })
+ },
+ render: function(h) {
+ return h() // avoid warning message
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/register.vue b/sgd-ui/src/views/register.vue
new file mode 100644
index 0000000..82f96c5
--- /dev/null
+++ b/sgd-ui/src/views/register.vue
@@ -0,0 +1,214 @@
+<template>
+ <div class="register">
+ <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
+ <h3 class="title">{{title}}</h3>
+ <el-form-item prop="username">
+ <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
+ <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+ </el-input>
+ </el-form-item>
+ <el-form-item prop="password" :rules="registerPwdValidator">
+ <el-input
+ v-model="registerForm.password"
+ type="password"
+ auto-complete="off"
+ placeholder="密码"
+ @keyup.enter.native="handleRegister"
+ >
+ <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+ </el-input>
+ </el-form-item>
+ <el-form-item prop="confirmPassword">
+ <el-input
+ v-model="registerForm.confirmPassword"
+ type="password"
+ auto-complete="off"
+ placeholder="确认密码"
+ @keyup.enter.native="handleRegister"
+ >
+ <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+ </el-input>
+ </el-form-item>
+ <el-form-item prop="code" v-if="captchaEnabled">
+ <el-input
+ v-model="registerForm.code"
+ auto-complete="off"
+ placeholder="验证码"
+ style="width: 63%"
+ @keyup.enter.native="handleRegister"
+ >
+ <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+ </el-input>
+ <div class="register-code">
+ <img :src="codeUrl" @click="getCode" class="register-code-img"/>
+ </div>
+ </el-form-item>
+ <el-form-item style="width:100%;">
+ <el-button
+ :loading="loading"
+ size="medium"
+ type="primary"
+ style="width:100%;"
+ @click.native.prevent="handleRegister"
+ >
+ <span v-if="!loading">注 册</span>
+ <span v-else>注 册 中...</span>
+ </el-button>
+ <div style="float: right;">
+ <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
+ </div>
+ </el-form-item>
+ </el-form>
+ <!-- 底部 -->
+ <div class="el-register-footer">
+ <span>{{ footerContent }}</span>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getCodeImg, register } from "@/api/login"
+import passwordRule from "@/utils/passwordRule"
+import defaultSettings from '@/settings'
+
+export default {
+ mixins: [passwordRule],
+ data() {
+ return {
+ title: process.env.VUE_APP_TITLE,
+ footerContent: defaultSettings.footerContent,
+ codeUrl: "",
+ registerForm: {
+ username: "",
+ password: "",
+ confirmPassword: "",
+ code: "",
+ uuid: ""
+ },
+ loading: false,
+ captchaEnabled: true
+ }
+ },
+ computed: {
+ registerRules() {
+ return {
+ username: [
+ { required: true, trigger: "blur", message: "请输入您的账号" },
+ { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
+ ],
+ confirmPassword: [
+ { required: true, message: "请再次输入您的密码", trigger: "blur" },
+ {
+ validator: (rule, value, callback) => {
+ if (this.registerForm.password !== value) {
+ callback(new Error("两次输入的密码不一致"))
+ } else {
+ callback()
+ }
+ }, trigger: "blur"
+ }
+ ],
+ code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+ }
+ }
+ },
+ created() {
+ this.getCode()
+ },
+ methods: {
+ getCode() {
+ getCodeImg().then(res => {
+ this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled
+ if (this.captchaEnabled) {
+ this.codeUrl = "data:image/gif;base64," + res.img
+ this.registerForm.uuid = res.uuid
+ }
+ })
+ },
+ handleRegister() {
+ this.$refs.registerForm.validate(valid => {
+ if (valid) {
+ this.loading = true
+ register(this.registerForm).then(() => {
+ const username = this.registerForm.username
+ this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
+ dangerouslyUseHTMLString: true,
+ type: 'success'
+ }).then(() => {
+ this.$router.push("/login")
+ }).catch(() => {})
+ }).catch(() => {
+ this.loading = false
+ if (this.captchaEnabled) {
+ this.getCode()
+ }
+ })
+ }
+ })
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.register {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ background-image: url("../assets/images/login-background.jpg");
+ background-size: cover;
+}
+.title {
+ margin: 0px auto 30px auto;
+ text-align: center;
+ color: #707070;
+}
+
+.register-form {
+ border-radius: 6px;
+ background: #ffffff;
+ width: 400px;
+ padding: 25px 25px 5px 25px;
+ .el-input {
+ height: 38px;
+ input {
+ height: 38px;
+ }
+ }
+ .input-icon {
+ height: 39px;
+ width: 14px;
+ margin-left: 2px;
+ }
+}
+.register-tip {
+ font-size: 13px;
+ text-align: center;
+ color: #bfbfbf;
+}
+.register-code {
+ width: 33%;
+ height: 38px;
+ float: right;
+ img {
+ cursor: pointer;
+ vertical-align: middle;
+ }
+}
+.el-register-footer {
+ height: 40px;
+ line-height: 40px;
+ position: fixed;
+ bottom: 0;
+ width: 100%;
+ text-align: center;
+ color: #fff;
+ font-family: Arial;
+ font-size: 12px;
+ letter-spacing: 1px;
+}
+.register-code-img {
+ height: 38px;
+}
+</style>
diff --git a/sgd-ui/src/views/system/config/index.vue b/sgd-ui/src/views/system/config/index.vue
new file mode 100644
index 0000000..beb6c3a
--- /dev/null
+++ b/sgd-ui/src/views/system/config/index.vue
@@ -0,0 +1,343 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="参数名称" prop="configName">
+ <el-input
+ v-model="queryParams.configName"
+ placeholder="请输入参数名称"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="参数键名" prop="configKey">
+ <el-input
+ v-model="queryParams.configKey"
+ placeholder="请输入参数键名"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="系统内置" prop="configType">
+ <el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_yes_no"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="创建时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:config:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:config:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:config:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:config:export']"
+ >导出</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-refresh"
+ size="mini"
+ @click="handleRefreshCache"
+ v-hasPermi="['system:config:remove']"
+ >刷新缓存</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="参数主键" align="center" prop="configId" />
+ <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
+ <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
+ <el-table-column label="参数键值" align="center" prop="configValue" :show-overflow-tooltip="true" />
+ <el-table-column label="系统内置" align="center" prop="configType">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.configType"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:config:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:config:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改参数配置对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-form-item label="参数名称" prop="configName">
+ <el-input v-model="form.configName" placeholder="请输入参数名称" />
+ </el-form-item>
+ <el-form-item label="参数键名" prop="configKey">
+ <el-input v-model="form.configKey" placeholder="请输入参数键名" />
+ </el-form-item>
+ <el-form-item label="参数键值" prop="configValue">
+ <el-input v-model="form.configValue" type="textarea" placeholder="请输入参数键值" />
+ </el-form-item>
+ <el-form-item label="系统内置" prop="configType">
+ <el-radio-group v-model="form.configType">
+ <el-radio
+ v-for="dict in dict.type.sys_yes_no"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="备注" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config"
+
+export default {
+ name: "Config",
+ dicts: ['sys_yes_no'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 参数表格数据
+ configList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 日期范围
+ dateRange: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ configName: undefined,
+ configKey: undefined,
+ configType: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ configName: [
+ { required: true, message: "参数名称不能为空", trigger: "blur" }
+ ],
+ configKey: [
+ { required: true, message: "参数键名不能为空", trigger: "blur" }
+ ],
+ configValue: [
+ { required: true, message: "参数键值不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询参数列表 */
+ getList() {
+ this.loading = true
+ listConfig(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.configList = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ configId: undefined,
+ configName: undefined,
+ configKey: undefined,
+ configValue: undefined,
+ configType: "Y",
+ remark: undefined
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加参数"
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.configId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const configId = row.configId || this.ids
+ getConfig(configId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改参数"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.configId != undefined) {
+ updateConfig(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addConfig(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const configIds = row.configId || this.ids
+ this.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function() {
+ return delConfig(configIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/config/export', {
+ ...this.queryParams
+ }, `config_${new Date().getTime()}.xlsx`)
+ },
+ /** 刷新缓存按钮操作 */
+ handleRefreshCache() {
+ refreshCache().then(() => {
+ this.$modal.msgSuccess("刷新成功")
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/system/dept/index.vue b/sgd-ui/src/views/system/dept/index.vue
new file mode 100644
index 0000000..3d41ee3
--- /dev/null
+++ b/sgd-ui/src/views/system/dept/index.vue
@@ -0,0 +1,392 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+ <el-form-item label="部门名称" prop="deptName">
+ <el-input
+ v-model="queryParams.deptName"
+ placeholder="请输入部门名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:dept:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-check"
+ size="mini"
+ @click="handleSaveSort"
+ v-hasPermi="['system:dept:edit']"
+ >保存排序</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="info"
+ plain
+ icon="el-icon-sort"
+ size="mini"
+ @click="toggleExpandAll"
+ >展开/折叠</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table
+ v-if="refreshTable"
+ v-loading="loading"
+ :data="deptList"
+ row-key="deptId"
+ :default-expand-all="isExpandAll"
+ :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+ >
+ <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
+ <el-table-column prop="orderNum" label="排序" width="200">
+ <template slot-scope="scope">
+ <el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" size="mini" style="width: 88px" />
+ </template>
+ </el-table-column>
+ <el-table-column prop="status" label="状态" width="100">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" width="200">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:dept:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-plus"
+ @click="handleAdd(scope.row)"
+ v-hasPermi="['system:dept:add']"
+ >新增</el-button>
+ <el-button
+ v-if="scope.row.parentId != 0"
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:dept:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 添加或修改部门对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-row>
+ <el-col :span="24" v-if="form.parentId !== 0">
+ <el-form-item label="上级部门" prop="parentId">
+ <treeselect v-model="form.parentId" :options="deptOptions" :normalizer="normalizer" placeholder="选择上级部门" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="部门名称" prop="deptName">
+ <el-input v-model="form.deptName" placeholder="请输入部门名称" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="显示排序" prop="orderNum">
+ <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="负责人" prop="leader">
+ <el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="联系电话" prop="phone">
+ <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="邮箱" prop="email">
+ <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="部门状态">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listDept, getDept, delDept, addDept, updateDept, updateDeptSort, listDeptExcludeChild } from "@/api/system/dept"
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+
+export default {
+ name: "Dept",
+ dicts: ['sys_normal_disable'],
+ components: { Treeselect },
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 表格树数据
+ deptList: [],
+ // 部门树选项
+ deptOptions: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 是否展开,默认全部展开
+ isExpandAll: true,
+ // 重新渲染表格状态
+ refreshTable: true,
+ // 记录原始排序,用于对比变更
+ originalOrders: {},
+ // 查询参数
+ queryParams: {
+ deptName: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ parentId: [
+ { required: true, message: "上级部门不能为空", trigger: "blur" }
+ ],
+ deptName: [
+ { required: true, message: "部门名称不能为空", trigger: "blur" }
+ ],
+ orderNum: [
+ { required: true, message: "显示排序不能为空", trigger: "blur" }
+ ],
+ email: [
+ {
+ type: "email",
+ message: "请输入正确的邮箱地址",
+ trigger: ["blur", "change"]
+ }
+ ],
+ phone: [
+ {
+ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+ message: "请输入正确的手机号码",
+ trigger: "blur"
+ }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询部门列表 */
+ getList() {
+ this.loading = true
+ listDept(this.queryParams).then(response => {
+ this.deptList = this.handleTree(response.data, "deptId")
+ // 记录原始排序值
+ this.recordOriginalOrders(this.deptList)
+ this.loading = false
+ })
+ },
+ /** 转换部门数据结构 */
+ normalizer(node) {
+ if (node.children && !node.children.length) {
+ delete node.children
+ }
+ return {
+ id: node.deptId,
+ label: node.deptName,
+ children: node.children
+ }
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ deptId: undefined,
+ parentId: undefined,
+ deptName: undefined,
+ orderNum: undefined,
+ leader: undefined,
+ phone: undefined,
+ email: undefined,
+ status: "0"
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd(row) {
+ this.reset()
+ if (row != undefined) {
+ this.form.parentId = row.deptId
+ }
+ this.open = true
+ this.title = "添加部门"
+ listDept().then(response => {
+ this.deptOptions = this.handleTree(response.data, "deptId")
+ })
+ },
+ /** 展开/折叠操作 */
+ toggleExpandAll() {
+ this.refreshTable = false
+ this.isExpandAll = !this.isExpandAll
+ this.$nextTick(() => {
+ this.refreshTable = true
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ getDept(row.deptId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改部门"
+ listDeptExcludeChild(row.deptId).then(response => {
+ this.deptOptions = this.handleTree(response.data, "deptId")
+ if (this.deptOptions.length == 0) {
+ const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] }
+ this.deptOptions.push(noResultsOptions)
+ }
+ })
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.deptId != undefined) {
+ updateDept(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addDept(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 递归记录原始排序 */
+ recordOriginalOrders(list) {
+ list.forEach(item => {
+ this.originalOrders[item.deptId] = item.orderNum
+ if (item.children && item.children.length) {
+ this.recordOriginalOrders(item.children)
+ }
+ })
+ },
+ /** 保存排序 */
+ handleSaveSort() {
+ const changedDeptIds = []
+ const changedOrderNums = []
+ const collectChanged = (list) => {
+ list.forEach(item => {
+ if (String(this.originalOrders[item.deptId]) !== String(item.orderNum)) {
+ changedDeptIds.push(item.deptId)
+ changedOrderNums.push(item.orderNum)
+ }
+ if (item.children && item.children.length) {
+ collectChanged(item.children)
+ }
+ })
+ }
+ collectChanged(this.deptList)
+ if (changedDeptIds.length === 0) {
+ this.$modal.msgWarning("未检测到排序修改")
+ return
+ }
+ updateDeptSort({ deptIds: changedDeptIds.join(","), orderNums: changedOrderNums.join(",") }).then(() => {
+ this.$modal.msgSuccess("排序保存成功")
+ this.recordOriginalOrders(this.deptList)
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
+ return delDept(row.deptId)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/system/dict/data.vue b/sgd-ui/src/views/system/dict/data.vue
new file mode 100644
index 0000000..17a77a1
--- /dev/null
+++ b/sgd-ui/src/views/system/dict/data.vue
@@ -0,0 +1,402 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="字典名称" prop="dictType">
+ <el-select v-model="queryParams.dictType">
+ <el-option
+ v-for="item in typeOptions"
+ :key="item.dictId"
+ :label="item.dictName"
+ :value="item.dictType"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="字典标签" prop="dictLabel">
+ <el-input
+ v-model="queryParams.dictLabel"
+ placeholder="请输入字典标签"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="数据状态" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:dict:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:dict:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:dict:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:dict:export']"
+ >导出</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-close"
+ size="mini"
+ @click="handleClose"
+ >关闭</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="字典编码" align="center" prop="dictCode" />
+ <el-table-column label="字典标签" align="center" prop="dictLabel">
+ <template slot-scope="scope">
+ <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
+ <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="字典键值" align="center" prop="dictValue" />
+ <el-table-column label="字典排序" align="center" prop="dictSort" />
+ <el-table-column label="状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:dict:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:dict:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改参数配置对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-form-item label="字典类型">
+ <el-input v-model="form.dictType" :disabled="true" />
+ </el-form-item>
+ <el-form-item label="数据标签" prop="dictLabel">
+ <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
+ </el-form-item>
+ <el-form-item label="数据键值" prop="dictValue">
+ <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
+ </el-form-item>
+ <el-form-item label="样式属性" prop="cssClass">
+ <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
+ </el-form-item>
+ <el-form-item label="显示排序" prop="dictSort">
+ <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
+ </el-form-item>
+ <el-form-item label="回显样式" prop="listClass">
+ <el-select v-model="form.listClass">
+ <el-option
+ v-for="item in listClassOptions"
+ :key="item.value"
+ :label="item.label + '(' + item.value + ')'"
+ :value="item.value"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="备注" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"
+import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type"
+
+export default {
+ name: "Data",
+ dicts: ['sys_normal_disable'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 字典表格数据
+ dataList: [],
+ // 默认字典类型
+ defaultDictType: "",
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 数据标签回显样式
+ listClassOptions: [
+ {
+ value: "default",
+ label: "默认"
+ },
+ {
+ value: "primary",
+ label: "主要"
+ },
+ {
+ value: "success",
+ label: "成功"
+ },
+ {
+ value: "info",
+ label: "信息"
+ },
+ {
+ value: "warning",
+ label: "警告"
+ },
+ {
+ value: "danger",
+ label: "危险"
+ }
+ ],
+ // 类型数据字典
+ typeOptions: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ dictType: undefined,
+ dictLabel: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ dictLabel: [
+ { required: true, message: "数据标签不能为空", trigger: "blur" }
+ ],
+ dictValue: [
+ { required: true, message: "数据键值不能为空", trigger: "blur" }
+ ],
+ dictSort: [
+ { required: true, message: "数据顺序不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ const dictId = this.$route.params && this.$route.params.dictId
+ this.getType(dictId)
+ this.getTypeList()
+ },
+ methods: {
+ /** 查询字典类型详细 */
+ getType(dictId) {
+ getType(dictId).then(response => {
+ this.queryParams.dictType = response.data.dictType
+ this.defaultDictType = response.data.dictType
+ this.getList()
+ })
+ },
+ /** 查询字典类型列表 */
+ getTypeList() {
+ getDictOptionselect().then(response => {
+ this.typeOptions = response.data
+ })
+ },
+ /** 查询字典数据列表 */
+ getList() {
+ this.loading = true
+ listData(this.queryParams).then(response => {
+ this.dataList = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ dictCode: undefined,
+ dictLabel: undefined,
+ dictValue: undefined,
+ cssClass: undefined,
+ listClass: 'default',
+ dictSort: 0,
+ status: "0",
+ remark: undefined
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 返回按钮操作 */
+ handleClose() {
+ const obj = { path: "/system/dict" }
+ this.$tab.closeOpenPage(obj)
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.queryParams.dictType = this.defaultDictType
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加字典数据"
+ this.form.dictType = this.queryParams.dictType
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.dictCode)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const dictCode = row.dictCode || this.ids
+ getData(dictCode).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改字典数据"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.dictCode != undefined) {
+ updateData(this.form).then(() => {
+ this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addData(this.form).then(() => {
+ this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const dictCodes = row.dictCode || this.ids
+ this.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
+ return delData(dictCodes)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ this.$store.dispatch('dict/removeDict', this.queryParams.dictType)
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/dict/data/export', {
+ ...this.queryParams
+ }, `data_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dict/detail.vue b/sgd-ui/src/views/system/dict/detail.vue
similarity index 100%
rename from ruoyi-ui/src/views/system/dict/detail.vue
rename to sgd-ui/src/views/system/dict/detail.vue
diff --git a/sgd-ui/src/views/system/dict/index.vue b/sgd-ui/src/views/system/dict/index.vue
new file mode 100644
index 0000000..6ea3ada
--- /dev/null
+++ b/sgd-ui/src/views/system/dict/index.vue
@@ -0,0 +1,375 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="字典名称" prop="dictName">
+ <el-input
+ v-model="queryParams.dictName"
+ placeholder="请输入字典名称"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="字典类型" prop="dictType">
+ <el-input
+ v-model="queryParams.dictType"
+ placeholder="请输入字典类型"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select
+ v-model="queryParams.status"
+ placeholder="字典状态"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="创建时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:dict:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:dict:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:dict:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:dict:export']"
+ >导出</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-refresh"
+ size="mini"
+ @click="handleRefreshCache"
+ v-hasPermi="['system:dict:remove']"
+ >刷新缓存</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="字典编号" align="center" prop="dictId" />
+ <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
+ <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.dictType }}</a>
+ </template>
+ </el-table-column>
+ <el-table-column label="状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:dict:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-s-operation"
+ @click="handleDataList(scope.row)"
+ v-hasPermi="['system:dict:edit']"
+ >列表</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:dict:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改参数配置对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="字典名称" prop="dictName">
+ <el-input v-model="form.dictName" placeholder="请输入字典名称" />
+ </el-form-item>
+ <el-form-item prop="dictType">
+ <el-input v-model="form.dictType" placeholder="请输入字典类型" maxlength="100" />
+ <span slot="label">
+ <el-tooltip content="数据存储中的Key值,如:sys_user_sex" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 字典类型
+ </span>
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="备注" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+
+ <dict-data-drawer :visible.sync="drawerVisible" :row="drawerRow" />
+ </div>
+</template>
+
+<script>
+import DictDataDrawer from './detail'
+import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type"
+
+export default {
+ name: "Dict",
+ components: { DictDataDrawer },
+ dicts: ['sys_normal_disable'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 字典表格数据
+ typeList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 字典数据抽屉状态
+ drawerVisible: false,
+ // 字典数据信息
+ drawerRow: {},
+ // 日期范围
+ dateRange: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ dictName: undefined,
+ dictType: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ dictName: [
+ { required: true, message: "字典名称不能为空", trigger: "blur" }
+ ],
+ dictType: [
+ { required: true, message: "字典类型不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询字典类型列表 */
+ getList() {
+ this.loading = true
+ listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.typeList = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ dictId: undefined,
+ dictName: undefined,
+ dictType: undefined,
+ status: "0",
+ remark: undefined
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加字典类型"
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.dictId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ /** 字典数据抽屉显示信息 */
+ handleViewData(row) {
+ this.drawerRow = row
+ this.drawerVisible = true
+ },
+ /** 字典数据列表页面 */
+ handleDataList(row) {
+ this.$tab.openPage("字典数据", '/system/dict-data/index/' + row.dictId)
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const dictId = row.dictId || this.ids
+ getType(dictId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改字典类型"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.dictId != undefined) {
+ updateType(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addType(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const dictIds = row.dictId || this.ids
+ this.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
+ return delType(dictIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/dict/type/export', {
+ ...this.queryParams
+ }, `type_${new Date().getTime()}.xlsx`)
+ },
+ /** 刷新缓存按钮操作 */
+ handleRefreshCache() {
+ refreshCache().then(() => {
+ this.$modal.msgSuccess("刷新成功")
+ this.$store.dispatch('dict/cleanDict')
+ })
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/sgd-ui/src/views/system/logininfor/index.vue b/sgd-ui/src/views/system/logininfor/index.vue
new file mode 100644
index 0000000..6be0542
--- /dev/null
+++ b/sgd-ui/src/views/system/logininfor/index.vue
@@ -0,0 +1,243 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="登录地址" prop="ipaddr">
+ <el-input
+ v-model="queryParams.ipaddr"
+ placeholder="请输入登录地址"
+ clearable
+ style="width: 240px;"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="用户名称" prop="userName">
+ <el-input
+ v-model="queryParams.userName"
+ placeholder="请输入用户名称"
+ clearable
+ style="width: 240px;"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select
+ v-model="queryParams.status"
+ placeholder="登录状态"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_common_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="登录时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ :default-time="['00:00:00', '23:59:59']"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:logininfor:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ @click="handleClean"
+ v-hasPermi="['system:logininfor:remove']"
+ >清空</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-unlock"
+ size="mini"
+ :disabled="single"
+ @click="handleUnlock"
+ v-hasPermi="['system:logininfor:unlock']"
+ >解锁</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:logininfor:export']"
+ >导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="访问编号" align="center" prop="infoId" />
+ <el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
+ <el-table-column label="地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
+ <el-table-column label="登录状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="描述" align="center" prop="msg" :show-overflow-tooltip="true" />
+ <el-table-column label="访问时间" align="center" prop="accessTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.accessTime) }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+ </div>
+</template>
+
+<script>
+import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/system/logininfor"
+
+export default {
+ name: "Logininfor",
+ dicts: ['sys_common_status'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 选择用户名
+ selectName: "",
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 表格数据
+ list: [],
+ // 日期范围
+ dateRange: [],
+ // 默认排序
+ defaultSort: { prop: "accessTime", order: "descending" },
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ ipaddr: undefined,
+ userName: undefined,
+ status: undefined
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询登录日志列表 */
+ getList() {
+ this.loading = true
+ list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.list = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.queryParams.pageNum = 1
+ this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
+ },
+ /** 多选框选中数据 */
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.infoId)
+ this.single = selection.length!=1
+ this.multiple = !selection.length
+ this.selectName = selection.map(item => item.userName)
+ },
+ /** 排序触发事件 */
+ handleSortChange(column, prop, order) {
+ this.queryParams.orderByColumn = column.prop
+ this.queryParams.isAsc = column.order
+ this.getList()
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const infoIds = row.infoId || this.ids
+ this.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function() {
+ return delLogininfor(infoIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 清空按钮操作 */
+ handleClean() {
+ this.$modal.confirm('是否确认清空所有登录日志数据项?').then(function() {
+ return cleanLogininfor()
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("清空成功")
+ }).catch(() => {})
+ },
+ /** 解锁按钮操作 */
+ handleUnlock() {
+ const username = this.selectName
+ this.$modal.confirm('是否确认解锁用户"' + username + '"数据项?').then(function() {
+ return unlockLogininfor(username)
+ }).then(() => {
+ this.$modal.msgSuccess("用户" + username + "解锁成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/logininfor/export', {
+ ...this.queryParams
+ }, `logininfor_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
+
diff --git a/sgd-ui/src/views/system/menu/index.vue b/sgd-ui/src/views/system/menu/index.vue
new file mode 100644
index 0000000..0255d0e
--- /dev/null
+++ b/sgd-ui/src/views/system/menu/index.vue
@@ -0,0 +1,533 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+ <el-form-item label="菜单名称" prop="menuName">
+ <el-input
+ v-model="queryParams.menuName"
+ placeholder="请输入菜单名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:menu:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-check"
+ size="mini"
+ @click="handleSaveSort"
+ v-hasPermi="['system:menu:edit']"
+ >保存排序</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="info"
+ plain
+ icon="el-icon-sort"
+ size="mini"
+ @click="toggleExpandAll"
+ >展开/折叠</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table
+ v-if="refreshTable"
+ v-loading="loading"
+ :data="menuList"
+ row-key="menuId"
+ :default-expand-all="isExpandAll"
+ :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+ >
+ <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="220">
+ <template slot-scope="scope">
+ <svg-icon :icon-class="scope.row.icon" />
+ <span class="ml5">{{ scope.row.menuName }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="menuName" label="类型" :show-overflow-tooltip="true" width="100">
+ <template slot-scope="scope">
+ <el-tag v-if="scope.row.menuType === 'M' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
+ <el-tag v-else-if="scope.row.menuType === 'M'" type="primary" size="small">目录</el-tag>
+ <el-tag v-else-if="scope.row.menuType === 'C' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
+ <el-tag v-else-if="scope.row.menuType === 'C'" type="success" size="small">菜单</el-tag>
+ <el-tag v-else-if="scope.row.menuType === 'F'" type="warning" size="small">按钮</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="orderNum" label="排序" width="200">
+ <template slot-scope="scope">
+ <el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" size="mini" style="width: 88px" />
+ </template>
+ </el-table-column>
+ <el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true" />
+ <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true" />
+ <el-table-column prop="status" label="状态" width="80">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status" />
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:menu:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-plus"
+ @click="handleAdd(scope.row)"
+ v-hasPermi="['system:menu:add']"
+ >新增</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:menu:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <!-- 添加或修改菜单对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="上级菜单" prop="parentId">
+ <treeselect
+ v-model="form.parentId"
+ :options="menuOptions"
+ :normalizer="normalizer"
+ :show-count="true"
+ placeholder="选择上级菜单"
+ />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="菜单类型" prop="menuType">
+ <el-radio-group v-model="form.menuType">
+ <el-radio label="M">目录</el-radio>
+ <el-radio label="C">菜单</el-radio>
+ <el-radio label="F">按钮</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12" v-if="form.menuType != 'F'">
+ <el-form-item label="菜单图标" prop="icon">
+ <el-popover
+ placement="bottom-start"
+ width="460"
+ trigger="click"
+ @show="$refs['iconSelect'].reset()"
+ >
+ <IconSelect ref="iconSelect" @selected="selected" :active-icon="form.icon" />
+ <el-input slot="reference" v-model="form.icon" placeholder="点击选择图标" readonly>
+ <svg-icon
+ v-if="form.icon"
+ slot="prefix"
+ :icon-class="form.icon"
+ style="width: 25px;"
+ />
+ <i v-else slot="prefix" class="el-icon-search el-input__icon" />
+ </el-input>
+ </el-popover>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="显示排序" prop="orderNum">
+ <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="菜单名称" prop="menuName">
+ <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.menuType == 'C'">
+ <el-form-item prop="routeName">
+ <el-input v-model="form.routeName" placeholder="请输入路由名称" />
+ <span slot="label">
+ <el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 路由名称
+ </span>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12" v-if="form.menuType != 'F'">
+ <el-form-item prop="isFrame">
+ <span slot="label">
+ <el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 是否外链
+ </span>
+ <el-radio-group v-model="form.isFrame">
+ <el-radio label="0">是</el-radio>
+ <el-radio label="1">否</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.menuType != 'F'">
+ <el-form-item prop="path">
+ <span slot="label">
+ <el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 路由地址
+ </span>
+ <el-input v-model="form.path" placeholder="请输入路由地址" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12" v-if="form.menuType == 'C'">
+ <el-form-item prop="component">
+ <span slot="label">
+ <el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 组件路径
+ </span>
+ <el-input v-model="form.component" placeholder="请输入组件路径" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.menuType != 'M'">
+ <el-form-item prop="perms">
+ <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
+ <span slot="label">
+ <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 权限字符
+ </span>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12" v-if="form.menuType == 'C'">
+ <el-form-item prop="query">
+ <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
+ <span slot="label">
+ <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 路由参数
+ </span>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12" v-if="form.menuType == 'C'">
+ <el-form-item prop="isCache">
+ <span slot="label">
+ <el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 是否缓存
+ </span>
+ <el-radio-group v-model="form.isCache">
+ <el-radio label="0">缓存</el-radio>
+ <el-radio label="1">不缓存</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12" v-if="form.menuType != 'F'">
+ <el-form-item prop="visible">
+ <span slot="label">
+ <el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 显示状态
+ </span>
+ <el-radio-group v-model="form.visible">
+ <el-radio
+ v-for="dict in dict.type.sys_show_hide"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item prop="status">
+ <span slot="label">
+ <el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 菜单状态
+ </span>
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listMenu, getMenu, delMenu, addMenu, updateMenu, updateMenuSort } from "@/api/system/menu"
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+import IconSelect from "@/components/IconSelect"
+
+export default {
+ name: "Menu",
+ dicts: ['sys_show_hide', 'sys_normal_disable'],
+ components: { Treeselect, IconSelect },
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 菜单表格树数据
+ menuList: [],
+ // 菜单树选项
+ menuOptions: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 是否展开,默认全部折叠
+ isExpandAll: false,
+ // 重新渲染表格状态
+ refreshTable: true,
+ // 记录原始排序,用于对比变更
+ originalOrders: {},
+ // 查询参数
+ queryParams: {
+ menuName: undefined,
+ visible: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ menuName: [
+ { required: true, message: "菜单名称不能为空", trigger: "blur" }
+ ],
+ orderNum: [
+ { required: true, message: "菜单顺序不能为空", trigger: "blur" }
+ ],
+ path: [
+ { required: true, message: "路由地址不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ // 选择图标
+ selected(name) {
+ this.form.icon = name
+ },
+ /** 查询菜单列表 */
+ getList() {
+ this.loading = true
+ listMenu(this.queryParams).then(response => {
+ this.menuList = this.handleTree(response.data, "menuId")
+ // 记录原始排序值
+ this.recordOriginalOrders(this.menuList)
+ this.loading = false
+ })
+ },
+ /** 转换菜单数据结构 */
+ normalizer(node) {
+ if (node.children && !node.children.length) {
+ delete node.children
+ }
+ return {
+ id: node.menuId,
+ label: node.menuName,
+ children: node.children
+ }
+ },
+ /** 查询菜单下拉树结构 */
+ getTreeselect() {
+ listMenu().then(response => {
+ this.menuOptions = []
+ const menu = { menuId: 0, menuName: '主类目', children: [] }
+ menu.children = this.handleTree(response.data, "menuId")
+ this.menuOptions.push(menu)
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ menuId: undefined,
+ parentId: 0,
+ menuName: undefined,
+ icon: undefined,
+ menuType: "M",
+ orderNum: undefined,
+ isFrame: "1",
+ isCache: "0",
+ visible: "0",
+ status: "0"
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 新增按钮操作 */
+ handleAdd(row) {
+ this.reset()
+ this.getTreeselect()
+ if (row != null && row.menuId) {
+ this.form.parentId = row.menuId
+ } else {
+ this.form.parentId = 0
+ }
+ this.open = true
+ this.title = "添加菜单"
+ },
+ /** 展开/折叠操作 */
+ toggleExpandAll() {
+ this.refreshTable = false
+ this.isExpandAll = !this.isExpandAll
+ this.$nextTick(() => {
+ this.refreshTable = true
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ this.getTreeselect()
+ getMenu(row.menuId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改菜单"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.menuId != undefined) {
+ updateMenu(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addMenu(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 递归记录原始排序 */
+ recordOriginalOrders(list) {
+ list.forEach(item => {
+ this.originalOrders[item.menuId] = item.orderNum
+ if (item.children && item.children.length) {
+ this.recordOriginalOrders(item.children)
+ }
+ })
+ },
+ /** 保存排序 */
+ handleSaveSort() {
+ const changedMenuIds = []
+ const changedOrderNums = []
+ const collectChanged = (list) => {
+ list.forEach(item => {
+ if (String(this.originalOrders[item.menuId]) !== String(item.orderNum)) {
+ changedMenuIds.push(item.menuId)
+ changedOrderNums.push(item.orderNum)
+ }
+ if (item.children && item.children.length) {
+ collectChanged(item.children)
+ }
+ })
+ }
+ collectChanged(this.menuList)
+ if (changedMenuIds.length === 0) {
+ this.$modal.msgWarning("未检测到排序修改")
+ return
+ }
+ updateMenuSort({ menuIds: changedMenuIds.join(","), orderNums: changedOrderNums.join(",") }).then(() => {
+ this.$modal.msgSuccess("排序保存成功")
+ this.recordOriginalOrders(this.menuList)
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ this.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
+ return delMenu(row.menuId)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/views/system/notice/ReadUsers.vue b/sgd-ui/src/views/system/notice/ReadUsers.vue
similarity index 100%
rename from ruoyi-ui/src/views/system/notice/ReadUsers.vue
rename to sgd-ui/src/views/system/notice/ReadUsers.vue
diff --git a/sgd-ui/src/views/system/notice/index.vue b/sgd-ui/src/views/system/notice/index.vue
new file mode 100644
index 0000000..27f65b0
--- /dev/null
+++ b/sgd-ui/src/views/system/notice/index.vue
@@ -0,0 +1,332 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="公告标题" prop="noticeTitle">
+ <el-input
+ v-model="queryParams.noticeTitle"
+ placeholder="请输入公告标题"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="操作人员" prop="createBy">
+ <el-input
+ v-model="queryParams.createBy"
+ placeholder="请输入操作人员"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="类型" prop="noticeType">
+ <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_notice_type"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:notice:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:notice:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:notice:remove']"
+ >删除</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="序号" align="center" prop="noticeId" width="100" />
+ <el-table-column label="公告标题" align="center" :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.noticeTitle }}</a>
+ </template>
+ </el-table-column>
+ <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="状态" align="center" prop="status" width="100">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建者" align="center" prop="createBy" width="100" />
+ <el-table-column label="创建时间" align="center" prop="createTime" width="100">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-user"
+ @click="handleReadUsers(scope.row)"
+ v-hasPermi="['system:notice:list']"
+ >阅读用户</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:notice:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:notice:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改公告对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="780px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="公告标题" prop="noticeTitle">
+ <el-input v-model="form.noticeTitle" placeholder="请输入公告标题" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="公告类型" prop="noticeType">
+ <el-select v-model="form.noticeType" placeholder="请选择公告类型">
+ <el-option
+ v-for="dict in dict.type.sys_notice_type"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="状态">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_notice_status"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="内容">
+ <editor v-model="form.noticeContent" :min-height="192"/>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+
+ <notice-detail-view ref="noticeViewRef" />
+ <read-users-dialog ref="readUsersRef" />
+ </div>
+</template>
+
+<script>
+import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView"
+import ReadUsersDialog from "./ReadUsers"
+import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"
+
+export default {
+ name: "Notice",
+ components: { NoticeDetailView, ReadUsersDialog },
+ dicts: ['sys_notice_status', 'sys_notice_type'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 公告表格数据
+ noticeList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ noticeTitle: undefined,
+ createBy: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ noticeTitle: [
+ { required: true, message: "公告标题不能为空", trigger: "blur" }
+ ],
+ noticeType: [
+ { required: true, message: "公告类型不能为空", trigger: "change" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询公告列表 */
+ getList() {
+ this.loading = true
+ listNotice(this.queryParams).then(response => {
+ this.noticeList = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ noticeId: undefined,
+ noticeTitle: undefined,
+ noticeType: undefined,
+ noticeContent: undefined,
+ status: "0"
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.noticeId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加公告"
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const noticeId = row.noticeId || this.ids
+ getNotice(noticeId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改公告"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.noticeId != undefined) {
+ updateNotice(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addNotice(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 查看公告详情 */
+ handleViewData(row) {
+ this.$refs.noticeViewRef.open(row)
+ },
+ /** 查看已读用户 */
+ handleReadUsers(row) {
+ this.$refs.readUsersRef.open(row)
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const noticeIds = row.noticeId || this.ids
+ this.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
+ return delNotice(noticeIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/views/system/operlog/detail.vue b/sgd-ui/src/views/system/operlog/detail.vue
similarity index 100%
rename from ruoyi-ui/src/views/system/operlog/detail.vue
rename to sgd-ui/src/views/system/operlog/detail.vue
diff --git a/sgd-ui/src/views/system/operlog/index.vue b/sgd-ui/src/views/system/operlog/index.vue
new file mode 100644
index 0000000..3c82004
--- /dev/null
+++ b/sgd-ui/src/views/system/operlog/index.vue
@@ -0,0 +1,279 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="操作地址" prop="operIp">
+ <el-input
+ v-model="queryParams.operIp"
+ placeholder="请输入操作地址"
+ clearable
+ style="width: 240px;"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="系统模块" prop="title">
+ <el-input
+ v-model="queryParams.title"
+ placeholder="请输入系统模块"
+ clearable
+ style="width: 240px;"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="操作人员" prop="operName">
+ <el-input
+ v-model="queryParams.operName"
+ placeholder="请输入操作人员"
+ clearable
+ style="width: 240px;"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="类型" prop="businessType">
+ <el-select
+ v-model="queryParams.businessType"
+ placeholder="操作类型"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_oper_type"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select
+ v-model="queryParams.status"
+ placeholder="操作状态"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_common_status"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="操作时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ :default-time="['00:00:00', '23:59:59']"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:operlog:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ @click="handleClean"
+ v-hasPermi="['system:operlog:remove']"
+ >清空</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:operlog:export']"
+ >导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
+ <el-table-column type="selection" width="50" align="center" />
+ <el-table-column label="日志编号" align="center" prop="operId" />
+ <el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
+ <el-table-column label="操作类型" align="center" prop="businessType">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_oper_type" :value="scope.row.businessType"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="请求方式" align="center" prop="requestMethod" />
+ <el-table-column label="操作人员" align="center" prop="operName" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']"/>
+ <el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
+ <el-table-column label="操作状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作日期" align="center" prop="operTime" width="180" sortable="custom" :sort-orders="['descending', 'ascending']">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.operTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="消耗时间" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
+ <template slot-scope="scope">
+ <span>{{ scope.row.costTime }}毫秒</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-view"
+ @click="handleDetail(scope.row,scope.index)"
+ v-hasPermi="['system:operlog:query']"
+ >详细</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <operlog-detail :visible.sync="detailVisible" :row="detailRow" />
+ </div>
+</template>
+
+<script>
+import OperlogDetail from './detail'
+import { list, delOperlog, cleanOperlog } from "@/api/system/operlog"
+
+export default {
+ name: "Operlog",
+ components: { OperlogDetail },
+ dicts: ['sys_oper_type', 'sys_common_status'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 表格数据
+ list: [],
+ // 是否显示弹出层
+ detailVisible: false,
+ detailRow: {},
+ // 日期范围
+ dateRange: [],
+ // 默认排序
+ defaultSort: { prop: "operTime", order: "descending" },
+ // 表单参数
+ form: {},
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ operIp: undefined,
+ title: undefined,
+ operName: undefined,
+ businessType: undefined,
+ status: undefined
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询登录日志 */
+ getList() {
+ this.loading = true
+ list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {
+ this.list = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ // 详细按钮操作
+ handleDetail(row) {
+ this.detailRow = row
+ this.detailVisible = true
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.queryParams.pageNum = 1
+ this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
+ },
+ /** 多选框选中数据 */
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.operId)
+ this.multiple = !selection.length
+ },
+ /** 排序触发事件 */
+ handleSortChange(column, prop, order) {
+ this.queryParams.orderByColumn = column.prop
+ this.queryParams.isAsc = column.order
+ this.getList()
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const operIds = row.operId || this.ids
+ this.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function() {
+ return delOperlog(operIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 清空按钮操作 */
+ handleClean() {
+ this.$modal.confirm('是否确认清空所有操作日志数据项?').then(function() {
+ return cleanOperlog()
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("清空成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/operlog/export', {
+ ...this.queryParams
+ }, `operlog_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
+
diff --git a/sgd-ui/src/views/system/post/index.vue b/sgd-ui/src/views/system/post/index.vue
new file mode 100644
index 0000000..93891ff
--- /dev/null
+++ b/sgd-ui/src/views/system/post/index.vue
@@ -0,0 +1,309 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="岗位编码" prop="postCode">
+ <el-input
+ v-model="queryParams.postCode"
+ placeholder="请输入岗位编码"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="岗位名称" prop="postName">
+ <el-input
+ v-model="queryParams.postName"
+ placeholder="请输入岗位名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="岗位状态" clearable>
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:post:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:post:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:post:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:post:export']"
+ >导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="岗位编号" align="center" prop="postId" />
+ <el-table-column label="岗位编码" align="center" prop="postCode" />
+ <el-table-column label="岗位名称" align="center" prop="postName" />
+ <el-table-column label="岗位排序" align="center" prop="postSort" />
+ <el-table-column label="状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:post:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:post:remove']"
+ >删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改岗位对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-form-item label="岗位名称" prop="postName">
+ <el-input v-model="form.postName" placeholder="请输入岗位名称" />
+ </el-form-item>
+ <el-form-item label="岗位编码" prop="postCode">
+ <el-input v-model="form.postCode" placeholder="请输入编码名称" />
+ </el-form-item>
+ <el-form-item label="岗位顺序" prop="postSort">
+ <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
+ </el-form-item>
+ <el-form-item label="岗位状态" prop="status">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="备注" prop="remark">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post"
+
+export default {
+ name: "Post",
+ dicts: ['sys_normal_disable'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 岗位表格数据
+ postList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ postCode: undefined,
+ postName: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ // 表单校验
+ rules: {
+ postName: [
+ { required: true, message: "岗位名称不能为空", trigger: "blur" }
+ ],
+ postCode: [
+ { required: true, message: "岗位编码不能为空", trigger: "blur" }
+ ],
+ postSort: [
+ { required: true, message: "岗位顺序不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询岗位列表 */
+ getList() {
+ this.loading = true
+ listPost(this.queryParams).then(response => {
+ this.postList = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ postId: undefined,
+ postCode: undefined,
+ postName: undefined,
+ postSort: 0,
+ status: "0",
+ remark: undefined
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.postId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.open = true
+ this.title = "添加岗位"
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const postId = row.postId || this.ids
+ getPost(postId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.title = "修改岗位"
+ })
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.postId != undefined) {
+ updatePost(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addPost(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const postIds = row.postId || this.ids
+ this.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
+ return delPost(postIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/post/export', {
+ ...this.queryParams
+ }, `post_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/system/role/authUser.vue b/sgd-ui/src/views/system/role/authUser.vue
new file mode 100644
index 0000000..c11babc
--- /dev/null
+++ b/sgd-ui/src/views/system/role/authUser.vue
@@ -0,0 +1,199 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+ <el-form-item label="用户名称" prop="userName">
+ <el-input
+ v-model="queryParams.userName"
+ placeholder="请输入用户名称"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="手机号码" prop="phonenumber">
+ <el-input
+ v-model="queryParams.phonenumber"
+ placeholder="请输入手机号码"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="openSelectUser"
+ v-hasPermi="['system:role:add']"
+ >添加用户</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-circle-close"
+ size="mini"
+ :disabled="multiple"
+ @click="cancelAuthUserAll"
+ v-hasPermi="['system:role:remove']"
+ >批量取消授权</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-close"
+ size="mini"
+ @click="handleClose"
+ >关闭</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
+ <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
+ <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
+ <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
+ <el-table-column label="状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-circle-close"
+ @click="cancelAuthUser(scope.row)"
+ v-hasPermi="['system:role:remove']"
+ >取消授权</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+ <select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" />
+ </div>
+</template>
+
+<script>
+import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role"
+import selectUser from "./selectUser"
+
+export default {
+ name: "AuthUser",
+ dicts: ['sys_normal_disable'],
+ components: { selectUser },
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中用户组
+ userIds: [],
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 用户表格数据
+ userList: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ roleId: undefined,
+ userName: undefined,
+ phonenumber: undefined
+ }
+ }
+ },
+ created() {
+ const roleId = this.$route.params && this.$route.params.roleId
+ if (roleId) {
+ this.queryParams.roleId = roleId
+ this.getList()
+ }
+ },
+ methods: {
+ /** 查询授权用户列表 */
+ getList() {
+ this.loading = true
+ allocatedUserList(this.queryParams).then(response => {
+ this.userList = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ // 返回按钮
+ handleClose() {
+ const obj = { path: "/system/role" }
+ this.$tab.closeOpenPage(obj)
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.userIds = selection.map(item => item.userId)
+ this.multiple = !selection.length
+ },
+ /** 打开授权用户表弹窗 */
+ openSelectUser() {
+ this.$refs.select.show()
+ },
+ /** 取消授权按钮操作 */
+ cancelAuthUser(row) {
+ const roleId = this.queryParams.roleId
+ this.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function() {
+ return authUserCancel({ userId: row.userId, roleId: roleId })
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("取消授权成功")
+ }).catch(() => {})
+ },
+ /** 批量取消授权按钮操作 */
+ cancelAuthUserAll() {
+ const roleId = this.queryParams.roleId
+ const userIds = this.userIds.join(",")
+ this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {
+ return authUserCancelAll({ roleId: roleId, userIds: userIds })
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("取消授权成功")
+ }).catch(() => {})
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/sgd-ui/src/views/system/role/index.vue b/sgd-ui/src/views/system/role/index.vue
new file mode 100644
index 0000000..b061151
--- /dev/null
+++ b/sgd-ui/src/views/system/role/index.vue
@@ -0,0 +1,605 @@
+<template>
+ <div class="app-container">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+ <el-form-item label="角色名称" prop="roleName">
+ <el-input
+ v-model="queryParams.roleName"
+ placeholder="请输入角色名称"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="权限字符" prop="roleKey">
+ <el-input
+ v-model="queryParams.roleKey"
+ placeholder="请输入权限字符"
+ clearable
+ style="width: 240px"
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select
+ v-model="queryParams.status"
+ placeholder="角色状态"
+ clearable
+ style="width: 240px"
+ >
+ <el-option
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="创建时间">
+ <el-date-picker
+ v-model="dateRange"
+ style="width: 240px"
+ value-format="yyyy-MM-dd"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ ></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button
+ type="primary"
+ plain
+ icon="el-icon-plus"
+ size="mini"
+ @click="handleAdd"
+ v-hasPermi="['system:role:add']"
+ >新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="success"
+ plain
+ icon="el-icon-edit"
+ size="mini"
+ :disabled="single"
+ @click="handleUpdate"
+ v-hasPermi="['system:role:edit']"
+ >修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="danger"
+ plain
+ icon="el-icon-delete"
+ size="mini"
+ :disabled="multiple"
+ @click="handleDelete"
+ v-hasPermi="['system:role:remove']"
+ >删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button
+ type="warning"
+ plain
+ icon="el-icon-download"
+ size="mini"
+ @click="handleExport"
+ v-hasPermi="['system:role:export']"
+ >导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+ <el-table-column label="角色编号" prop="roleId" width="120" />
+ <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
+ <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
+ <el-table-column label="显示顺序" prop="roleSort" width="100" />
+ <el-table-column label="状态" align="center" width="100">
+ <template slot-scope="scope">
+ <el-switch
+ v-model="scope.row.status"
+ active-value="0"
+ inactive-value="1"
+ @change="handleStatusChange(scope.row)"
+ ></el-switch>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+ <template slot-scope="scope" v-if="scope.row.roleId !== 1">
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-edit"
+ @click="handleUpdate(scope.row)"
+ v-hasPermi="['system:role:edit']"
+ >修改</el-button>
+ <el-button
+ size="mini"
+ type="text"
+ icon="el-icon-delete"
+ @click="handleDelete(scope.row)"
+ v-hasPermi="['system:role:remove']"
+ >删除</el-button>
+ <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:role:edit']">
+ <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
+ v-hasPermi="['system:role:edit']">数据权限</el-dropdown-item>
+ <el-dropdown-item command="handleAuthUser" icon="el-icon-user"
+ v-hasPermi="['system:role:edit']">分配用户</el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+
+ <!-- 添加或修改角色配置对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+ <el-form-item label="角色名称" prop="roleName">
+ <el-input v-model="form.roleName" placeholder="请输入角色名称" />
+ </el-form-item>
+ <el-form-item prop="roleKey">
+ <span slot="label">
+ <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ 权限字符
+ </span>
+ <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
+ </el-form-item>
+ <el-form-item label="角色顺序" prop="roleSort">
+ <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
+ </el-form-item>
+ <el-form-item label="状态">
+ <el-radio-group v-model="form.status">
+ <el-radio
+ v-for="dict in dict.type.sys_normal_disable"
+ :key="dict.value"
+ :label="dict.value"
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="菜单权限">
+ <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
+ <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
+ <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
+ <el-tree
+ class="tree-border"
+ :data="menuOptions"
+ show-checkbox
+ ref="menu"
+ node-key="id"
+ :check-strictly="!form.menuCheckStrictly"
+ empty-text="加载中,请稍候"
+ :props="defaultProps"
+ ></el-tree>
+ </el-form-item>
+ <el-form-item label="备注">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+
+ <!-- 分配角色数据权限对话框 -->
+ <el-dialog :title="title" :visible.sync="openDataScope" width="500px" append-to-body>
+ <el-form :model="form" label-width="80px">
+ <el-form-item label="角色名称">
+ <el-input v-model="form.roleName" :disabled="true" />
+ </el-form-item>
+ <el-form-item label="权限字符">
+ <el-input v-model="form.roleKey" :disabled="true" />
+ </el-form-item>
+ <el-form-item label="权限范围">
+ <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
+ <el-option
+ v-for="item in dataScopeOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="数据权限" v-show="form.dataScope == 2">
+ <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
+ <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
+ <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
+ <el-tree
+ class="tree-border"
+ :data="deptOptions"
+ show-checkbox
+ default-expand-all
+ ref="dept"
+ node-key="id"
+ :check-strictly="!form.deptCheckStrictly"
+ empty-text="加载中,请稍候"
+ :props="defaultProps"
+ ></el-tree>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitDataScope">确 定</el-button>
+ <el-button @click="cancelDataScope">取 消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus, deptTreeSelect } from "@/api/system/role"
+import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu"
+
+export default {
+ name: "Role",
+ dicts: ['sys_normal_disable'],
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 角色表格数据
+ roleList: [],
+ // 弹出层标题
+ title: "",
+ // 是否显示弹出层
+ open: false,
+ // 是否显示弹出层(数据权限)
+ openDataScope: false,
+ menuExpand: false,
+ menuNodeAll: false,
+ deptExpand: true,
+ deptNodeAll: false,
+ // 日期范围
+ dateRange: [],
+ // 数据范围选项
+ dataScopeOptions: [
+ {
+ value: "1",
+ label: "全部数据权限"
+ },
+ {
+ value: "2",
+ label: "自定数据权限"
+ },
+ {
+ value: "3",
+ label: "本部门数据权限"
+ },
+ {
+ value: "4",
+ label: "本部门及以下数据权限"
+ },
+ {
+ value: "5",
+ label: "仅本人数据权限"
+ }
+ ],
+ // 菜单列表
+ menuOptions: [],
+ // 部门列表
+ deptOptions: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ roleName: undefined,
+ roleKey: undefined,
+ status: undefined
+ },
+ // 表单参数
+ form: {},
+ defaultProps: {
+ children: "children",
+ label: "label"
+ },
+ // 表单校验
+ rules: {
+ roleName: [
+ { required: true, message: "角色名称不能为空", trigger: "blur" }
+ ],
+ roleKey: [
+ { required: true, message: "权限字符不能为空", trigger: "blur" }
+ ],
+ roleSort: [
+ { required: true, message: "角色顺序不能为空", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ },
+ methods: {
+ /** 查询角色列表 */
+ getList() {
+ this.loading = true
+ listRole(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.roleList = response.rows
+ this.total = response.total
+ this.loading = false
+ }
+ )
+ },
+ /** 查询菜单树结构 */
+ getMenuTreeselect() {
+ menuTreeselect().then(response => {
+ this.menuOptions = response.data
+ })
+ },
+ // 所有菜单节点数据
+ getMenuAllCheckedKeys() {
+ // 目前被选中的菜单节点
+ let checkedKeys = this.$refs.menu.getCheckedKeys()
+ // 半选中的菜单节点
+ let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys()
+ checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
+ return checkedKeys
+ },
+ // 所有部门节点数据
+ getDeptAllCheckedKeys() {
+ // 目前被选中的部门节点
+ let checkedKeys = this.$refs.dept.getCheckedKeys()
+ // 半选中的部门节点
+ let halfCheckedKeys = this.$refs.dept.getHalfCheckedKeys()
+ checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
+ return checkedKeys
+ },
+ /** 根据角色ID查询菜单树结构 */
+ getRoleMenuTreeselect(roleId) {
+ return roleMenuTreeselect(roleId).then(response => {
+ this.menuOptions = response.menus
+ return response
+ })
+ },
+ /** 根据角色ID查询部门树结构 */
+ getDeptTree(roleId) {
+ return deptTreeSelect(roleId).then(response => {
+ this.deptOptions = response.depts
+ return response
+ })
+ },
+ // 角色状态修改
+ handleStatusChange(row) {
+ let text = row.status === "0" ? "启用" : "停用"
+ this.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function() {
+ return changeRoleStatus(row.roleId, row.status)
+ }).then(() => {
+ this.$modal.msgSuccess(text + "成功")
+ }).catch(function() {
+ row.status = row.status === "0" ? "1" : "0"
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 取消按钮(数据权限)
+ cancelDataScope() {
+ this.openDataScope = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ if (this.$refs.menu != undefined) {
+ this.$refs.menu.setCheckedKeys([])
+ }
+ this.menuExpand = false,
+ this.menuNodeAll = false,
+ this.deptExpand = true,
+ this.deptNodeAll = false,
+ this.form = {
+ roleId: undefined,
+ roleName: undefined,
+ roleKey: undefined,
+ roleSort: 0,
+ status: "0",
+ menuIds: [],
+ deptIds: [],
+ menuCheckStrictly: true,
+ deptCheckStrictly: true,
+ remark: undefined
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.roleId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ // 更多操作触发
+ handleCommand(command, row) {
+ switch (command) {
+ case "handleDataScope":
+ this.handleDataScope(row)
+ break
+ case "handleAuthUser":
+ this.handleAuthUser(row)
+ break
+ default:
+ break
+ }
+ },
+ // 树权限(展开/折叠)
+ handleCheckedTreeExpand(value, type) {
+ if (type == 'menu') {
+ let treeList = this.menuOptions
+ for (let i = 0; i < treeList.length; i++) {
+ this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value
+ }
+ } else if (type == 'dept') {
+ let treeList = this.deptOptions
+ for (let i = 0; i < treeList.length; i++) {
+ this.$refs.dept.store.nodesMap[treeList[i].id].expanded = value
+ }
+ }
+ },
+ // 树权限(全选/全不选)
+ handleCheckedTreeNodeAll(value, type) {
+ if (type == 'menu') {
+ this.$refs.menu.setCheckedNodes(value ? this.menuOptions: [])
+ } else if (type == 'dept') {
+ this.$refs.dept.setCheckedNodes(value ? this.deptOptions: [])
+ }
+ },
+ // 树权限(父子联动)
+ handleCheckedTreeConnect(value, type) {
+ if (type == 'menu') {
+ this.form.menuCheckStrictly = value ? true: false
+ } else if (type == 'dept') {
+ this.form.deptCheckStrictly = value ? true: false
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ this.getMenuTreeselect()
+ this.open = true
+ this.title = "添加角色"
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const roleId = row.roleId || this.ids
+ const roleMenu = this.getRoleMenuTreeselect(roleId)
+ getRole(roleId).then(response => {
+ this.form = response.data
+ this.open = true
+ this.$nextTick(() => {
+ roleMenu.then(res => {
+ let checkedKeys = res.checkedKeys
+ checkedKeys.forEach((v) => {
+ this.$nextTick(()=>{
+ this.$refs.menu.setChecked(v, true ,false)
+ })
+ })
+ })
+ })
+ })
+ this.title = "修改角色"
+ },
+ /** 选择角色权限范围触发 */
+ dataScopeSelectChange(value) {
+ if(value !== '2') {
+ this.$refs.dept.setCheckedKeys([])
+ }
+ },
+ /** 分配数据权限操作 */
+ handleDataScope(row) {
+ this.reset()
+ const deptTreeSelect = this.getDeptTree(row.roleId)
+ getRole(row.roleId).then(response => {
+ this.form = response.data
+ this.openDataScope = true
+ this.$nextTick(() => {
+ deptTreeSelect.then(res => {
+ this.$refs.dept.setCheckedKeys(res.checkedKeys)
+ })
+ })
+ })
+ this.title = "分配数据权限"
+ },
+ /** 分配用户操作 */
+ handleAuthUser(row) {
+ const roleId = row.roleId
+ this.$router.push("/system/role-auth/user/" + roleId)
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.roleId != undefined) {
+ this.form.menuIds = this.getMenuAllCheckedKeys()
+ updateRole(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ this.form.menuIds = this.getMenuAllCheckedKeys()
+ addRole(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 提交按钮(数据权限) */
+ submitDataScope() {
+ if (this.form.roleId != undefined) {
+ this.form.deptIds = this.getDeptAllCheckedKeys()
+ dataScope(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.openDataScope = false
+ this.getList()
+ })
+ }
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const roleIds = row.roleId || this.ids
+ this.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function() {
+ return delRole(roleIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/role/export', {
+ ...this.queryParams
+ }, `role_${new Date().getTime()}.xlsx`)
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/sgd-ui/src/views/system/role/selectUser.vue b/sgd-ui/src/views/system/role/selectUser.vue
new file mode 100644
index 0000000..d2b21bf
--- /dev/null
+++ b/sgd-ui/src/views/system/role/selectUser.vue
@@ -0,0 +1,136 @@
+<template>
+ <!-- 授权用户 -->
+ <el-dialog title="选择用户" :visible.sync="visible" width="800px" top="5vh" append-to-body>
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
+ <el-form-item label="用户名称" prop="userName">
+ <el-input
+ v-model="queryParams.userName"
+ placeholder="请输入用户名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="手机号码" prop="phonenumber">
+ <el-input
+ v-model="queryParams.phonenumber"
+ placeholder="请输入手机号码"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+ <el-row>
+ <el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px">
+ <el-table-column type="selection" width="55"></el-table-column>
+ <el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
+ <el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
+ <el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
+ <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
+ <el-table-column label="状态" align="center" prop="status">
+ <template slot-scope="scope">
+ <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+ </el-row>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="handleSelectUser">确 定</el-button>
+ <el-button @click="visible = false">取 消</el-button>
+ </div>
+ </el-dialog>
+</template>
+
+<script>
+import { unallocatedUserList, authUserSelectAll } from "@/api/system/role"
+export default {
+ dicts: ['sys_normal_disable'],
+ props: {
+ // 角色编号
+ roleId: {
+ type: [Number, String]
+ }
+ },
+ data() {
+ return {
+ // 遮罩层
+ visible: false,
+ // 选中数组值
+ userIds: [],
+ // 总条数
+ total: 0,
+ // 未授权用户数据
+ userList: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ roleId: undefined,
+ userName: undefined,
+ phonenumber: undefined
+ }
+ }
+ },
+ methods: {
+ // 显示弹框
+ show() {
+ this.queryParams.roleId = this.roleId
+ this.getList()
+ this.visible = true
+ },
+ clickRow(row) {
+ this.$refs.table.toggleRowSelection(row)
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.userIds = selection.map(item => item.userId)
+ },
+ // 查询表数据
+ getList() {
+ unallocatedUserList(this.queryParams).then(res => {
+ this.userList = res.rows
+ this.total = res.total
+ })
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 选择授权用户操作 */
+ handleSelectUser() {
+ const roleId = this.queryParams.roleId
+ const userIds = this.userIds.join(",")
+ if (userIds == "") {
+ this.$modal.msgError("请选择要分配的用户")
+ return
+ }
+ authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
+ this.$modal.msgSuccess(res.msg)
+ this.visible = false
+ this.$emit("ok")
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/system/user/authRole.vue b/sgd-ui/src/views/system/user/authRole.vue
new file mode 100644
index 0000000..c06640c
--- /dev/null
+++ b/sgd-ui/src/views/system/user/authRole.vue
@@ -0,0 +1,123 @@
+<template>
+ <div class="app-container">
+ <h4 class="form-header h4">基本信息</h4>
+ <el-form ref="form" :model="form" label-width="80px">
+ <el-row>
+ <el-col :span="8" :offset="2">
+ <el-form-item label="用户昵称" prop="nickName">
+ <el-input v-model="form.nickName" disabled />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8" :offset="2">
+ <el-form-item label="登录账号" prop="userName">
+ <el-input v-model="form.userName" disabled />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+
+ <h4 class="form-header h4">角色信息</h4>
+ <el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="table" @selection-change="handleSelectionChange" :data="roles.slice((pageNum-1)*pageSize,pageNum*pageSize)">
+ <el-table-column label="序号" type="index" align="center">
+ <template slot-scope="scope">
+ <span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55" />
+ <el-table-column label="角色编号" align="center" prop="roleId" />
+ <el-table-column label="角色名称" align="center" prop="roleName" />
+ <el-table-column label="权限字符" align="center" prop="roleKey" />
+ <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
+
+ <el-form label-width="100px">
+ <el-form-item style="text-align: center;margin-left:-120px;margin-top:30px;">
+ <el-button type="primary" @click="submitForm()">提交</el-button>
+ <el-button @click="close()">返回</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+</template>
+
+<script>
+import { getAuthRole, updateAuthRole } from "@/api/system/user"
+
+export default {
+ name: "AuthRole",
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 分页信息
+ total: 0,
+ pageNum: 1,
+ pageSize: 10,
+ // 选中角色编号
+ roleIds: [],
+ // 角色信息
+ roles: [],
+ // 用户信息
+ form: {}
+ }
+ },
+ created() {
+ const userId = this.$route.params && this.$route.params.userId
+ if (userId) {
+ this.loading = true
+ getAuthRole(userId).then((response) => {
+ this.form = response.user
+ this.roles = response.roles
+ this.total = this.roles.length
+ this.$nextTick(() => {
+ this.roles.forEach((row) => {
+ if (row.flag) {
+ this.$refs.table.toggleRowSelection(row)
+ }
+ })
+ })
+ this.loading = false
+ })
+ }
+ },
+ methods: {
+ /** 单击选中行数据 */
+ clickRow(row) {
+ if (this.checkSelectable(row)) {
+ this.$refs.table.toggleRowSelection(row)
+ }
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.roleIds = selection.map((item) => item.roleId)
+ },
+ // 保存选中的数据编号
+ getRowKey(row) {
+ return row.roleId
+ },
+ // 检查角色状态
+ checkSelectable(row) {
+ return row.status === "0" ? true : false
+ },
+ /** 提交按钮 */
+ submitForm() {
+ const userId = this.form.userId
+ const roleIds = this.roleIds.join(",")
+ updateAuthRole({ userId: userId, roleIds: roleIds }).then(() => {
+ this.$modal.msgSuccess("授权成功")
+ this.close()
+ })
+ },
+ /** 关闭按钮 */
+ close() {
+ const obj = { path: "/system/user" }
+ this.$tab.closeOpenPage(obj)
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/sgd-ui/src/views/system/user/index.vue b/sgd-ui/src/views/system/user/index.vue
new file mode 100644
index 0000000..b6fd14d
--- /dev/null
+++ b/sgd-ui/src/views/system/user/index.vue
@@ -0,0 +1,467 @@
+<template>
+ <div class="app-container tree-sidebar-manage-wrap">
+ <tree-panel title="组织机构" :tree-data="deptOptions" search-placeholder="请输入部门名称" storage-key="dept-sidebar-width" :defaultExpandAll="true" @node-click="handleNodeClick" @refresh="getDeptTree" ref="deptTreeRef" />
+ <div class="tree-sidebar-content">
+ <div class="content-inner">
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+ <el-form-item label="用户名称" prop="userName">
+ <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
+ </el-form-item>
+ <el-form-item label="手机号码" prop="phonenumber">
+ <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
+ </el-form-item>
+ <el-form-item label="状态" prop="status">
+ <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
+ <el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="创建时间">
+ <el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
+ </el-col>
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
+ </el-row>
+
+ <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="50" align="center" />
+ <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
+ <el-table-column label="用户名称" align="center" key="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true">
+ <template slot-scope="scope">
+ <a class="link-type" style="cursor:pointer" @click="handleViewData(scope.row)">{{ scope.row.userName }}</a>
+ </template>
+ </el-table-column>
+ <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
+ <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
+ <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
+ <el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
+ <template slot-scope="scope">
+ <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
+ </template>
+ </el-table-column>
+ <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns.createTime.visible" width="160">
+ <template slot-scope="scope">
+ <span>{{ parseTime(scope.row.createTime) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
+ <template slot-scope="scope" v-if="scope.row.userId !== 1">
+ <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button>
+ <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button>
+ <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
+ <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
+ <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+ </div>
+ </div>
+
+ <!-- 添加或修改用户配置对话框 -->
+ <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="用户昵称" prop="nickName">
+ <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="归属部门" prop="deptId">
+ <treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="手机号码" prop="phonenumber">
+ <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="邮箱" prop="email">
+ <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
+ <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password" :rules="pwdValidator">
+ <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="用户性别">
+ <el-select v-model="form.sex" placeholder="请选择性别">
+ <el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="状态">
+ <el-radio-group v-model="form.status">
+ <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="岗位">
+ <el-select v-model="form.postIds" multiple placeholder="请选择岗位">
+ <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="角色">
+ <el-select v-model="form.roleIds" multiple placeholder="请选择角色">
+ <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24">
+ <el-form-item label="备注">
+ <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="submitForm">确 定</el-button>
+ <el-button @click="cancel">取 消</el-button>
+ </div>
+ </el-dialog>
+
+ <!-- 用户详情抽屉 -->
+ <user-view-drawer ref="userViewRef" />
+ <!-- 用户导入对话框 -->
+ <excel-import-dialog ref="importUserRef" title="用户导入" action="/system/user/importData" template-action="/system/user/importTemplate" template-file-name="user_template" update-support-label="是否更新已经存在的用户数据" @success="getList" />
+ </div>
+</template>
+
+<script>
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+import TreePanel from "@/components/TreePanel"
+import ExcelImportDialog from "@/components/ExcelImportDialog"
+import UserViewDrawer from "./view"
+import passwordRule from "@/utils/passwordRule"
+
+export default {
+ name: "User",
+ mixins: [passwordRule],
+ dicts: ['sys_normal_disable', 'sys_user_sex'],
+ components: { Treeselect, TreePanel, ExcelImportDialog, UserViewDrawer },
+ data() {
+ return {
+ // 遮罩层
+ loading: true,
+ // 选中数组
+ ids: [],
+ // 非单个禁用
+ single: true,
+ // 非多个禁用
+ multiple: true,
+ // 显示搜索条件
+ showSearch: true,
+ // 总条数
+ total: 0,
+ // 用户表格数据
+ userList: null,
+ // 弹出层标题
+ title: "",
+ // 所有部门树选项
+ deptOptions: undefined,
+ // 过滤掉已禁用部门树选项
+ enabledDeptOptions: undefined,
+ // 是否显示弹出层
+ open: false,
+ // 默认密码
+ initPassword: undefined,
+ // 日期范围
+ dateRange: [],
+ // 岗位选项
+ postOptions: [],
+ // 角色选项
+ roleOptions: [],
+ // 表单参数
+ form: {},
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ userName: undefined,
+ phonenumber: undefined,
+ status: undefined,
+ deptId: undefined
+ },
+ // 列信息
+ columns: {
+ userId: { label: '用户编号', visible: true },
+ userName: { label: '用户名称', visible: true },
+ nickName: { label: '用户昵称', visible: true },
+ deptName: { label: '部门', visible: true },
+ phonenumber: { label: '手机号码', visible: true },
+ status: { label: '状态', visible: true },
+ createTime: { label: '创建时间', visible: true }
+ },
+ // 表单校验
+ rules: {
+ userName: [
+ { required: true, message: "用户名称不能为空", trigger: "blur" },
+ { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
+ ],
+ nickName: [
+ { required: true, message: "用户昵称不能为空", trigger: "blur" }
+ ],
+ email: [
+ {
+ type: "email",
+ message: "请输入正确的邮箱地址",
+ trigger: ["blur", "change"]
+ }
+ ],
+ phonenumber: [
+ {
+ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+ message: "请输入正确的手机号码",
+ trigger: "blur"
+ }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getList()
+ this.getDeptTree()
+ this.getConfigKey("sys.user.initPassword").then(response => {
+ this.initPassword = response.msg
+ })
+ },
+ methods: {
+ /** 查询用户列表 */
+ getList() {
+ this.loading = true
+ listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+ this.userList = response.rows
+ this.total = response.total
+ this.loading = false
+ })
+ },
+ /** 查询部门下拉树结构 */
+ getDeptTree() {
+ deptTreeSelect().then(response => {
+ this.deptOptions = response.data
+ this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
+ })
+ },
+ // 过滤禁用的部门
+ filterDisabledDept(deptList) {
+ return deptList.filter(dept => {
+ if (dept.disabled) {
+ return false
+ }
+ if (dept.children && dept.children.length) {
+ dept.children = this.filterDisabledDept(dept.children)
+ }
+ return true
+ })
+ },
+ // 节点单击事件
+ handleNodeClick(data) {
+ this.queryParams.deptId = data.id
+ this.handleQuery()
+ },
+ // 用户状态修改
+ handleStatusChange(row) {
+ let text = row.status === "0" ? "启用" : "停用"
+ this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
+ return changeUserStatus(row.userId, row.status)
+ }).then(() => {
+ this.$modal.msgSuccess(text + "成功")
+ }).catch(function() {
+ row.status = row.status === "0" ? "1" : "0"
+ })
+ },
+ // 取消按钮
+ cancel() {
+ this.open = false
+ this.reset()
+ },
+ // 表单重置
+ reset() {
+ this.form = {
+ userId: undefined,
+ deptId: undefined,
+ userName: undefined,
+ nickName: undefined,
+ password: undefined,
+ phonenumber: undefined,
+ email: undefined,
+ sex: undefined,
+ status: "0",
+ remark: undefined,
+ postIds: [],
+ roleIds: []
+ }
+ this.resetForm("form")
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.dateRange = []
+ this.resetForm("queryForm")
+ this.queryParams.deptId = undefined
+ this.$refs.deptTreeRef.setCurrentKey(null)
+ this.handleQuery()
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.ids = selection.map(item => item.userId)
+ this.single = selection.length != 1
+ this.multiple = !selection.length
+ },
+ // 更多操作触发
+ handleCommand(command, row) {
+ switch (command) {
+ case "handleResetPwd":
+ this.handleResetPwd(row)
+ break
+ case "handleAuthRole":
+ this.handleAuthRole(row)
+ break
+ default:
+ break
+ }
+ },
+ /** 新增按钮操作 */
+ handleAdd() {
+ this.reset()
+ getUser().then(response => {
+ this.postOptions = response.posts
+ this.roleOptions = response.roles
+ this.open = true
+ this.title = "添加用户"
+ this.form.password = this.initPassword
+ })
+ },
+ /** 修改按钮操作 */
+ handleUpdate(row) {
+ this.reset()
+ const userId = row.userId || this.ids
+ getUser(userId).then(response => {
+ this.form = response.data
+ this.postOptions = response.posts
+ this.roleOptions = response.roles
+ this.$set(this.form, "postIds", response.postIds)
+ this.$set(this.form, "roleIds", response.roleIds)
+ this.open = true
+ this.title = "修改用户"
+ this.form.password = ""
+ })
+ },
+ /** 重置密码按钮操作 */
+ handleResetPwd(row) {
+ this.$prompt(`请输入「${row.userName}」的新密码`, "重置密码", {
+ confirmButtonText: "确定",
+ cancelButtonText: "取消",
+ closeOnClickModal: false,
+ inputValidator: this.pwdPromptValidator
+ }).then(({ value }) => {
+ resetUserPwd(row.userId, value).then(() => {
+ this.$modal.msgSuccess("修改成功,新密码是:" + value)
+ })
+ }).catch(() => {})
+ },
+ /** 分配角色操作 */
+ handleAuthRole(row) {
+ const userId = row.userId
+ this.$router.push("/system/user-auth/role/" + userId)
+ },
+ /** 提交按钮 */
+ submitForm() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ if (this.form.userId != undefined) {
+ updateUser(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.open = false
+ this.getList()
+ })
+ } else {
+ addUser(this.form).then(() => {
+ this.$modal.msgSuccess("新增成功")
+ this.open = false
+ this.getList()
+ })
+ }
+ }
+ })
+ },
+ /** 删除按钮操作 */
+ handleDelete(row) {
+ const userIds = row.userId || this.ids
+ this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
+ return delUser(userIds)
+ }).then(() => {
+ this.getList()
+ this.$modal.msgSuccess("删除成功")
+ }).catch(() => {})
+ },
+ /** 导出按钮操作 */
+ handleExport() {
+ this.download('system/user/export', {
+ ...this.queryParams
+ }, `user_${new Date().getTime()}.xlsx`)
+ },
+ /** 详情按钮操作 */
+ handleViewData(row) {
+ this.$refs.userViewRef.open(row.userId)
+ },
+ /** 导入按钮操作 */
+ handleImport() {
+ this.$refs.importUserRef.open()
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/index.vue b/sgd-ui/src/views/system/user/profile/index.vue
similarity index 100%
rename from ruoyi-ui/src/views/system/user/profile/index.vue
rename to sgd-ui/src/views/system/user/profile/index.vue
diff --git a/sgd-ui/src/views/system/user/profile/resetPwd.vue b/sgd-ui/src/views/system/user/profile/resetPwd.vue
new file mode 100644
index 0000000..edbb227
--- /dev/null
+++ b/sgd-ui/src/views/system/user/profile/resetPwd.vue
@@ -0,0 +1,70 @@
+<template>
+ <el-form ref="form" :model="user" :rules="formRules" label-width="80px">
+ <el-form-item label="旧密码" prop="oldPassword">
+ <el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password/>
+ </el-form-item>
+ <el-form-item label="新密码" prop="newPassword" :rules="infoPwdValidator">
+ <el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password/>
+ </el-form-item>
+ <el-form-item label="确认密码" prop="confirmPassword">
+ <el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" size="mini" @click="submit">保存</el-button>
+ <el-button type="danger" size="mini" @click="close">关闭</el-button>
+ </el-form-item>
+ </el-form>
+</template>
+
+<script>
+import { updateUserPwd } from "@/api/system/user"
+import passwordRule from "@/utils/passwordRule"
+
+export default {
+ mixins: [passwordRule],
+ data() {
+ return {
+ user: {
+ oldPassword: undefined,
+ newPassword: undefined,
+ confirmPassword: undefined
+ }
+ }
+ },
+ computed: {
+ formRules() {
+ return {
+ oldPassword: [
+ { required: true, message: "旧密码不能为空", trigger: "blur" }
+ ],
+ confirmPassword: [
+ { required: true, message: "确认密码不能为空", trigger: "blur" },
+ {
+ validator: (rule, value, callback) => {
+ if (this.user.newPassword !== value) {
+ callback(new Error("两次输入的密码不一致"))
+ } else {
+ callback()
+ }
+ }, trigger: "blur"
+ }
+ ]
+ }
+ }
+ },
+ methods: {
+ submit() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ updateUserPwd(this.user.oldPassword, this.user.newPassword).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ })
+ }
+ })
+ },
+ close() {
+ this.$tab.closePage()
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/system/user/profile/userAvatar.vue b/sgd-ui/src/views/system/user/profile/userAvatar.vue
new file mode 100644
index 0000000..b4e1593
--- /dev/null
+++ b/sgd-ui/src/views/system/user/profile/userAvatar.vue
@@ -0,0 +1,184 @@
+<template>
+ <div>
+ <div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
+ <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
+ <el-row>
+ <el-col :xs="24" :md="12" :style="{height: '350px'}">
+ <vue-cropper
+ ref="cropper"
+ :img="options.img"
+ :info="true"
+ :autoCrop="options.autoCrop"
+ :autoCropWidth="options.autoCropWidth"
+ :autoCropHeight="options.autoCropHeight"
+ :fixedBox="options.fixedBox"
+ :outputType="options.outputType"
+ @realTime="realTime"
+ v-if="visible"
+ />
+ </el-col>
+ <el-col :xs="24" :md="12" :style="{height: '350px'}">
+ <div class="avatar-upload-preview">
+ <img :src="previews.url" :style="previews.img" />
+ </div>
+ </el-col>
+ </el-row>
+ <br />
+ <el-row>
+ <el-col :lg="2" :sm="3" :xs="3">
+ <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
+ <el-button size="small">
+ 选择
+ <i class="el-icon-upload el-icon--right"></i>
+ </el-button>
+ </el-upload>
+ </el-col>
+ <el-col :lg="{span: 1, offset: 2}" :sm="2" :xs="2">
+ <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
+ </el-col>
+ <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+ <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
+ </el-col>
+ <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+ <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
+ </el-col>
+ <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+ <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
+ </el-col>
+ <el-col :lg="{span: 2, offset: 6}" :sm="2" :xs="2">
+ <el-button type="primary" size="small" @click="uploadImg()">提 交</el-button>
+ </el-col>
+ </el-row>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import store from "@/store"
+import { VueCropper } from "vue-cropper"
+import { uploadAvatar } from "@/api/system/user"
+import { debounce } from '@/utils'
+
+export default {
+ components: { VueCropper },
+ data() {
+ return {
+ // 是否显示弹出层
+ open: false,
+ // 是否显示cropper
+ visible: false,
+ // 弹出层标题
+ title: "修改头像",
+ options: {
+ img: store.getters.avatar, //裁剪图片的地址
+ autoCrop: true, // 是否默认生成截图框
+ autoCropWidth: 200, // 默认生成截图框宽度
+ autoCropHeight: 200, // 默认生成截图框高度
+ fixedBox: true, // 固定截图框大小 不允许改变
+ outputType:"png", // 默认生成截图为PNG格式
+ filename: 'avatar' // 文件名称
+ },
+ previews: {},
+ resizeHandler: null
+ }
+ },
+ methods: {
+ // 编辑头像
+ editCropper() {
+ this.open = true
+ },
+ // 打开弹出层结束时的回调
+ modalOpened() {
+ this.visible = true
+ if (!this.resizeHandler) {
+ this.resizeHandler = debounce(() => {
+ this.refresh()
+ }, 100)
+ }
+ window.addEventListener("resize", this.resizeHandler)
+ },
+ // 刷新组件
+ refresh() {
+ this.$refs.cropper.refresh()
+ },
+ // 覆盖默认的上传行为
+ requestUpload() {
+ },
+ // 向左旋转
+ rotateLeft() {
+ this.$refs.cropper.rotateLeft()
+ },
+ // 向右旋转
+ rotateRight() {
+ this.$refs.cropper.rotateRight()
+ },
+ // 图片缩放
+ changeScale(num) {
+ num = num || 1
+ this.$refs.cropper.changeScale(num)
+ },
+ // 上传预处理
+ beforeUpload(file) {
+ if (file.type.indexOf("image/") == -1) {
+ this.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。")
+ } else {
+ const reader = new FileReader()
+ reader.readAsDataURL(file)
+ reader.onload = () => {
+ this.options.img = reader.result
+ this.options.filename = file.name
+ }
+ }
+ },
+ // 上传图片
+ uploadImg() {
+ this.$refs.cropper.getCropBlob(data => {
+ let formData = new FormData()
+ formData.append("avatarfile", data, this.options.filename)
+ uploadAvatar(formData).then(response => {
+ this.open = false
+ this.options.img = response.imgUrl
+ store.commit('SET_AVATAR', this.options.img)
+ this.$modal.msgSuccess("修改成功")
+ this.visible = false
+ })
+ })
+ },
+ // 实时预览
+ realTime(data) {
+ this.previews = data
+ },
+ // 关闭窗口
+ closeDialog() {
+ this.options.img = store.getters.avatar
+ this.visible = false
+ window.removeEventListener("resize", this.resizeHandler)
+ }
+ }
+}
+</script>
+<style scoped lang="scss">
+.user-info-head {
+ position: relative;
+ display: inline-block;
+ height: 120px;
+}
+
+.user-info-head:hover:after {
+ content: '+';
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ color: #eee;
+ background: rgba(0, 0, 0, 0.5);
+ font-size: 24px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ cursor: pointer;
+ line-height: 110px;
+ border-radius: 50%;
+}
+</style>
diff --git a/sgd-ui/src/views/system/user/profile/userInfo.vue b/sgd-ui/src/views/system/user/profile/userInfo.vue
new file mode 100644
index 0000000..0819318
--- /dev/null
+++ b/sgd-ui/src/views/system/user/profile/userInfo.vue
@@ -0,0 +1,88 @@
+<template>
+ <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+ <el-form-item label="用户昵称" prop="nickName">
+ <el-input v-model="form.nickName" maxlength="30" />
+ </el-form-item>
+ <el-form-item label="手机号码" prop="phonenumber">
+ <el-input v-model="form.phonenumber" maxlength="11" />
+ </el-form-item>
+ <el-form-item label="邮箱" prop="email">
+ <el-input v-model="form.email" maxlength="50" />
+ </el-form-item>
+ <el-form-item label="性别">
+ <el-radio-group v-model="form.sex">
+ <el-radio label="0">男</el-radio>
+ <el-radio label="1">女</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" size="mini" @click="submit">保存</el-button>
+ <el-button type="danger" size="mini" @click="close">关闭</el-button>
+ </el-form-item>
+ </el-form>
+</template>
+
+<script>
+import { updateUserProfile } from "@/api/system/user"
+
+export default {
+ props: {
+ user: {
+ type: Object
+ }
+ },
+ data() {
+ return {
+ form: {},
+ // 表单校验
+ rules: {
+ nickName: [
+ { required: true, message: "用户昵称不能为空", trigger: "blur" }
+ ],
+ email: [
+ { required: true, message: "邮箱地址不能为空", trigger: "blur" },
+ {
+ type: "email",
+ message: "请输入正确的邮箱地址",
+ trigger: ["blur", "change"]
+ }
+ ],
+ phonenumber: [
+ { required: true, message: "手机号码不能为空", trigger: "blur" },
+ {
+ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+ message: "请输入正确的手机号码",
+ trigger: "blur"
+ }
+ ]
+ }
+ }
+ },
+ watch: {
+ user: {
+ handler(user) {
+ if (user) {
+ this.form = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex }
+ }
+ },
+ immediate: true
+ }
+ },
+ methods: {
+ submit() {
+ this.$refs["form"].validate(valid => {
+ if (valid) {
+ updateUserProfile(this.form).then(() => {
+ this.$modal.msgSuccess("修改成功")
+ this.user.phonenumber = this.form.phonenumber
+ this.user.email = this.form.email
+ })
+ }
+ })
+ },
+ close() {
+ this.$tab.closePage()
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/views/system/user/view.vue b/sgd-ui/src/views/system/user/view.vue
similarity index 100%
rename from ruoyi-ui/src/views/system/user/view.vue
rename to sgd-ui/src/views/system/user/view.vue
diff --git a/sgd-ui/src/views/tool/build/CodeTypeDialog.vue b/sgd-ui/src/views/tool/build/CodeTypeDialog.vue
new file mode 100644
index 0000000..b5c2e2e
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/CodeTypeDialog.vue
@@ -0,0 +1,106 @@
+<template>
+ <div>
+ <el-dialog
+ v-bind="$attrs"
+ width="500px"
+ :close-on-click-modal="false"
+ :modal-append-to-body="false"
+ v-on="$listeners"
+ @open="onOpen"
+ @close="onClose"
+ >
+ <el-row :gutter="15">
+ <el-form
+ ref="elForm"
+ :model="formData"
+ :rules="rules"
+ size="medium"
+ label-width="100px"
+ >
+ <el-col :span="24">
+ <el-form-item label="生成类型" prop="type">
+ <el-radio-group v-model="formData.type">
+ <el-radio-button
+ v-for="(item, index) in typeOptions"
+ :key="index"
+ :label="item.value"
+ :disabled="item.disabled"
+ >
+ {{ item.label }}
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="showFileName" label="文件名" prop="fileName">
+ <el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
+ </el-form-item>
+ </el-col>
+ </el-form>
+ </el-row>
+
+ <div slot="footer">
+ <el-button @click="close">
+ 取消
+ </el-button>
+ <el-button type="primary" @click="handleConfirm">
+ 确定
+ </el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+<script>
+export default {
+ inheritAttrs: false,
+ props: ['showFileName'],
+ data() {
+ return {
+ formData: {
+ fileName: undefined,
+ type: 'file'
+ },
+ rules: {
+ fileName: [{
+ required: true,
+ message: '请输入文件名',
+ trigger: 'blur'
+ }],
+ type: [{
+ required: true,
+ message: '生成类型不能为空',
+ trigger: 'change'
+ }]
+ },
+ typeOptions: [{
+ label: '页面',
+ value: 'file'
+ }, {
+ label: '弹窗',
+ value: 'dialog'
+ }]
+ }
+ },
+ computed: {
+ },
+ watch: {},
+ mounted() {},
+ methods: {
+ onOpen() {
+ if (this.showFileName) {
+ this.formData.fileName = `${+new Date()}.vue`
+ }
+ },
+ onClose() {
+ },
+ close(e) {
+ this.$emit('update:visible', false)
+ },
+ handleConfirm() {
+ this.$refs.elForm.validate(valid => {
+ if (!valid) return
+ this.$emit('confirm', { ...this.formData })
+ this.close()
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/build/DraggableItem.vue b/sgd-ui/src/views/tool/build/DraggableItem.vue
new file mode 100644
index 0000000..e881778
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/DraggableItem.vue
@@ -0,0 +1,100 @@
+<script>
+import draggable from 'vuedraggable'
+import render from '@/utils/generator/render'
+
+const components = {
+ itemBtns(h, element, index, parent) {
+ const { copyItem, deleteItem } = this.$listeners
+ return [
+ <span class="drawing-item-copy" title="复制" onClick={event => {
+ copyItem(element, parent); event.stopPropagation()
+ }}>
+ <i class="el-icon-copy-document" />
+ </span>,
+ <span class="drawing-item-delete" title="删除" onClick={event => {
+ deleteItem(index, parent); event.stopPropagation()
+ }}>
+ <i class="el-icon-delete" />
+ </span>
+ ]
+ }
+}
+const layouts = {
+ colFormItem(h, element, index, parent) {
+ const { activeItem } = this.$listeners
+ let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
+ if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
+ return (
+ <el-col span={element.span} class={className}
+ nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
+ <el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
+ label={element.label} required={element.required}>
+ <render key={element.renderKey} conf={element} onInput={ event => {
+ this.$set(element, 'defaultValue', event)
+ }} />
+ </el-form-item>
+ {components.itemBtns.apply(this, arguments)}
+ </el-col>
+ )
+ },
+ rowFormItem(h, element, index, parent) {
+ const { activeItem } = this.$listeners
+ const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
+ let child = renderChildren.apply(this, arguments)
+ if (element.type === 'flex') {
+ child = <el-row type={element.type} justify={element.justify} align={element.align}>
+ {child}
+ </el-row>
+ }
+ return (
+ <el-col span={element.span}>
+ <el-row gutter={element.gutter} class={className}
+ nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
+ <span class="component-name">{element.componentName}</span>
+ <draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
+ {child}
+ </draggable>
+ {components.itemBtns.apply(this, arguments)}
+ </el-row>
+ </el-col>
+ )
+ }
+}
+
+function renderChildren(h, element, index, parent) {
+ if (!Array.isArray(element.children)) return null
+ return element.children.map((el, i) => {
+ const layout = layouts[el.layout]
+ if (layout) {
+ return layout.call(this, h, el, i, element.children)
+ }
+ return layoutIsNotFound()
+ })
+}
+
+function layoutIsNotFound() {
+ throw new Error(`没有与${this.element.layout}匹配的layout`)
+}
+
+export default {
+ components: {
+ render,
+ draggable
+ },
+ props: [
+ 'element',
+ 'index',
+ 'drawingList',
+ 'activeId',
+ 'formConf'
+ ],
+ render(h) {
+ const layout = layouts[this.element.layout]
+
+ if (layout) {
+ return layout.call(this, h, this.element, this.index, this.drawingList)
+ }
+ return layoutIsNotFound()
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/build/IconsDialog.vue b/sgd-ui/src/views/tool/build/IconsDialog.vue
new file mode 100644
index 0000000..958be50
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/IconsDialog.vue
@@ -0,0 +1,123 @@
+<template>
+ <div class="icon-dialog">
+ <el-dialog
+ v-bind="$attrs"
+ width="980px"
+ :modal-append-to-body="false"
+ v-on="$listeners"
+ @open="onOpen"
+ @close="onClose"
+ >
+ <div slot="title">
+ 选择图标
+ <el-input
+ v-model="key"
+ size="mini"
+ :style="{width: '260px'}"
+ placeholder="请输入图标名称"
+ prefix-icon="el-icon-search"
+ clearable
+ />
+ </div>
+ <ul class="icon-ul">
+ <li
+ v-for="icon in iconList"
+ :key="icon"
+ :class="active===icon?'active-item':''"
+ @click="onSelect(icon)"
+ >
+ <i :class="icon" />
+ <div>{{ icon }}</div>
+ </li>
+ </ul>
+ </el-dialog>
+ </div>
+</template>
+<script>
+import iconList from '@/utils/generator/icon.json'
+
+const originList = iconList.map(name => `el-icon-${name}`)
+
+export default {
+ inheritAttrs: false,
+ props: ['current'],
+ data() {
+ return {
+ iconList: originList,
+ active: null,
+ key: ''
+ }
+ },
+ watch: {
+ key(val) {
+ if (val) {
+ this.iconList = originList.filter(name => name.indexOf(val) > -1)
+ } else {
+ this.iconList = originList
+ }
+ }
+ },
+ methods: {
+ onOpen() {
+ this.active = this.current
+ this.key = ''
+ },
+ onClose() {},
+ onSelect(icon) {
+ this.active = icon
+ this.$emit('select', icon)
+ this.$emit('update:visible', false)
+ }
+ }
+}
+</script>
+<style lang="scss" scoped>
+.icon-ul {
+ margin: 0;
+ padding: 0;
+ font-size: 0;
+ li {
+ list-style-type: none;
+ text-align: center;
+ font-size: 14px;
+ display: inline-block;
+ width: 16.66%;
+ box-sizing: border-box;
+ height: 108px;
+ padding: 15px 6px 6px 6px;
+ cursor: pointer;
+ overflow: hidden;
+ &:hover {
+ background: #f2f2f2;
+ }
+ &.active-item{
+ background: #e1f3fb;
+ color: #7a6df0
+ }
+ > i {
+ font-size: 30px;
+ line-height: 50px;
+ }
+ }
+}
+.icon-dialog {
+ ::v-deep .el-dialog {
+ border-radius: 8px;
+ margin-bottom: 0;
+ margin-top: 4vh !important;
+ display: flex;
+ flex-direction: column;
+ max-height: 92vh;
+ overflow: hidden;
+ box-sizing: border-box;
+ .el-dialog__header {
+ padding-top: 14px;
+ }
+ .el-dialog__body {
+ margin: 0 20px 20px 20px;
+ padding: 0;
+ overflow: auto;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/views/tool/build/RightPanel.vue b/sgd-ui/src/views/tool/build/RightPanel.vue
new file mode 100644
index 0000000..c2760eb
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/RightPanel.vue
@@ -0,0 +1,946 @@
+<template>
+ <div class="right-board">
+ <el-tabs v-model="currentTab" class="center-tabs">
+ <el-tab-pane label="组件属性" name="field" />
+ <el-tab-pane label="表单属性" name="form" />
+ </el-tabs>
+ <div class="field-box">
+ <a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
+ <i class="el-icon-link" />
+ </a>
+ <el-scrollbar class="right-scrollbar">
+ <!-- 组件属性 -->
+ <el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
+ <el-form-item v-if="activeData.changeTag" label="组件类型">
+ <el-select
+ v-model="activeData.tagIcon"
+ placeholder="请选择组件类型"
+ :style="{width: '100%'}"
+ @change="tagChange"
+ >
+ <el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
+ <el-option
+ v-for="item in group.options"
+ :key="item.label"
+ :label="item.label"
+ :value="item.tagIcon"
+ >
+ <svg-icon class="node-icon" :icon-class="item.tagIcon" />
+ <span> {{ item.label }}</span>
+ </el-option>
+ </el-option-group>
+ </el-select>
+ </el-form-item>
+ <el-form-item v-if="activeData.vModel!==undefined" label="字段名">
+ <el-input v-model="activeData.vModel" placeholder="请输入字段名(v-model)" />
+ </el-form-item>
+ <el-form-item v-if="activeData.componentName!==undefined" label="组件名">
+ {{ activeData.componentName }}
+ </el-form-item>
+ <el-form-item v-if="activeData.label!==undefined" label="标题">
+ <el-input v-model="activeData.label" placeholder="请输入标题" />
+ </el-form-item>
+ <el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
+ <el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
+ </el-form-item>
+ <el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
+ <el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
+ </el-form-item>
+ <el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
+ <el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
+ </el-form-item>
+ <el-form-item v-if="activeData.span!==undefined" label="表单栅格">
+ <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
+ </el-form-item>
+ <el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔">
+ <el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
+ </el-form-item>
+ <el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式">
+ <el-radio-group v-model="activeData.type">
+ <el-radio-button label="default" />
+ <el-radio-button label="flex" />
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="水平排列">
+ <el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{width: '100%'}">
+ <el-option
+ v-for="(item, index) in justifyOptions"
+ :key="index"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="垂直排列">
+ <el-radio-group v-model="activeData.align">
+ <el-radio-button label="top" />
+ <el-radio-button label="middle" />
+ <el-radio-button label="bottom" />
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度">
+ <el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
+ </el-form-item>
+ <el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
+ <el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
+ </el-form-item>
+ <el-form-item v-if="activeData.vModel!==undefined" label="默认值">
+ <el-input
+ :value="setDefaultValue(activeData.defaultValue)"
+ placeholder="请输入默认值"
+ @input="onDefaultValueInput"
+ />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选">
+ <el-input-number
+ :value="activeData.min"
+ :min="0"
+ placeholder="至少应选"
+ @input="$set(activeData, 'min', $event?$event:undefined)"
+ />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选">
+ <el-input-number
+ :value="activeData.max"
+ :min="0"
+ placeholder="最多可选"
+ @input="$set(activeData, 'max', $event?$event:undefined)"
+ />
+ </el-form-item>
+ <el-form-item v-if="activeData.prepend!==undefined" label="前缀">
+ <el-input v-model="activeData.prepend" placeholder="请输入前缀" />
+ </el-form-item>
+ <el-form-item v-if="activeData.append!==undefined" label="后缀">
+ <el-input v-model="activeData.append" placeholder="请输入后缀" />
+ </el-form-item>
+ <el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
+ <el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
+ <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')">
+ 选择
+ </el-button>
+ </el-input>
+ </el-form-item>
+ <el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
+ <el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
+ <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')">
+ 选择
+ </el-button>
+ </el-input>
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
+ <el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
+ </el-form-item>
+ <el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
+ <el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
+ </el-form-item>
+ <el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
+ <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
+ </el-form-item>
+ <el-form-item v-if="activeData.min !== undefined" label="最小值">
+ <el-input-number v-model="activeData.min" placeholder="最小值" />
+ </el-form-item>
+ <el-form-item v-if="activeData.max !== undefined" label="最大值">
+ <el-input-number v-model="activeData.max" placeholder="最大值" />
+ </el-form-item>
+ <el-form-item v-if="activeData.step !== undefined" label="步长">
+ <el-input-number v-model="activeData.step" placeholder="步数" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
+ <el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
+ <el-radio-group v-model="activeData['controls-position']">
+ <el-radio-button label="">
+ 默认
+ </el-radio-button>
+ <el-radio-button label="right">
+ 右侧
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
+ <el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
+ <template slot="append">
+ 个字符
+ </template>
+ </el-input>
+ </el-form-item>
+ <el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
+ <el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
+ </el-form-item>
+ <el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
+ <el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
+ </el-form-item>
+ <el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
+ <el-input
+ :value="setDefaultValue(activeData['active-value'])"
+ placeholder="请输入开启值"
+ @input="onSwitchValueInput($event, 'active-value')"
+ />
+ </el-form-item>
+ <el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
+ <el-input
+ :value="setDefaultValue(activeData['inactive-value'])"
+ placeholder="请输入关闭值"
+ @input="onSwitchValueInput($event, 'inactive-value')"
+ />
+ </el-form-item>
+ <el-form-item
+ v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
+ label="时间类型"
+ >
+ <el-select
+ v-model="activeData.type"
+ placeholder="请选择时间类型"
+ :style="{ width: '100%' }"
+ @change="dateTypeChange"
+ >
+ <el-option
+ v-for="(item, index) in dateOptions"
+ :key="index"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item v-if="activeData.name !== undefined" label="文件字段名">
+ <el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
+ </el-form-item>
+ <el-form-item v-if="activeData.accept !== undefined" label="文件类型">
+ <el-select
+ v-model="activeData.accept"
+ placeholder="请选择文件类型"
+ :style="{ width: '100%' }"
+ clearable
+ >
+ <el-option label="图片" value="image/*" />
+ <el-option label="视频" value="video/*" />
+ <el-option label="音频" value="audio/*" />
+ <el-option label="excel" value=".xls,.xlsx" />
+ <el-option label="word" value=".doc,.docx" />
+ <el-option label="pdf" value=".pdf" />
+ <el-option label="txt" value=".txt" />
+ </el-select>
+ </el-form-item>
+ <el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
+ <el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
+ <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
+ <el-option label="KB" value="KB" />
+ <el-option label="MB" value="MB" />
+ <el-option label="GB" value="GB" />
+ </el-select>
+ </el-input>
+ </el-form-item>
+ <el-form-item v-if="activeData.action !== undefined" label="上传地址">
+ <el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
+ </el-form-item>
+ <el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
+ <el-radio-group v-model="activeData['list-type']" size="small">
+ <el-radio-button label="text">
+ text
+ </el-radio-button>
+ <el-radio-button label="picture">
+ picture
+ </el-radio-button>
+ <el-radio-button label="picture-card">
+ picture-card
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item
+ v-if="activeData.buttonText !== undefined"
+ v-show="'picture-card' !== activeData['list-type']"
+ label="按钮文字"
+ >
+ <el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
+ </el-form-item>
+ <el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
+ <el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
+ </el-form-item>
+ <el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
+ <el-input
+ v-model="activeData['picker-options'].selectableRange"
+ placeholder="请输入时间段"
+ />
+ </el-form-item>
+ <el-form-item v-if="activeData.format !== undefined" label="时间格式">
+ <el-input
+ :value="activeData.format"
+ placeholder="请输入时间格式"
+ @input="setTimeValue($event)"
+ />
+ </el-form-item>
+ <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
+ <el-divider>选项</el-divider>
+ <draggable
+ :list="activeData.options"
+ :animation="340"
+ group="selectItem"
+ handle=".option-drag"
+ >
+ <div v-for="(item, index) in activeData.options" :key="index" class="select-item">
+ <div class="select-line-icon option-drag">
+ <i class="el-icon-s-operation" />
+ </div>
+ <el-input v-model="item.label" placeholder="选项名" size="small" />
+ <el-input
+ placeholder="选项值"
+ size="small"
+ :value="item.value"
+ @input="setOptionValue(item, $event)"
+ />
+ <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
+ <i class="el-icon-remove-outline" />
+ </div>
+ </div>
+ </draggable>
+ <div style="margin-left: 20px;">
+ <el-button
+ style="padding-bottom: 0"
+ icon="el-icon-circle-plus-outline"
+ type="text"
+ @click="addSelectItem"
+ >
+ 添加选项
+ </el-button>
+ </div>
+ <el-divider />
+ </template>
+
+ <template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
+ <el-divider>选项</el-divider>
+ <el-form-item label="数据类型">
+ <el-radio-group v-model="activeData.dataType" size="small">
+ <el-radio-button label="dynamic">
+ 动态数据
+ </el-radio-button>
+ <el-radio-button label="static">
+ 静态数据
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+
+ <template v-if="activeData.dataType === 'dynamic'">
+ <el-form-item label="标签键名">
+ <el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
+ </el-form-item>
+ <el-form-item label="值键名">
+ <el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
+ </el-form-item>
+ <el-form-item label="子级键名">
+ <el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
+ </el-form-item>
+ </template>
+
+ <el-tree
+ v-if="activeData.dataType === 'static'"
+ draggable
+ :data="activeData.options"
+ node-key="id"
+ :expand-on-click-node="false"
+ :render-content="renderContent"
+ />
+ <div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
+ <el-button
+ style="padding-bottom: 0"
+ icon="el-icon-circle-plus-outline"
+ type="text"
+ @click="addTreeItem"
+ >
+ 添加父级
+ </el-button>
+ </div>
+ <el-divider />
+ </template>
+
+ <el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
+ <el-radio-group v-model="activeData.optionType">
+ <el-radio-button label="default">
+ 默认
+ </el-radio-button>
+ <el-radio-button label="button">
+ 按钮
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
+ <el-color-picker v-model="activeData['active-color']" />
+ </el-form-item>
+ <el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
+ <el-color-picker v-model="activeData['inactive-color']" />
+ </el-form-item>
+
+ <el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
+ <el-switch v-model="activeData['allow-half']" />
+ </el-form-item>
+ <el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
+ <el-switch v-model="activeData['show-text']" @change="rateTextChange" />
+ </el-form-item>
+ <el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
+ <el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
+ </el-form-item>
+ <el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
+ <el-switch v-model="activeData['show-stops']" />
+ </el-form-item>
+ <el-form-item v-if="activeData.range !== undefined" label="范围选择">
+ <el-switch v-model="activeData.range" @change="rangeChange" />
+ </el-form-item>
+ <el-form-item
+ v-if="activeData.border !== undefined && activeData.optionType === 'default'"
+ label="是否带边框"
+ >
+ <el-switch v-model="activeData.border" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
+ <el-select
+ v-model="activeData['color-format']"
+ placeholder="请选择颜色格式"
+ :style="{ width: '100%' }"
+ @change="colorFormatChange"
+ >
+ <el-option
+ v-for="(item, index) in colorFormatOptions"
+ :key="index"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item
+ v-if="activeData.size !== undefined &&
+ (activeData.optionType === 'button' ||
+ activeData.border ||
+ activeData.tag === 'el-color-picker')"
+ label="选项尺寸"
+ >
+ <el-radio-group v-model="activeData.size">
+ <el-radio-button label="medium">
+ 中等
+ </el-radio-button>
+ <el-radio-button label="small">
+ 较小
+ </el-radio-button>
+ <el-radio-button label="mini">
+ 迷你
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
+ <el-switch v-model="activeData['show-word-limit']" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
+ <el-switch v-model="activeData['step-strictly']" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
+ <el-switch v-model="activeData.props.props.multiple" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
+ <el-switch v-model="activeData['show-all-levels']" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
+ <el-switch v-model="activeData.filterable" />
+ </el-form-item>
+ <el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
+ <el-switch v-model="activeData.clearable" />
+ </el-form-item>
+ <el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
+ <el-switch v-model="activeData.showTip" />
+ </el-form-item>
+ <el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
+ <el-switch v-model="activeData.multiple" />
+ </el-form-item>
+ <el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
+ <el-switch v-model="activeData['auto-upload']" />
+ </el-form-item>
+ <el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
+ <el-switch v-model="activeData.readonly" />
+ </el-form-item>
+ <el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
+ <el-switch v-model="activeData.disabled" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
+ <el-switch v-model="activeData.filterable" />
+ </el-form-item>
+ <el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
+ <el-switch v-model="activeData.multiple" @change="multipleChange" />
+ </el-form-item>
+ <el-form-item v-if="activeData.required !== undefined" label="是否必填">
+ <el-switch v-model="activeData.required" />
+ </el-form-item>
+
+ <template v-if="activeData.layoutTree">
+ <el-divider>布局结构树</el-divider>
+ <el-tree
+ :data="[activeData]"
+ :props="layoutTreeProps"
+ node-key="renderKey"
+ default-expand-all
+ draggable
+ >
+ <span slot-scope="{ node, data }">
+ <span class="node-label">
+ <svg-icon class="node-icon" :icon-class="data.tagIcon" />
+ {{ node.label }}
+ </span>
+ </span>
+ </el-tree>
+ </template>
+
+ <template v-if="activeData.layout === 'colFormItem' && activeData.tag !== 'el-button'">
+ <el-divider>正则校验</el-divider>
+ <div
+ v-for="(item, index) in activeData.regList"
+ :key="index"
+ class="reg-item"
+ >
+ <span class="close-btn" @click="activeData.regList.splice(index, 1)">
+ <i class="el-icon-close" />
+ </span>
+ <el-form-item label="表达式">
+ <el-input v-model="item.pattern" placeholder="请输入正则" />
+ </el-form-item>
+ <el-form-item label="错误提示" style="margin-bottom:0">
+ <el-input v-model="item.message" placeholder="请输入错误提示" />
+ </el-form-item>
+ </div>
+ <div style="margin-left: 20px">
+ <el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
+ 添加规则
+ </el-button>
+ </div>
+ </template>
+ </el-form>
+ <!-- 表单属性 -->
+ <el-form v-show="currentTab === 'form'" size="small" label-width="90px">
+ <el-form-item label="表单名">
+ <el-input v-model="formConf.formRef" placeholder="请输入表单名(ref)" />
+ </el-form-item>
+ <el-form-item label="表单模型">
+ <el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
+ </el-form-item>
+ <el-form-item label="校验模型">
+ <el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
+ </el-form-item>
+ <el-form-item label="表单尺寸">
+ <el-radio-group v-model="formConf.size">
+ <el-radio-button label="medium">
+ 中等
+ </el-radio-button>
+ <el-radio-button label="small">
+ 较小
+ </el-radio-button>
+ <el-radio-button label="mini">
+ 迷你
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="标签对齐">
+ <el-radio-group v-model="formConf.labelPosition">
+ <el-radio-button label="left">
+ 左对齐
+ </el-radio-button>
+ <el-radio-button label="right">
+ 右对齐
+ </el-radio-button>
+ <el-radio-button label="top">
+ 顶部对齐
+ </el-radio-button>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="标签宽度">
+ <el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
+ </el-form-item>
+ <el-form-item label="栅格间隔">
+ <el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
+ </el-form-item>
+ <el-form-item label="禁用表单">
+ <el-switch v-model="formConf.disabled" />
+ </el-form-item>
+ <el-form-item label="表单按钮">
+ <el-switch v-model="formConf.formBtns" />
+ </el-form-item>
+ <el-form-item label="显示未选中组件边框">
+ <el-switch v-model="formConf.unFocusedComponentBorder" />
+ </el-form-item>
+ </el-form>
+ </el-scrollbar>
+ </div>
+
+ <treeNode-dialog :visible.sync="dialogVisible" title="添加选项" @commit="addNode" />
+ <icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
+ </div>
+</template>
+
+<script>
+import { isArray } from 'util'
+import draggable from 'vuedraggable'
+import TreeNodeDialog from './TreeNodeDialog'
+import { isNumberStr } from '@/utils/index'
+import IconsDialog from './IconsDialog'
+import {
+ inputComponents,
+ selectComponents,
+ layoutComponents
+} from '@/utils/generator/config'
+
+const dateTimeFormat = {
+ date: 'yyyy-MM-dd',
+ week: 'yyyy 第 WW 周',
+ month: 'yyyy-MM',
+ year: 'yyyy',
+ datetime: 'yyyy-MM-dd HH:mm:ss',
+ daterange: 'yyyy-MM-dd',
+ monthrange: 'yyyy-MM',
+ datetimerange: 'yyyy-MM-dd HH:mm:ss'
+}
+
+export default {
+ components: {
+ draggable,
+ TreeNodeDialog,
+ IconsDialog
+ },
+ props: ['showField', 'activeData', 'formConf'],
+ data() {
+ return {
+ currentTab: 'field',
+ currentNode: null,
+ dialogVisible: false,
+ iconsVisible: false,
+ currentIconModel: null,
+ dateTypeOptions: [
+ {
+ label: '日(date)',
+ value: 'date'
+ },
+ {
+ label: '周(week)',
+ value: 'week'
+ },
+ {
+ label: '月(month)',
+ value: 'month'
+ },
+ {
+ label: '年(year)',
+ value: 'year'
+ },
+ {
+ label: '日期时间(datetime)',
+ value: 'datetime'
+ }
+ ],
+ dateRangeTypeOptions: [
+ {
+ label: '日期范围(daterange)',
+ value: 'daterange'
+ },
+ {
+ label: '月范围(monthrange)',
+ value: 'monthrange'
+ },
+ {
+ label: '日期时间范围(datetimerange)',
+ value: 'datetimerange'
+ }
+ ],
+ colorFormatOptions: [
+ {
+ label: 'hex',
+ value: 'hex'
+ },
+ {
+ label: 'rgb',
+ value: 'rgb'
+ },
+ {
+ label: 'rgba',
+ value: 'rgba'
+ },
+ {
+ label: 'hsv',
+ value: 'hsv'
+ },
+ {
+ label: 'hsl',
+ value: 'hsl'
+ }
+ ],
+ justifyOptions: [
+ {
+ label: 'start',
+ value: 'start'
+ },
+ {
+ label: 'end',
+ value: 'end'
+ },
+ {
+ label: 'center',
+ value: 'center'
+ },
+ {
+ label: 'space-around',
+ value: 'space-around'
+ },
+ {
+ label: 'space-between',
+ value: 'space-between'
+ }
+ ],
+ layoutTreeProps: {
+ label(data, node) {
+ return data.componentName || `${data.label}: ${data.vModel}`
+ }
+ }
+ }
+ },
+ computed: {
+ documentLink() {
+ return (
+ this.activeData.document
+ || 'https://element.eleme.cn/#/zh-CN/component/installation'
+ )
+ },
+ dateOptions() {
+ if (
+ this.activeData.type !== undefined
+ && this.activeData.tag === 'el-date-picker'
+ ) {
+ if (this.activeData['start-placeholder'] === undefined) {
+ return this.dateTypeOptions
+ }
+ return this.dateRangeTypeOptions
+ }
+ return []
+ },
+ tagList() {
+ return [
+ {
+ label: '输入型组件',
+ options: inputComponents
+ },
+ {
+ label: '选择型组件',
+ options: selectComponents
+ }
+ ]
+ }
+ },
+ methods: {
+ addReg() {
+ this.activeData.regList.push({
+ pattern: '',
+ message: ''
+ })
+ },
+ addSelectItem() {
+ this.activeData.options.push({
+ label: '',
+ value: ''
+ })
+ },
+ addTreeItem() {
+ ++this.idGlobal
+ this.dialogVisible = true
+ this.currentNode = this.activeData.options
+ },
+ renderContent(h, { node, data, store }) {
+ return (
+ <div class="custom-tree-node">
+ <span>{node.label}</span>
+ <span class="node-operation">
+ <i on-click={() => this.append(data)}
+ class="el-icon-plus"
+ title="添加"
+ ></i>
+ <i on-click={() => this.remove(node, data)}
+ class="el-icon-delete"
+ title="删除"
+ ></i>
+ </span>
+ </div>
+ )
+ },
+ append(data) {
+ if (!data.children) {
+ this.$set(data, 'children', [])
+ }
+ this.dialogVisible = true
+ this.currentNode = data.children
+ },
+ remove(node, data) {
+ const { parent } = node
+ const children = parent.data.children || parent.data
+ const index = children.findIndex(d => d.id === data.id)
+ children.splice(index, 1)
+ },
+ addNode(data) {
+ this.currentNode.push(data)
+ },
+ setOptionValue(item, val) {
+ item.value = isNumberStr(val) ? +val : val
+ },
+ setDefaultValue(val) {
+ if (Array.isArray(val)) {
+ return val.join(',')
+ }
+ if (['string', 'number'].indexOf(val) > -1) {
+ return val
+ }
+ if (typeof val === 'boolean') {
+ return `${val}`
+ }
+ return val
+ },
+ onDefaultValueInput(str) {
+ if (isArray(this.activeData.defaultValue)) {
+ // 数组
+ this.$set(
+ this.activeData,
+ 'defaultValue',
+ str.split(',').map(val => (isNumberStr(val) ? +val : val))
+ )
+ } else if (['true', 'false'].indexOf(str) > -1) {
+ // 布尔
+ this.$set(this.activeData, 'defaultValue', JSON.parse(str))
+ } else {
+ // 字符串和数字
+ this.$set(
+ this.activeData,
+ 'defaultValue',
+ isNumberStr(str) ? +str : str
+ )
+ }
+ },
+ onSwitchValueInput(val, name) {
+ if (['true', 'false'].indexOf(val) > -1) {
+ this.$set(this.activeData, name, JSON.parse(val))
+ } else {
+ this.$set(this.activeData, name, isNumberStr(val) ? +val : val)
+ }
+ },
+ setTimeValue(val, type) {
+ const valueFormat = type === 'week' ? dateTimeFormat.date : val
+ this.$set(this.activeData, 'defaultValue', null)
+ this.$set(this.activeData, 'value-format', valueFormat)
+ this.$set(this.activeData, 'format', val)
+ },
+ spanChange(val) {
+ this.formConf.span = val
+ },
+ multipleChange(val) {
+ this.$set(this.activeData, 'defaultValue', val ? [] : '')
+ },
+ dateTypeChange(val) {
+ this.setTimeValue(dateTimeFormat[val], val)
+ },
+ rangeChange(val) {
+ this.$set(
+ this.activeData,
+ 'defaultValue',
+ val ? [this.activeData.min, this.activeData.max] : this.activeData.min
+ )
+ },
+ rateTextChange(val) {
+ if (val) this.activeData['show-score'] = false
+ },
+ rateScoreChange(val) {
+ if (val) this.activeData['show-text'] = false
+ },
+ colorFormatChange(val) {
+ this.activeData.defaultValue = null
+ this.activeData['show-alpha'] = val.indexOf('a') > -1
+ this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
+ },
+ openIconsDialog(model) {
+ this.iconsVisible = true
+ this.currentIconModel = model
+ },
+ setIcon(val) {
+ this.activeData[this.currentIconModel] = val
+ },
+ tagChange(tagIcon) {
+ let target = inputComponents.find(item => item.tagIcon === tagIcon)
+ if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
+ this.$emit('tag-change', target)
+ }
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+.right-board {
+ width: 350px;
+ position: absolute;
+ right: 0;
+ top: 0;
+ padding-top: 3px;
+ .field-box {
+ position: relative;
+ height: calc(100vh - 42px);
+ box-sizing: border-box;
+ overflow: hidden;
+ }
+ .el-scrollbar {
+ height: 100%;
+ }
+}
+.select-item {
+ display: flex;
+ border: 1px dashed #fff;
+ box-sizing: border-box;
+ & .close-btn {
+ cursor: pointer;
+ color: #f56c6c;
+ }
+ & .el-input + .el-input {
+ margin-left: 4px;
+ }
+}
+.select-item + .select-item {
+ margin-top: 4px;
+}
+.select-item.sortable-chosen {
+ border: 1px dashed #409eff;
+}
+.select-line-icon {
+ line-height: 32px;
+ font-size: 22px;
+ padding: 0 4px;
+ color: #777;
+}
+.option-drag {
+ cursor: move;
+}
+.time-range {
+ .el-date-editor {
+ width: 227px;
+ }
+ ::v-deep .el-icon-time {
+ display: none;
+ }
+}
+.document-link {
+ position: absolute;
+ display: block;
+ width: 26px;
+ height: 26px;
+ top: 0;
+ left: 0;
+ cursor: pointer;
+ background: #409eff;
+ z-index: 1;
+ border-radius: 0 0 6px 0;
+ text-align: center;
+ line-height: 26px;
+ color: #fff;
+ font-size: 18px;
+}
+.node-label{
+ font-size: 14px;
+}
+.node-icon{
+ color: #bebfc3;
+}
+</style>
diff --git a/sgd-ui/src/views/tool/build/TreeNodeDialog.vue b/sgd-ui/src/views/tool/build/TreeNodeDialog.vue
new file mode 100644
index 0000000..e913d0f
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/TreeNodeDialog.vue
@@ -0,0 +1,148 @@
+<template>
+ <div>
+ <el-dialog
+ v-bind="$attrs"
+ :close-on-click-modal="false"
+ :modal-append-to-body="false"
+ v-on="$listeners"
+ @open="onOpen"
+ @close="onClose"
+ >
+ <el-row :gutter="0">
+ <el-form
+ ref="elForm"
+ :model="formData"
+ :rules="rules"
+ size="small"
+ label-width="100px"
+ >
+ <el-col :span="24">
+ <el-form-item
+ label="选项名"
+ prop="label"
+ >
+ <el-input
+ v-model="formData.label"
+ placeholder="请输入选项名"
+ clearable
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item
+ label="选项值"
+ prop="value"
+ >
+ <el-input
+ v-model="formData.value"
+ placeholder="请输入选项值"
+ clearable
+ >
+ <el-select
+ slot="append"
+ v-model="dataType"
+ :style="{width: '100px'}"
+ >
+ <el-option
+ v-for="(item, index) in dataTypeOptions"
+ :key="index"
+ :label="item.label"
+ :value="item.value"
+ :disabled="item.disabled"
+ />
+ </el-select>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ </el-form>
+ </el-row>
+ <div slot="footer">
+ <el-button
+ type="primary"
+ @click="handleConfirm"
+ >
+ 确定
+ </el-button>
+ <el-button @click="close">
+ 取消
+ </el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+<script>
+import { isNumberStr } from '@/utils/index'
+
+export default {
+ components: {},
+ inheritAttrs: false,
+ props: [],
+ data() {
+ return {
+ id: 100,
+ formData: {
+ label: undefined,
+ value: undefined
+ },
+ rules: {
+ label: [
+ {
+ required: true,
+ message: '请输入选项名',
+ trigger: 'blur'
+ }
+ ],
+ value: [
+ {
+ required: true,
+ message: '请输入选项值',
+ trigger: 'blur'
+ }
+ ]
+ },
+ dataType: 'string',
+ dataTypeOptions: [
+ {
+ label: '字符串',
+ value: 'string'
+ },
+ {
+ label: '数字',
+ value: 'number'
+ }
+ ]
+ }
+ },
+ computed: {},
+ watch: {
+ 'formData.value': function (val) {
+ this.dataType = isNumberStr(val) ? 'number' : 'string'
+ }
+ },
+ created() {},
+ mounted() {},
+ methods: {
+ onOpen() {
+ this.formData = {
+ label: undefined,
+ value: undefined
+ }
+ },
+ onClose() {},
+ close() {
+ this.$emit('update:visible', false)
+ },
+ handleConfirm() {
+ this.$refs.elForm.validate(valid => {
+ if (!valid) return
+ if (this.dataType === 'number') {
+ this.formData.value = parseFloat(this.formData.value)
+ }
+ this.formData.id = this.id++
+ this.$emit('commit', this.formData)
+ this.close()
+ })
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/build/index.vue b/sgd-ui/src/views/tool/build/index.vue
new file mode 100644
index 0000000..889422b
--- /dev/null
+++ b/sgd-ui/src/views/tool/build/index.vue
@@ -0,0 +1,775 @@
+<template>
+ <div class="container">
+ <div class="left-board">
+ <div class="logo-wrapper">
+ <div class="logo">
+ <img :src="logo" alt="logo"> Form Generator
+ </div>
+ </div>
+ <el-scrollbar class="left-scrollbar">
+ <div class="components-list">
+ <div class="components-title">
+ <svg-icon icon-class="component" />输入型组件
+ </div>
+ <draggable
+ class="components-draggable"
+ :list="inputComponents"
+ :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+ :clone="cloneComponent"
+ draggable=".components-item"
+ :sort="false"
+ @end="onEnd"
+ >
+ <div
+ v-for="(element, index) in inputComponents" :key="index" class="components-item"
+ @click="addComponent(element)"
+ >
+ <div class="components-body">
+ <svg-icon :icon-class="element.tagIcon" />
+ {{ element.label }}
+ </div>
+ </div>
+ </draggable>
+ <div class="components-title">
+ <svg-icon icon-class="component" />选择型组件
+ </div>
+ <draggable
+ class="components-draggable"
+ :list="selectComponents"
+ :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+ :clone="cloneComponent"
+ draggable=".components-item"
+ :sort="false"
+ @end="onEnd"
+ >
+ <div
+ v-for="(element, index) in selectComponents"
+ :key="index"
+ class="components-item"
+ @click="addComponent(element)"
+ >
+ <div class="components-body">
+ <svg-icon :icon-class="element.tagIcon" />
+ {{ element.label }}
+ </div>
+ </div>
+ </draggable>
+ <div class="components-title">
+ <svg-icon icon-class="component" /> 布局型组件
+ </div>
+ <draggable
+ class="components-draggable" :list="layoutComponents"
+ :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
+ draggable=".components-item" :sort="false" @end="onEnd"
+ >
+ <div
+ v-for="(element, index) in layoutComponents" :key="index" class="components-item"
+ @click="addComponent(element)"
+ >
+ <div class="components-body">
+ <svg-icon :icon-class="element.tagIcon" />
+ {{ element.label }}
+ </div>
+ </div>
+ </draggable>
+ </div>
+ </el-scrollbar>
+ </div>
+
+ <div class="center-board">
+ <div class="action-bar">
+ <el-button icon="el-icon-download" type="text" @click="download">
+ 导出vue文件
+ </el-button>
+ <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
+ 复制代码
+ </el-button>
+ <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
+ 清空
+ </el-button>
+ </div>
+ <el-scrollbar class="center-scrollbar">
+ <el-row class="center-board-row" :gutter="formConf.gutter">
+ <el-form
+ :size="formConf.size"
+ :label-position="formConf.labelPosition"
+ :disabled="formConf.disabled"
+ :label-width="formConf.labelWidth + 'px'"
+ >
+ <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
+ <draggable-item
+ v-for="(element, index) in drawingList"
+ :key="element.renderKey"
+ :drawing-list="drawingList"
+ :element="element"
+ :index="index"
+ :active-id="activeId"
+ :form-conf="formConf"
+ @activeItem="activeFormItem"
+ @copyItem="drawingItemCopy"
+ @deleteItem="drawingItemDelete"
+ />
+ </draggable>
+ <div v-show="!drawingList.length" class="empty-info">
+ 从左侧拖入或点选组件进行表单设计
+ </div>
+ </el-form>
+ </el-row>
+ </el-scrollbar>
+ </div>
+
+ <right-panel
+ :active-data="activeData"
+ :form-conf="formConf"
+ :show-field="!!drawingList.length"
+ @tag-change="tagChange"
+ />
+
+ <code-type-dialog
+ :visible.sync="dialogVisible"
+ title="选择生成类型"
+ :show-file-name="showFileName"
+ @confirm="generate"
+ />
+ <input id="copyNode" type="hidden">
+ </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+import beautifier from 'js-beautify'
+import ClipboardJS from 'clipboard'
+import render from '@/utils/generator/render'
+import RightPanel from './RightPanel'
+import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'
+import { beautifierConf, titleCase } from '@/utils/index'
+import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
+import { makeUpJs } from '@/utils/generator/js'
+import { makeUpCss } from '@/utils/generator/css'
+import { drawingDefaultValue, initDrawingDefaultValue, cleanDrawingDefaultValue } from '@/utils/generator/drawingDefault'
+import logo from '@/assets/logo/logo.png'
+import CodeTypeDialog from './CodeTypeDialog'
+import DraggableItem from './DraggableItem'
+
+let oldActiveId
+let tempActiveData
+let clipboard = null
+
+export default {
+ components: {
+ draggable,
+ render,
+ RightPanel,
+ CodeTypeDialog,
+ DraggableItem
+ },
+ data() {
+ return {
+ logo,
+ idGlobal: 100,
+ formConf,
+ inputComponents,
+ selectComponents,
+ layoutComponents,
+ labelWidth: 100,
+ drawingList: drawingDefaultValue,
+ drawingData: {},
+ activeId: drawingDefaultValue[0].formId,
+ drawerVisible: false,
+ formData: {},
+ dialogVisible: false,
+ generateConf: null,
+ showFileName: false,
+ activeData: drawingDefaultValue[0]
+ }
+ },
+ beforeCreate() {
+ initDrawingDefaultValue()
+ },
+ created() {
+ // 防止 firefox 下 拖拽 会新打卡一个选项卡
+ document.body.ondrop = event => {
+ event.preventDefault()
+ event.stopPropagation()
+ }
+ },
+ watch: {
+ 'activeData.label': function (val, oldVal) {
+ if (
+ this.activeData.placeholder === undefined
+ || !this.activeData.tag
+ || oldActiveId !== this.activeId
+ ) {
+ return
+ }
+ this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
+ },
+ activeId: {
+ handler(val) {
+ oldActiveId = val
+ },
+ immediate: true
+ }
+ },
+ mounted() {
+ clipboard = new ClipboardJS('#copyNode', {
+ text: trigger => {
+ const codeStr = this.generateCode()
+ this.$notify({
+ title: '成功',
+ message: '代码已复制到剪切板,可粘贴。',
+ type: 'success'
+ })
+ return codeStr
+ }
+ })
+ clipboard.on('error', e => {
+ this.$message.error('代码复制失败')
+ })
+ },
+ beforeDestroy() {
+ clipboard.destroy()
+ },
+ methods: {
+ activeFormItem(element) {
+ this.activeData = element
+ this.activeId = element.formId
+ },
+ onEnd(obj, a) {
+ if (obj.from !== obj.to) {
+ this.activeData = tempActiveData
+ this.activeId = this.idGlobal
+ }
+ },
+ addComponent(item) {
+ const clone = this.cloneComponent(item)
+ this.drawingList.push(clone)
+ this.activeFormItem(clone)
+ },
+ cloneComponent(origin) {
+ const clone = JSON.parse(JSON.stringify(origin))
+ clone.formId = ++this.idGlobal
+ clone.span = formConf.span
+ clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
+ if (!clone.layout) clone.layout = 'colFormItem'
+ if (clone.layout === 'colFormItem') {
+ clone.vModel = `field${this.idGlobal}`
+ clone.placeholder !== undefined && (clone.placeholder += clone.label)
+ tempActiveData = clone
+ } else if (clone.layout === 'rowFormItem') {
+ delete clone.label
+ clone.componentName = `row${this.idGlobal}`
+ clone.gutter = this.formConf.gutter
+ tempActiveData = clone
+ }
+ return tempActiveData
+ },
+ AssembleFormData() {
+ this.formData = {
+ fields: JSON.parse(JSON.stringify(this.drawingList)),
+ ...this.formConf
+ }
+ },
+ generate(data) {
+ const func = this[`exec${titleCase(this.operationType)}`]
+ this.generateConf = data
+ func && func(data)
+ },
+ execRun(data) {
+ this.AssembleFormData()
+ this.drawerVisible = true
+ },
+ execDownload(data) {
+ const codeStr = this.generateCode()
+ const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
+ this.$download.saveAs(blob, data.fileName)
+ },
+ execCopy(data) {
+ document.getElementById('copyNode').click()
+ },
+ empty() {
+ this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
+ () => {
+ this.drawingList = []
+ cleanDrawingDefaultValue()
+ }
+ )
+ },
+ drawingItemCopy(item, parent) {
+ let clone = JSON.parse(JSON.stringify(item))
+ clone = this.createIdAndKey(clone)
+ parent.push(clone)
+ this.activeFormItem(clone)
+ },
+ createIdAndKey(item) {
+ item.formId = ++this.idGlobal
+ item.renderKey = +new Date()
+ if (item.layout === 'colFormItem') {
+ item.vModel = `field${this.idGlobal}`
+ } else if (item.layout === 'rowFormItem') {
+ item.componentName = `row${this.idGlobal}`
+ }
+ if (Array.isArray(item.children)) {
+ item.children = item.children.map(childItem => this.createIdAndKey(childItem))
+ }
+ return item
+ },
+ drawingItemDelete(index, parent) {
+ parent.splice(index, 1)
+ this.$nextTick(() => {
+ const len = this.drawingList.length
+ if (len) {
+ this.activeFormItem(this.drawingList[len - 1])
+ }
+ })
+ },
+ generateCode() {
+ const { type } = this.generateConf
+ this.AssembleFormData()
+ const script = vueScript(makeUpJs(this.formData, type))
+ const html = vueTemplate(makeUpHtml(this.formData, type))
+ const css = cssStyle(makeUpCss(this.formData))
+ return beautifier.html(html + script + css, beautifierConf.html)
+ },
+ download() {
+ this.dialogVisible = true
+ this.showFileName = true
+ this.operationType = 'download'
+ },
+ run() {
+ this.dialogVisible = true
+ this.showFileName = false
+ this.operationType = 'run'
+ },
+ copy() {
+ this.dialogVisible = true
+ this.showFileName = false
+ this.operationType = 'copy'
+ },
+ tagChange(newTag) {
+ newTag = this.cloneComponent(newTag)
+ newTag.vModel = this.activeData.vModel
+ newTag.formId = this.activeId
+ newTag.span = this.activeData.span
+ delete this.activeData.tag
+ delete this.activeData.tagIcon
+ delete this.activeData.document
+ Object.keys(newTag).forEach(key => {
+ if (this.activeData[key] !== undefined
+ && typeof this.activeData[key] === typeof newTag[key]) {
+ newTag[key] = this.activeData[key]
+ }
+ })
+ this.activeData = newTag
+ this.updateDrawingList(newTag, this.drawingList)
+ },
+ updateDrawingList(newTag, list) {
+ const index = list.findIndex(item => item.formId === this.activeId)
+ if (index > -1) {
+ list.splice(index, 1, newTag)
+ } else {
+ list.forEach(item => {
+ if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
+ })
+ }
+ }
+ }
+}
+</script>
+
+<style lang='scss'>
+.editor-tabs{
+ background: #121315;
+ .el-tabs__header{
+ margin: 0;
+ border-bottom-color: #121315;
+ .el-tabs__nav{
+ border-color: #121315;
+ }
+ }
+ .el-tabs__item{
+ height: 32px;
+ line-height: 32px;
+ color: #888a8e;
+ border-left: 1px solid #121315 !important;
+ background: #363636;
+ margin-right: 5px;
+ user-select: none;
+ }
+ .el-tabs__item.is-active{
+ background: #1e1e1e;
+ border-bottom-color: #1e1e1e!important;
+ color: #fff;
+ }
+ .el-icon-edit{
+ color: #f1fa8c;
+ }
+ .el-icon-document{
+ color: #a95812;
+ }
+}
+
+// home
+.right-scrollbar {
+ .el-scrollbar__view {
+ padding: 12px 18px 15px 15px;
+ }
+}
+.left-scrollbar .el-scrollbar__wrap {
+ box-sizing: border-box;
+ overflow-x: hidden !important;
+ margin-bottom: 0 !important;
+}
+.center-tabs{
+ .el-tabs__header{
+ margin-bottom: 0!important;
+ }
+ .el-tabs__item{
+ width: 50%;
+ text-align: center;
+ }
+ .el-tabs__nav{
+ width: 100%;
+ }
+}
+.reg-item{
+ padding: 12px 6px;
+ background: #f8f8f8;
+ position: relative;
+ border-radius: 4px;
+ .close-btn{
+ position: absolute;
+ right: -6px;
+ top: -6px;
+ display: block;
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 50%;
+ color: #fff;
+ text-align: center;
+ z-index: 1;
+ cursor: pointer;
+ font-size: 12px;
+ &:hover{
+ background: rgba(210, 23, 23, 0.5)
+ }
+ }
+ & + .reg-item{
+ margin-top: 18px;
+ }
+}
+.action-bar{
+ & .el-button+.el-button {
+ margin-left: 15px;
+ }
+ & i {
+ font-size: 20px;
+ vertical-align: middle;
+ position: relative;
+ top: -1px;
+ }
+}
+
+.custom-tree-node{
+ width: 100%;
+ font-size: 14px;
+ .node-operation{
+ float: right;
+ }
+ i[class*="el-icon"] + i[class*="el-icon"]{
+ margin-left: 6px;
+ }
+ .el-icon-plus{
+ color: #409EFF;
+ }
+ .el-icon-delete{
+ color: #157a0c;
+ }
+}
+
+.left-scrollbar .el-scrollbar__view{
+ overflow-x: hidden;
+}
+
+.el-rate{
+ display: inline-block;
+ vertical-align: text-top;
+}
+.el-upload__tip{
+ line-height: 1.2;
+}
+
+$selectedColor: #f6f7ff;
+$lighterBlue: #409EFF;
+
+.container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.components-list {
+ padding: 8px;
+ box-sizing: border-box;
+ height: 100%;
+ .components-item {
+ display: inline-block;
+ width: 48%;
+ margin: 1%;
+ transition: transform 0ms !important;
+ }
+}
+.components-draggable{
+ padding-bottom: 20px;
+}
+.components-title{
+ font-size: 14px;
+ color: #222;
+ margin: 6px 2px;
+ .svg-icon{
+ color: #666;
+ font-size: 18px;
+ }
+}
+
+.components-body {
+ padding: 8px 10px;
+ background: $selectedColor;
+ font-size: 12px;
+ cursor: move;
+ border: 1px dashed $selectedColor;
+ border-radius: 3px;
+ .svg-icon{
+ color: #777;
+ font-size: 15px;
+ }
+ &:hover {
+ border: 1px dashed #787be8;
+ color: #787be8;
+ .svg-icon {
+ color: #787be8;
+ }
+ }
+}
+
+.left-board {
+ width: 260px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 100vh;
+}
+.left-scrollbar{
+ height: calc(100vh - 42px);
+ overflow: hidden;
+}
+.center-scrollbar {
+ height: calc(100vh - 42px);
+ overflow: hidden;
+ border-left: 1px solid #f1e8e8;
+ border-right: 1px solid #f1e8e8;
+ box-sizing: border-box;
+}
+.center-board {
+ height: 100vh;
+ width: auto;
+ margin: 0 350px 0 260px;
+ box-sizing: border-box;
+}
+.empty-info{
+ position: absolute;
+ top: 46%;
+ left: 0;
+ right: 0;
+ text-align: center;
+ font-size: 18px;
+ color: #ccb1ea;
+ letter-spacing: 4px;
+}
+.action-bar{
+ position: relative;
+ height: 42px;
+ text-align: right;
+ padding: 0 15px;
+ box-sizing: border-box;;
+ border: 1px solid #f1e8e8;
+ border-top: none;
+ border-left: none;
+ .delete-btn{
+ color: #F56C6C;
+ }
+}
+.logo-wrapper{
+ position: relative;
+ height: 42px;
+ background: #fff;
+ border-bottom: 1px solid #f1e8e8;
+ box-sizing: border-box;
+}
+.logo{
+ position: absolute;
+ left: 12px;
+ top: 6px;
+ line-height: 30px;
+ color: #00afff;
+ font-weight: 600;
+ font-size: 17px;
+ white-space: nowrap;
+ > img{
+ width: 30px;
+ height: 30px;
+ vertical-align: top;
+ }
+ .github{
+ display: inline-block;
+ vertical-align: sub;
+ margin-left: 15px;
+ > img{
+ height: 22px;
+ }
+ }
+}
+
+.center-board-row {
+ padding: 12px 12px 15px 12px;
+ box-sizing: border-box;
+ & > .el-form {
+ // 69 = 12+15+42
+ height: calc(100vh - 69px);
+ }
+}
+.drawing-board {
+ height: 100%;
+ position: relative;
+ .components-body {
+ padding: 0;
+ margin: 0;
+ font-size: 0;
+ }
+ .sortable-ghost {
+ position: relative;
+ display: block;
+ overflow: hidden;
+ &::before {
+ content: " ";
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ height: 3px;
+ background: rgb(89, 89, 223);
+ z-index: 2;
+ }
+ }
+ .components-item.sortable-ghost {
+ width: 100%;
+ height: 60px;
+ background-color: $selectedColor;
+ }
+ .active-from-item {
+ & > .el-form-item{
+ background: $selectedColor;
+ border-radius: 6px;
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: initial;
+ }
+ & > .component-name{
+ color: $lighterBlue;
+ }
+ }
+ .el-form-item{
+ margin-bottom: 15px;
+ }
+}
+.drawing-item{
+ position: relative;
+ cursor: move;
+ &.unfocus-bordered:not(.activeFromItem) > div:first-child {
+ border: 1px dashed #ccc;
+ }
+ .el-form-item{
+ padding: 12px 10px;
+ }
+}
+.drawing-row-item{
+ position: relative;
+ cursor: move;
+ box-sizing: border-box;
+ border: 1px dashed #ccc;
+ border-radius: 3px;
+ padding: 0 2px;
+ margin-bottom: 15px;
+ .drawing-row-item {
+ margin-bottom: 2px;
+ }
+ .el-col{
+ margin-top: 22px;
+ }
+ .el-form-item{
+ margin-bottom: 0;
+ }
+ .drag-wrapper{
+ min-height: 80px;
+ }
+ &.active-from-item{
+ border: 1px dashed $lighterBlue;
+ }
+ .component-name{
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 12px;
+ color: #bbb;
+ display: inline-block;
+ padding: 0 6px;
+ }
+}
+.drawing-item, .drawing-row-item{
+ &:hover {
+ & > .el-form-item{
+ background: $selectedColor;
+ border-radius: 6px;
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: initial;
+ }
+ }
+ & > .drawing-item-copy, & > .drawing-item-delete{
+ display: none;
+ position: absolute;
+ top: -10px;
+ width: 22px;
+ height: 22px;
+ line-height: 22px;
+ text-align: center;
+ border-radius: 50%;
+ font-size: 12px;
+ border: 1px solid;
+ cursor: pointer;
+ z-index: 1;
+ }
+ & > .drawing-item-copy{
+ right: 56px;
+ border-color: $lighterBlue;
+ color: $lighterBlue;
+ background: #fff;
+ &:hover{
+ background: $lighterBlue;
+ color: #fff;
+ }
+ }
+ & > .drawing-item-delete{
+ right: 24px;
+ border-color: #F56C6C;
+ color: #F56C6C;
+ background: #fff;
+ &:hover{
+ background: #F56C6C;
+ color: #fff;
+ }
+ }
+}
+</style>
diff --git a/sgd-ui/src/views/tool/gen/basicInfoForm.vue b/sgd-ui/src/views/tool/gen/basicInfoForm.vue
new file mode 100644
index 0000000..3a6e2ed
--- /dev/null
+++ b/sgd-ui/src/views/tool/gen/basicInfoForm.vue
@@ -0,0 +1,60 @@
+<template>
+ <el-form ref="basicInfoForm" :model="info" :rules="rules" label-width="150px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item label="表名称" prop="tableName">
+ <el-input placeholder="请输入仓库名称" v-model="info.tableName" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="表描述" prop="tableComment">
+ <el-input placeholder="请输入" v-model="info.tableComment" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="实体类名称" prop="className">
+ <el-input placeholder="请输入" v-model="info.className" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="作者" prop="functionAuthor">
+ <el-input placeholder="请输入" v-model="info.functionAuthor" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="备注" prop="remark">
+ <el-input type="textarea" :rows="3" v-model="info.remark"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+</template>
+
+<script>
+export default {
+ props: {
+ info: {
+ type: Object,
+ default: null
+ }
+ },
+ data() {
+ return {
+ rules: {
+ tableName: [
+ { required: true, message: "请输入表名称", trigger: "blur" }
+ ],
+ tableComment: [
+ { required: true, message: "请输入表描述", trigger: "blur" }
+ ],
+ className: [
+ { required: true, message: "请输入实体类名称", trigger: "blur" }
+ ],
+ functionAuthor: [
+ { required: true, message: "请输入作者", trigger: "blur" }
+ ]
+ }
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/gen/editTable.vue b/sgd-ui/src/views/tool/gen/editTable.vue
new file mode 100644
index 0000000..e8371a1
--- /dev/null
+++ b/sgd-ui/src/views/tool/gen/editTable.vue
@@ -0,0 +1,230 @@
+<template>
+ <el-card>
+ <el-tabs v-model="activeName">
+ <el-tab-pane label="基本信息" name="basic">
+ <basic-info-form ref="basicInfo" :info="info" />
+ </el-tab-pane>
+ <el-tab-pane label="字段信息" name="columnInfo">
+ <el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
+ <el-table-column label="序号" type="index" min-width="5%" class-name="allowDrag"/>
+ <el-table-column label="字段列名" prop="columnName" min-width="10%" :show-overflow-tooltip="true" class-name="allowDrag"/>
+ <el-table-column label="字段描述" min-width="10%">
+ <template slot-scope="scope">
+ <el-input v-model="scope.row.columnComment"></el-input>
+ </template>
+ </el-table-column>
+ <el-table-column
+ label="物理类型"
+ prop="columnType"
+ min-width="10%"
+ :show-overflow-tooltip="true"
+ />
+ <el-table-column label="Java类型" min-width="11%">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.javaType">
+ <el-option label="Long" value="Long" />
+ <el-option label="String" value="String" />
+ <el-option label="Integer" value="Integer" />
+ <el-option label="Double" value="Double" />
+ <el-option label="BigDecimal" value="BigDecimal" />
+ <el-option label="Date" value="Date" />
+ <el-option label="Boolean" value="Boolean" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="java属性" min-width="10%">
+ <template slot-scope="scope">
+ <el-input v-model="scope.row.javaField"></el-input>
+ </template>
+ </el-table-column>
+
+ <el-table-column label="插入" min-width="5%">
+ <template slot-scope="scope">
+ <el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
+ </template>
+ </el-table-column>
+ <el-table-column label="编辑" min-width="5%">
+ <template slot-scope="scope">
+ <el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
+ </template>
+ </el-table-column>
+ <el-table-column label="列表" min-width="5%">
+ <template slot-scope="scope">
+ <el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
+ </template>
+ </el-table-column>
+ <el-table-column label="查询" min-width="5%">
+ <template slot-scope="scope">
+ <el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
+ </template>
+ </el-table-column>
+ <el-table-column label="查询方式" min-width="10%">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.queryType">
+ <el-option label="=" value="EQ" />
+ <el-option label="!=" value="NE" />
+ <el-option label=">" value="GT" />
+ <el-option label=">=" value="GTE" />
+ <el-option label="<" value="LT" />
+ <el-option label="<=" value="LTE" />
+ <el-option label="LIKE" value="LIKE" />
+ <el-option label="BETWEEN" value="BETWEEN" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="必填" min-width="5%">
+ <template slot-scope="scope">
+ <el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
+ </template>
+ </el-table-column>
+ <el-table-column label="显示类型" min-width="12%">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.htmlType">
+ <el-option label="文本框" value="input" />
+ <el-option label="文本域" value="textarea" />
+ <el-option label="下拉框" value="select" />
+ <el-option label="单选框" value="radio" />
+ <el-option label="复选框" value="checkbox" />
+ <el-option label="日期控件" value="datetime" />
+ <el-option label="图片上传" value="imageUpload" />
+ <el-option label="文件上传" value="fileUpload" />
+ <el-option label="富文本控件" value="editor" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="字典类型" min-width="12%">
+ <template slot-scope="scope">
+ <el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
+ <el-option
+ v-for="dict in dictOptions"
+ :key="dict.dictType"
+ :label="dict.dictName"
+ :value="dict.dictType">
+ <span style="float: left">{{ dict.dictName }}</span>
+ <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
+ </el-option>
+ </el-select>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-tab-pane>
+ <el-tab-pane label="生成信息" name="genInfo">
+ <gen-info-form ref="genInfo" :info="info" :tables="tables" :menus="menus"/>
+ </el-tab-pane>
+ </el-tabs>
+ <el-form label-width="100px">
+ <el-form-item style="text-align: center;margin-left:-100px;margin-top:10px;">
+ <el-button type="primary" @click="submitForm()">提交</el-button>
+ <el-button @click="close()">返回</el-button>
+ </el-form-item>
+ </el-form>
+ </el-card>
+</template>
+
+<script>
+import { getGenTable, updateGenTable } from "@/api/tool/gen"
+import { optionselect as getDictOptionselect } from "@/api/system/dict/type"
+import { listMenu as getMenuTreeselect } from "@/api/system/menu"
+import basicInfoForm from "./basicInfoForm"
+import genInfoForm from "./genInfoForm"
+import Sortable from 'sortablejs'
+
+export default {
+ name: "GenEdit",
+ components: {
+ basicInfoForm,
+ genInfoForm
+ },
+ data() {
+ return {
+ // 选中选项卡的 name
+ activeName: "columnInfo",
+ // 表格的高度
+ tableHeight: document.documentElement.scrollHeight - 245 + "px",
+ // 表信息
+ tables: [],
+ // 表列信息
+ columns: [],
+ // 字典信息
+ dictOptions: [],
+ // 菜单信息
+ menus: [],
+ // 表详细信息
+ info: {}
+ }
+ },
+ created() {
+ const tableId = this.$route.params && this.$route.params.tableId
+ if (tableId) {
+ // 获取表详细信息
+ getGenTable(tableId).then(res => {
+ this.columns = res.data.rows
+ this.info = res.data.info
+ this.tables = res.data.tables
+ })
+ /** 查询字典下拉列表 */
+ getDictOptionselect().then(response => {
+ this.dictOptions = response.data
+ })
+ /** 查询菜单下拉列表 */
+ getMenuTreeselect().then(response => {
+ this.menus = this.handleTree(response.data, "menuId")
+ })
+ }
+ },
+ methods: {
+ /** 提交按钮 */
+ submitForm() {
+ const basicForm = this.$refs.basicInfo.$refs.basicInfoForm
+ const genForm = this.$refs.genInfo.$refs.genInfoForm
+ Promise.all([basicForm, genForm].map(this.getFormPromise)).then(res => {
+ const validateResult = res.every(item => !!item)
+ if (validateResult) {
+ const genTable = Object.assign({}, basicForm.model, genForm.model)
+ genTable.columns = this.columns
+ genTable.params = {
+ genView: genTable.view ? '1' : '0',
+ treeCode: genTable.treeCode,
+ treeName: genTable.treeName,
+ treeParentCode: genTable.treeParentCode,
+ parentMenuId: genTable.parentMenuId
+ }
+ updateGenTable(genTable).then(res => {
+ this.$modal.msgSuccess(res.msg)
+ if (res.code === 200) {
+ this.close()
+ }
+ })
+ } else {
+ this.$modal.msgError("表单校验未通过,请重新检查提交内容")
+ }
+ })
+ },
+ getFormPromise(form) {
+ return new Promise(resolve => {
+ form.validate(res => {
+ resolve(res)
+ })
+ })
+ },
+ /** 关闭按钮 */
+ close() {
+ const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } }
+ this.$tab.closeOpenPage(obj)
+ }
+ },
+ mounted() {
+ const el = this.$refs.dragTable.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0]
+ const sortable = Sortable.create(el, {
+ handle: ".allowDrag",
+ onEnd: evt => {
+ const targetRow = this.columns.splice(evt.oldIndex, 1)[0]
+ this.columns.splice(evt.newIndex, 0, targetRow)
+ for (let index in this.columns) {
+ this.columns[index].sort = parseInt(index) + 1
+ }
+ }
+ })
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/gen/genInfoForm.vue b/sgd-ui/src/views/tool/gen/genInfoForm.vue
new file mode 100644
index 0000000..474f9ae
--- /dev/null
+++ b/sgd-ui/src/views/tool/gen/genInfoForm.vue
@@ -0,0 +1,336 @@
+<template>
+ <el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
+ <el-row>
+ <el-col :span="12">
+ <el-form-item prop="tplCategory">
+ <span slot="label">生成模板</span>
+ <el-select v-model="info.tplCategory" @change="tplSelectChange">
+ <el-option label="单表(增删改查)" value="crud" />
+ <el-option label="树表(增删改查)" value="tree" />
+ <el-option label="主子表(增删改查)" value="sub" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item prop="tplWebType">
+ <span slot="label">前端类型</span>
+ <el-select v-model="info.tplWebType">
+ <el-option label="Vue2 Element UI 模版" value="element-ui" />
+ <el-option label="Vue3 Element Plus 模版" value="element-plus" />
+ <el-option label="Vue3 Element Plus TypeScript 模版" value="element-plus-typescript" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item prop="packageName">
+ <span slot="label">
+ 生成包路径
+ <el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="info.packageName" />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="moduleName">
+ <span slot="label">
+ 生成模块名
+ <el-tooltip content="可理解为子系统名,例如 system" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="info.moduleName" />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="businessName">
+ <span slot="label">
+ 生成业务名
+ <el-tooltip content="可理解为功能英文名,例如 user" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="info.businessName" />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="functionName">
+ <span slot="label">
+ 生成功能名
+ <el-tooltip content="用作类描述,例如 用户" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="info.functionName" />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="formColNum">
+ <span slot="label">
+ 表单布局
+ <el-tooltip content="选择表单的栅格布局方式" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.formColNum">
+ <el-option label="单列" :value="1" />
+ <el-option label="双列" :value="2" />
+ <el-option label="三列" :value="3" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="genView">
+ <span slot="label">扩展功能</span>
+ <el-checkbox v-model="info.view">生成详情页</el-checkbox>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item prop="genType">
+ <span slot="label">
+ 生成代码方式
+ <el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
+ <el-radio v-model="info.genType" label="1">自定义路径</el-radio>
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 上级菜单
+ <el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <treeselect
+ :append-to-body="true"
+ v-model="info.parentMenuId"
+ :options="menus"
+ :normalizer="normalizer"
+ :show-count="true"
+ placeholder="请选择系统菜单"
+ />
+ </el-form-item>
+ </el-col>
+
+ <el-col :span="24" v-if="info.genType == '1'">
+ <el-form-item prop="genPath">
+ <span slot="label">
+ 自定义路径
+ <el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-input v-model="info.genPath">
+ <el-dropdown slot="append">
+ <el-button type="primary">
+ 最近路径快速选择
+ <i class="el-icon-arrow-down el-icon--right"></i>
+ </el-button>
+ <el-dropdown-menu slot="dropdown">
+ <el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+
+ <el-row v-show="info.tplCategory == 'tree'">
+ <h4 class="form-header">其他信息</h4>
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 树编码字段
+ <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.treeCode" placeholder="请选择">
+ <el-option
+ v-for="(column, index) in info.columns"
+ :key="index"
+ :label="column.columnName + ':' + column.columnComment"
+ :value="column.columnName"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 树父编码字段
+ <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.treeParentCode" placeholder="请选择">
+ <el-option
+ v-for="(column, index) in info.columns"
+ :key="index"
+ :label="column.columnName + ':' + column.columnComment"
+ :value="column.columnName"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 树名称字段
+ <el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.treeName" placeholder="请选择">
+ <el-option
+ v-for="(column, index) in info.columns"
+ :key="index"
+ :label="column.columnName + ':' + column.columnComment"
+ :value="column.columnName"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row v-show="info.tplCategory == 'sub'">
+ <h4 class="form-header">关联信息</h4>
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 关联子表的表名
+ <el-tooltip content="关联子表的表名, 如:sys_user" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
+ <el-option
+ v-for="(table, index) in tables"
+ :key="index"
+ :label="table.tableName + ':' + table.tableComment"
+ :value="table.tableName"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item>
+ <span slot="label">
+ 子表关联的外键名
+ <el-tooltip content="子表关联的外键名, 如:user_id" placement="top">
+ <i class="el-icon-question"></i>
+ </el-tooltip>
+ </span>
+ <el-select v-model="info.subTableFkName" placeholder="请选择">
+ <el-option
+ v-for="(column, index) in subColumns"
+ :key="index"
+ :label="column.columnName + ':' + column.columnComment"
+ :value="column.columnName"
+ ></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+</template>
+
+<script>
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+
+export default {
+ components: { Treeselect },
+ props: {
+ info: {
+ type: Object,
+ default: null
+ },
+ tables: {
+ type: Array,
+ default: null
+ },
+ menus: {
+ type: Array,
+ default: []
+ }
+ },
+ data() {
+ return {
+ subColumns: [],
+ rules: {
+ tplCategory: [
+ { required: true, message: "请选择生成模板", trigger: "blur" }
+ ],
+ packageName: [
+ { required: true, message: "请输入生成包路径", trigger: "blur" }
+ ],
+ moduleName: [
+ { required: true, message: "请输入生成模块名", trigger: "blur" }
+ ],
+ businessName: [
+ { required: true, message: "请输入生成业务名", trigger: "blur" }
+ ],
+ functionName: [
+ { required: true, message: "请输入生成功能名", trigger: "blur" }
+ ]
+ }
+ }
+ },
+ watch: {
+ 'info.subTableName': function(val) {
+ this.setSubTableColumns(val)
+ },
+ 'info.tplWebType': function(val) {
+ if (val === '') {
+ this.info.tplWebType = "element-ui"
+ }
+ }
+ },
+ methods: {
+ /** 转换菜单数据结构 */
+ normalizer(node) {
+ if (node.children && !node.children.length) {
+ delete node.children
+ }
+ return {
+ id: node.menuId,
+ label: node.menuName,
+ children: node.children
+ }
+ },
+ /** 选择子表名触发 */
+ subSelectChange(value) {
+ this.info.subTableFkName = ''
+ },
+ /** 选择生成模板触发 */
+ tplSelectChange(value) {
+ if(value !== 'sub') {
+ this.info.subTableName = ''
+ this.info.subTableFkName = ''
+ }
+ },
+ /** 设置关联外键 */
+ setSubTableColumns(value) {
+ for (var item in this.tables) {
+ const name = this.tables[item].tableName
+ if (value === name) {
+ this.subColumns = this.tables[item].columns
+ break
+ }
+ }
+ }
+ }
+}
+</script>
diff --git a/sgd-ui/src/views/tool/gen/importTable.vue b/sgd-ui/src/views/tool/gen/importTable.vue
new file mode 100644
index 0000000..91d62b7
--- /dev/null
+++ b/sgd-ui/src/views/tool/gen/importTable.vue
@@ -0,0 +1,120 @@
+<template>
+ <!-- 导入表 -->
+ <el-dialog title="导入表" :visible.sync="visible" width="800px" top="5vh" append-to-body>
+ <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
+ <el-form-item label="表名称" prop="tableName">
+ <el-input
+ v-model="queryParams.tableName"
+ placeholder="请输入表名称"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="表描述" prop="tableComment">
+ <el-input
+ v-model="queryParams.tableComment"
+ placeholder="请输入表描述"
+ clearable
+ @keyup.enter.native="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+ </el-form-item>
+ </el-form>
+ <el-row>
+ <el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
+ <el-table-column type="selection" width="55"></el-table-column>
+ <el-table-column prop="tableName" label="表名称" :show-overflow-tooltip="true"></el-table-column>
+ <el-table-column prop="tableComment" label="表描述" :show-overflow-tooltip="true"></el-table-column>
+ <el-table-column prop="createTime" label="创建时间"></el-table-column>
+ <el-table-column prop="updateTime" label="更新时间"></el-table-column>
+ </el-table>
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="queryParams.pageNum"
+ :limit.sync="queryParams.pageSize"
+ @pagination="getList"
+ />
+ </el-row>
+ <div slot="footer" class="dialog-footer">
+ <el-button type="primary" @click="handleImportTable">确 定</el-button>
+ <el-button @click="visible = false">取 消</el-button>
+ </div>
+ </el-dialog>
+</template>
+
+<script>
+import { listDbTable, importTable } from "@/api/tool/gen"
+export default {
+ data() {
+ return {
+ // 遮罩层
+ visible: false,
+ // 选中数组值
+ tables: [],
+ // 总条数
+ total: 0,
+ // 表数据
+ dbTableList: [],
+ // 查询参数
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+ tableName: undefined,
+ tableComment: undefined
+ }
+ }
+ },
+ methods: {
+ // 显示弹框
+ show() {
+ this.getList()
+ this.visible = true
+ },
+ clickRow(row) {
+ this.$refs.table.toggleRowSelection(row)
+ },
+ // 多选框选中数据
+ handleSelectionChange(selection) {
+ this.tables = selection.map(item => item.tableName)
+ },
+ // 查询表数据
+ getList() {
+ listDbTable(this.queryParams).then(res => {
+ if (res.code === 200) {
+ this.dbTableList = res.rows
+ this.total = res.total
+ }
+ })
+ },
+ /** 搜索按钮操作 */
+ handleQuery() {
+ this.queryParams.pageNum = 1
+ this.getList()
+ },
+ /** 重置按钮操作 */
+ resetQuery() {
+ this.resetForm("queryForm")
+ this.handleQuery()
+ },
+ /** 导入按钮操作 */
+ handleImportTable() {
+ const tableNames = this.tables.join(",")
+ if (tableNames == "") {
+ this.$modal.msgError("请选择要导入的表")
+ return
+ }
+ importTable({ tables: tableNames, tplWebType: 'element-ui' }).then(res => {
+ this.$modal.msgSuccess(res.msg)
+ if (res.code === 200) {
+ this.visible = false
+ this.$emit("ok")
+ }
+ })
+ }
+ }
+}
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/sgd-ui/src/views/tool/gen/index.vue
similarity index 100%
rename from ruoyi-ui/src/views/tool/gen/index.vue
rename to sgd-ui/src/views/tool/gen/index.vue
diff --git a/sgd-ui/vue.config.js b/sgd-ui/vue.config.js
new file mode 100644
index 0000000..cfdb6ea
--- /dev/null
+++ b/sgd-ui/vue.config.js
@@ -0,0 +1,129 @@
+'use strict'
+const path = require('path')
+
+function resolve(dir) {
+ return path.join(__dirname, dir)
+}
+
+const CompressionPlugin = require('compression-webpack-plugin')
+
+const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
+
+const port = process.env.port || process.env.npm_config_port || 80 // 端口
+
+// vue.config.js 配置说明
+//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
+// 这里只列一部分,具体配置参考文档
+module.exports = {
+ // 部署生产环境和开发环境下的URL。
+ // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
+ // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
+ publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
+ // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
+ outputDir: 'dist',
+ // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
+ assetsDir: 'static',
+ // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
+ productionSourceMap: false,
+ transpileDependencies: ['quill'],
+ // webpack-dev-server 相关配置
+ devServer: {
+ host: '0.0.0.0',
+ port: port,
+ open: true,
+ proxy: {
+ // detail: https://cli.vuejs.org/config/#devserver-proxy
+ [process.env.VUE_APP_BASE_API]: {
+ target: `http://localhost:18080`,
+ changeOrigin: true,
+ pathRewrite: {
+ ['^' + process.env.VUE_APP_BASE_API]: ''
+ }
+ }
+ },
+ disableHostCheck: true
+ },
+ css: {
+ loaderOptions: {
+ sass: {
+ sassOptions: { outputStyle: "expanded" }
+ }
+ }
+ },
+ configureWebpack: {
+ name: name,
+ resolve: {
+ alias: {
+ '@': resolve('src')
+ }
+ },
+ plugins: [
+ // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
+ new CompressionPlugin({
+ cache: false, // 不启用文件缓存
+ test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i, // 压缩文件格式
+ filename: '[path][base].gz[query]', // 压缩后的文件名
+ algorithm: 'gzip', // 使用gzip压缩
+ minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩
+ deleteOriginalAssets: false // 压缩后删除原文件
+ })
+ ],
+ },
+ chainWebpack(config) {
+ config.plugins.delete('preload') // TODO: need test
+ config.plugins.delete('prefetch') // TODO: need test
+
+ // set svg-sprite-loader
+ config.module
+ .rule('svg')
+ .exclude.add(resolve('src/assets/icons'))
+ .end()
+ config.module
+ .rule('icons')
+ .test(/\.svg$/)
+ .include.add(resolve('src/assets/icons'))
+ .end()
+ .use('svg-sprite-loader')
+ .loader('svg-sprite-loader')
+ .options({
+ symbolId: 'icon-[name]'
+ })
+ .end()
+
+ config.when(process.env.NODE_ENV !== 'development', config => {
+ config
+ .plugin('ScriptExtHtmlWebpackPlugin')
+ .after('html')
+ .use('script-ext-html-webpack-plugin', [{
+ // `runtime` must same as runtimeChunk name. default is `runtime`
+ inline: /runtime\..*\.js$/
+ }])
+ .end()
+
+ config.optimization.splitChunks({
+ chunks: 'all',
+ cacheGroups: {
+ libs: {
+ name: 'chunk-libs',
+ test: /[\\/]node_modules[\\/]/,
+ priority: 10,
+ chunks: 'initial' // only package third parties that are initially dependent
+ },
+ elementUI: {
+ name: 'chunk-elementUI', // split elementUI into a single package
+ test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
+ priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
+ },
+ commons: {
+ name: 'chunk-commons',
+ test: resolve('src/components'), // can customize your rules
+ minChunks: 3, // minimum common number
+ priority: 5,
+ reuseExistingChunk: true
+ }
+ }
+ })
+ config.optimization.runtimeChunk('single')
+ })
+ }
+}
--
Gitblit v1.9.3