From 632d32c0c6bd0767fa0e78e38e19893399bfc5b4 Mon Sep 17 00:00:00 2001 From: haotian <2421912570@qq.com> Date: Fri, 25 Jul 2025 10:03:06 +0800 Subject: [PATCH] original_project --- README.md | 146 ++++ admin-api/.gitignore | 8 + admin-api/Dockerfile | 27 + admin-api/application/__init__.py | 2 + admin-api/application/asgi.py | 16 + admin-api/application/settings.py | 110 +++ admin-api/application/urls.py | 21 + admin-api/application/wsgi.py | 15 + admin-api/build.sh | 3 + admin-api/config.py | 68 ++ admin-api/createDatabase.py | 32 + admin-api/crontab/myScheduler.py | 20 + admin-api/database/core.py | 25 + admin-api/docker-compose.yaml | 21 + admin-api/gunicorn.conf.py | 42 + admin-api/initDatabase.py | 386 +++++++++ admin-api/manage.py | 20 + admin-api/middleware/myAuthorization.py | 50 ++ admin-api/middleware/myMiddleware.py | 80 ++ admin-api/requirements.txt | Bin 0 -> 994 bytes admin-api/utils/myDataUtils.py | 291 +++++++ admin-api/utils/myEncrypt.py | 59 ++ admin-api/utils/myEnum.py | 54 ++ admin-api/utils/myResFormat.py | 48 ++ admin-api/utils/mySnowflake.py | 122 +++ admin-api/utils/myTimeFormat.py | 41 + admin-api/web/__init__.py | 0 admin-api/web/admin.py | 3 + admin-api/web/apps.py | 6 + admin-api/web/captchaImage.py | 109 +++ admin-api/web/migrations/0001_initial.py | 37 + .../web/migrations/0002_auto_20240531_1456.py | 174 ++++ .../web/migrations/0003_auto_20240531_2104.py | 21 + .../web/migrations/0004_auto_20240614_1628.py | 58 ++ admin-api/web/migrations/__init__.py | 0 admin-api/web/models.py | 108 +++ admin-api/web/paginator.py | 42 + admin-api/web/serializer.py | 55 ++ admin-api/web/static/fontBold.ttf | Bin 0 -> 705684 bytes admin-api/web/system/urls.py | 48 ++ admin-api/web/system/views.py | 776 ++++++++++++++++++ admin-api/web/tests.py | 3 + admin-api/web/urls.py | 10 + admin-api/web/views.py | 199 +++++ admin-ui/.env.development | 9 + admin-ui/.env.production | 11 + admin-ui/.env.staging | 11 + admin-ui/.gitignore | 23 + admin-ui/Dockerfile | 4 + admin-ui/LICENSE | 0 admin-ui/build.sh | 4 + admin-ui/docker-compose.yaml | 18 + admin-ui/html/ie.html | 46 ++ admin-ui/index.html | 216 +++++ admin-ui/package.json | 45 + admin-ui/public/favicon.ico | Bin 0 -> 5663 bytes admin-ui/src/App.vue | 15 + admin-ui/src/api/login.js | 51 ++ admin-ui/src/api/menu.js | 9 + admin-ui/src/api/monitor/cache.js | 57 ++ admin-ui/src/api/monitor/job.js | 71 ++ admin-ui/src/api/monitor/jobLog.js | 26 + admin-ui/src/api/monitor/logininfor.js | 34 + admin-ui/src/api/monitor/online.js | 18 + admin-ui/src/api/monitor/operlog.js | 26 + admin-ui/src/api/monitor/server.js | 9 + admin-ui/src/api/system/config.js | 60 ++ admin-ui/src/api/system/dept.js | 52 ++ admin-ui/src/api/system/dict/data.js | 52 ++ admin-ui/src/api/system/dict/type.js | 60 ++ admin-ui/src/api/system/menu.js | 60 ++ admin-ui/src/api/system/notice.js | 44 + admin-ui/src/api/system/post.js | 44 + admin-ui/src/api/system/role.js | 119 +++ admin-ui/src/api/system/user.js | 135 +++ admin-ui/src/api/tool/gen.js | 76 ++ admin-ui/src/assets/icons/svg/404.svg | 1 + admin-ui/src/assets/icons/svg/bug.svg | 1 + admin-ui/src/assets/icons/svg/build.svg | 1 + admin-ui/src/assets/icons/svg/button.svg | 1 + admin-ui/src/assets/icons/svg/cascader.svg | 1 + admin-ui/src/assets/icons/svg/chart.svg | 1 + admin-ui/src/assets/icons/svg/checkbox.svg | 1 + admin-ui/src/assets/icons/svg/clipboard.svg | 1 + admin-ui/src/assets/icons/svg/code.svg | 1 + admin-ui/src/assets/icons/svg/color.svg | 1 + admin-ui/src/assets/icons/svg/component.svg | 1 + admin-ui/src/assets/icons/svg/dashboard.svg | 1 + admin-ui/src/assets/icons/svg/date-range.svg | 1 + admin-ui/src/assets/icons/svg/date.svg | 1 + admin-ui/src/assets/icons/svg/dict.svg | 1 + .../src/assets/icons/svg/documentation.svg | 1 + admin-ui/src/assets/icons/svg/download.svg | 1 + admin-ui/src/assets/icons/svg/drag.svg | 1 + admin-ui/src/assets/icons/svg/druid.svg | 1 + admin-ui/src/assets/icons/svg/edit.svg | 1 + admin-ui/src/assets/icons/svg/education.svg | 1 + admin-ui/src/assets/icons/svg/email.svg | 1 + admin-ui/src/assets/icons/svg/example.svg | 1 + admin-ui/src/assets/icons/svg/excel.svg | 1 + .../src/assets/icons/svg/exit-fullscreen.svg | 1 + admin-ui/src/assets/icons/svg/eye-open.svg | 1 + admin-ui/src/assets/icons/svg/eye.svg | 1 + admin-ui/src/assets/icons/svg/form.svg | 1 + admin-ui/src/assets/icons/svg/fullscreen.svg | 1 + admin-ui/src/assets/icons/svg/github.svg | 1 + admin-ui/src/assets/icons/svg/guide.svg | 1 + admin-ui/src/assets/icons/svg/icon.svg | 1 + admin-ui/src/assets/icons/svg/input.svg | 1 + .../src/assets/icons/svg/international.svg | 1 + admin-ui/src/assets/icons/svg/job.svg | 1 + admin-ui/src/assets/icons/svg/language.svg | 1 + admin-ui/src/assets/icons/svg/link.svg | 1 + admin-ui/src/assets/icons/svg/list.svg | 1 + admin-ui/src/assets/icons/svg/lock.svg | 1 + admin-ui/src/assets/icons/svg/log.svg | 1 + admin-ui/src/assets/icons/svg/logininfor.svg | 1 + admin-ui/src/assets/icons/svg/message.svg | 1 + admin-ui/src/assets/icons/svg/money.svg | 1 + admin-ui/src/assets/icons/svg/monitor.svg | 2 + admin-ui/src/assets/icons/svg/nested.svg | 1 + admin-ui/src/assets/icons/svg/number.svg | 1 + admin-ui/src/assets/icons/svg/online.svg | 1 + admin-ui/src/assets/icons/svg/password.svg | 1 + admin-ui/src/assets/icons/svg/pdf.svg | 1 + admin-ui/src/assets/icons/svg/people.svg | 1 + admin-ui/src/assets/icons/svg/peoples.svg | 1 + admin-ui/src/assets/icons/svg/phone.svg | 1 + admin-ui/src/assets/icons/svg/post.svg | 1 + admin-ui/src/assets/icons/svg/qq.svg | 1 + admin-ui/src/assets/icons/svg/question.svg | 1 + admin-ui/src/assets/icons/svg/radio.svg | 1 + admin-ui/src/assets/icons/svg/rate.svg | 1 + admin-ui/src/assets/icons/svg/redis-list.svg | 2 + admin-ui/src/assets/icons/svg/redis.svg | 1 + admin-ui/src/assets/icons/svg/row.svg | 1 + admin-ui/src/assets/icons/svg/search.svg | 1 + admin-ui/src/assets/icons/svg/select.svg | 1 + admin-ui/src/assets/icons/svg/server.svg | 1 + admin-ui/src/assets/icons/svg/shopping.svg | 1 + admin-ui/src/assets/icons/svg/size.svg | 1 + admin-ui/src/assets/icons/svg/skill.svg | 1 + admin-ui/src/assets/icons/svg/slider.svg | 1 + admin-ui/src/assets/icons/svg/star.svg | 1 + admin-ui/src/assets/icons/svg/swagger.svg | 1 + admin-ui/src/assets/icons/svg/switch.svg | 1 + admin-ui/src/assets/icons/svg/system.svg | 2 + admin-ui/src/assets/icons/svg/tab.svg | 1 + admin-ui/src/assets/icons/svg/table.svg | 1 + admin-ui/src/assets/icons/svg/textarea.svg | 1 + admin-ui/src/assets/icons/svg/theme.svg | 1 + admin-ui/src/assets/icons/svg/time-range.svg | 1 + admin-ui/src/assets/icons/svg/time.svg | 1 + admin-ui/src/assets/icons/svg/tool.svg | 1 + admin-ui/src/assets/icons/svg/tree-table.svg | 1 + admin-ui/src/assets/icons/svg/tree.svg | 1 + admin-ui/src/assets/icons/svg/upload.svg | 1 + admin-ui/src/assets/icons/svg/user.svg | 1 + admin-ui/src/assets/icons/svg/validCode.svg | 1 + admin-ui/src/assets/icons/svg/wechat.svg | 1 + admin-ui/src/assets/icons/svg/zip.svg | 1 + admin-ui/src/assets/images/dark.svg | 39 + admin-ui/src/assets/images/light.svg | 39 + admin-ui/src/assets/styles/btn.scss | 99 +++ admin-ui/src/assets/styles/element-ui.scss | 96 +++ admin-ui/src/assets/styles/index.scss | 184 +++++ admin-ui/src/assets/styles/mixin.scss | 66 ++ admin-ui/src/assets/styles/ruoyi.scss | 281 +++++++ admin-ui/src/assets/styles/sidebar.scss | 238 ++++++ admin-ui/src/assets/styles/transition.scss | 49 ++ .../src/assets/styles/variables.module.scss | 65 ++ admin-ui/src/components/Breadcrumb/index.vue | 66 ++ admin-ui/src/components/Crontab/day.vue | 174 ++++ admin-ui/src/components/Crontab/hour.vue | 127 +++ admin-ui/src/components/Crontab/index.vue | 310 +++++++ admin-ui/src/components/Crontab/min.vue | 126 +++ admin-ui/src/components/Crontab/month.vue | 141 ++++ admin-ui/src/components/Crontab/result.vue | 540 ++++++++++++ admin-ui/src/components/Crontab/second.vue | 128 +++ admin-ui/src/components/Crontab/week.vue | 197 +++++ admin-ui/src/components/Crontab/year.vue | 149 ++++ admin-ui/src/components/DictTag/index.vue | 82 ++ admin-ui/src/components/Editor/index.vue | 251 ++++++ admin-ui/src/components/FileUpload/index.vue | 207 +++++ admin-ui/src/components/Hamburger/index.vue | 41 + .../src/components/HeaderSearch/index.vue | 187 +++++ admin-ui/src/components/IconSelect/index.vue | 111 +++ .../src/components/IconSelect/requireIcons.js | 8 + .../src/components/ImagePreview/index.vue | 92 +++ admin-ui/src/components/ImageUpload/index.vue | 213 +++++ admin-ui/src/components/Pagination/index.vue | 105 +++ admin-ui/src/components/ParentView/index.vue | 3 + .../src/components/RightToolbar/index.vue | 134 +++ admin-ui/src/components/SvgIcon/index.vue | 53 ++ admin-ui/src/components/SvgIcon/svgicon.js | 10 + admin-ui/src/components/TopNav/index.vue | 214 +++++ admin-ui/src/components/TreeSelect/index.vue | 156 ++++ admin-ui/src/components/iFrame/index.vue | 31 + admin-ui/src/directive/common/copyText.js | 66 ++ admin-ui/src/directive/index.js | 9 + admin-ui/src/directive/permission/hasPermi.js | 28 + admin-ui/src/directive/permission/hasRole.js | 28 + admin-ui/src/layout/components/AppMain.vue | 68 ++ .../layout/components/IframeToggle/index.vue | 25 + .../src/layout/components/InnerLink/index.vue | 24 + admin-ui/src/layout/components/Navbar.vue | 174 ++++ .../src/layout/components/Settings/index.vue | 205 +++++ .../src/layout/components/Sidebar/Link.vue | 40 + .../src/layout/components/Sidebar/Logo.vue | 81 ++ .../layout/components/Sidebar/SidebarItem.vue | 102 +++ .../src/layout/components/Sidebar/index.vue | 54 ++ .../layout/components/TagsView/ScrollPane.vue | 105 +++ .../src/layout/components/TagsView/index.vue | 338 ++++++++ admin-ui/src/layout/components/index.js | 4 + admin-ui/src/layout/index.vue | 111 +++ admin-ui/src/main.js | 84 ++ admin-ui/src/permission.js | 79 ++ admin-ui/src/plugins/auth.js | 60 ++ admin-ui/src/plugins/cache.js | 77 ++ admin-ui/src/plugins/download.js | 79 ++ admin-ui/src/plugins/index.js | 18 + admin-ui/src/plugins/modal.js | 82 ++ admin-ui/src/plugins/tab.js | 69 ++ admin-ui/src/router/index.js | 134 +++ admin-ui/src/settings.js | 47 ++ admin-ui/src/store/index.js | 3 + admin-ui/src/store/modules/app.js | 46 ++ admin-ui/src/store/modules/dict.js | 57 ++ admin-ui/src/store/modules/permission.js | 142 ++++ admin-ui/src/store/modules/settings.js | 38 + admin-ui/src/store/modules/tagsView.js | 182 ++++ admin-ui/src/store/modules/user.js | 72 ++ admin-ui/src/utils/auth.js | 15 + admin-ui/src/utils/dict.js | 24 + admin-ui/src/utils/dynamicTitle.js | 15 + admin-ui/src/utils/errorCode.js | 6 + admin-ui/src/utils/index.js | 390 +++++++++ admin-ui/src/utils/jsencrypt.js | 30 + admin-ui/src/utils/permission.js | 51 ++ admin-ui/src/utils/request.js | 152 ++++ admin-ui/src/utils/ruoyi.js | 246 ++++++ admin-ui/src/utils/scroll-to.js | 58 ++ admin-ui/src/utils/theme.js | 49 ++ admin-ui/src/utils/validate.js | 93 +++ admin-ui/src/views/error/401.vue | 82 ++ admin-ui/src/views/error/404.vue | 227 +++++ admin-ui/src/views/index.vue | 23 + admin-ui/src/views/login.vue | 228 +++++ admin-ui/src/views/redirect/index.vue | 14 + admin-ui/src/views/register.vue | 216 +++++ admin-ui/src/views/system/dept/index.vue | 381 +++++++++ admin-ui/src/views/system/menu/index.vue | 462 +++++++++++ admin-ui/src/views/system/role/authUser.vue | 171 ++++ admin-ui/src/views/system/role/index.vue | 630 ++++++++++++++ admin-ui/src/views/system/role/selectUser.vue | 138 ++++ admin-ui/src/views/system/user/authRole.vue | 112 +++ admin-ui/src/views/system/user/index.vue | 482 +++++++++++ .../src/views/system/user/profile/index.vue | 80 ++ .../views/system/user/profile/resetPwd.vue | 57 ++ .../views/system/user/profile/userAvatar.vue | 171 ++++ .../views/system/user/profile/userInfo.vue | 62 ++ admin-ui/vite.config.js | 64 ++ admin-ui/vite/plugins/auto-import.js | 12 + admin-ui/vite/plugins/compression.js | 28 + admin-ui/vite/plugins/index.js | 15 + admin-ui/vite/plugins/setup-extend.js | 5 + admin-ui/vite/plugins/svg-icon.js | 10 + 267 files changed, 17391 insertions(+) create mode 100644 README.md create mode 100644 admin-api/.gitignore create mode 100644 admin-api/Dockerfile create mode 100644 admin-api/application/__init__.py create mode 100644 admin-api/application/asgi.py create mode 100644 admin-api/application/settings.py create mode 100644 admin-api/application/urls.py create mode 100644 admin-api/application/wsgi.py create mode 100644 admin-api/build.sh create mode 100644 admin-api/config.py create mode 100644 admin-api/createDatabase.py create mode 100644 admin-api/crontab/myScheduler.py create mode 100644 admin-api/database/core.py create mode 100644 admin-api/docker-compose.yaml create mode 100644 admin-api/gunicorn.conf.py create mode 100644 admin-api/initDatabase.py create mode 100644 admin-api/manage.py create mode 100644 admin-api/middleware/myAuthorization.py create mode 100644 admin-api/middleware/myMiddleware.py create mode 100644 admin-api/requirements.txt create mode 100644 admin-api/utils/myDataUtils.py create mode 100644 admin-api/utils/myEncrypt.py create mode 100644 admin-api/utils/myEnum.py create mode 100644 admin-api/utils/myResFormat.py create mode 100644 admin-api/utils/mySnowflake.py create mode 100644 admin-api/utils/myTimeFormat.py create mode 100644 admin-api/web/__init__.py create mode 100644 admin-api/web/admin.py create mode 100644 admin-api/web/apps.py create mode 100644 admin-api/web/captchaImage.py create mode 100644 admin-api/web/migrations/0001_initial.py create mode 100644 admin-api/web/migrations/0002_auto_20240531_1456.py create mode 100644 admin-api/web/migrations/0003_auto_20240531_2104.py create mode 100644 admin-api/web/migrations/0004_auto_20240614_1628.py create mode 100644 admin-api/web/migrations/__init__.py create mode 100644 admin-api/web/models.py create mode 100644 admin-api/web/paginator.py create mode 100644 admin-api/web/serializer.py create mode 100644 admin-api/web/static/fontBold.ttf create mode 100644 admin-api/web/system/urls.py create mode 100644 admin-api/web/system/views.py create mode 100644 admin-api/web/tests.py create mode 100644 admin-api/web/urls.py create mode 100644 admin-api/web/views.py create mode 100644 admin-ui/.env.development create mode 100644 admin-ui/.env.production create mode 100644 admin-ui/.env.staging create mode 100644 admin-ui/.gitignore create mode 100644 admin-ui/Dockerfile create mode 100644 admin-ui/LICENSE create mode 100644 admin-ui/build.sh create mode 100644 admin-ui/docker-compose.yaml create mode 100644 admin-ui/html/ie.html create mode 100644 admin-ui/index.html create mode 100644 admin-ui/package.json create mode 100644 admin-ui/public/favicon.ico create mode 100644 admin-ui/src/App.vue create mode 100644 admin-ui/src/api/login.js create mode 100644 admin-ui/src/api/menu.js create mode 100644 admin-ui/src/api/monitor/cache.js create mode 100644 admin-ui/src/api/monitor/job.js create mode 100644 admin-ui/src/api/monitor/jobLog.js create mode 100644 admin-ui/src/api/monitor/logininfor.js create mode 100644 admin-ui/src/api/monitor/online.js create mode 100644 admin-ui/src/api/monitor/operlog.js create mode 100644 admin-ui/src/api/monitor/server.js create mode 100644 admin-ui/src/api/system/config.js create mode 100644 admin-ui/src/api/system/dept.js create mode 100644 admin-ui/src/api/system/dict/data.js create mode 100644 admin-ui/src/api/system/dict/type.js create mode 100644 admin-ui/src/api/system/menu.js create mode 100644 admin-ui/src/api/system/notice.js create mode 100644 admin-ui/src/api/system/post.js create mode 100644 admin-ui/src/api/system/role.js create mode 100644 admin-ui/src/api/system/user.js create mode 100644 admin-ui/src/api/tool/gen.js create mode 100644 admin-ui/src/assets/icons/svg/404.svg create mode 100644 admin-ui/src/assets/icons/svg/bug.svg create mode 100644 admin-ui/src/assets/icons/svg/build.svg create mode 100644 admin-ui/src/assets/icons/svg/button.svg create mode 100644 admin-ui/src/assets/icons/svg/cascader.svg create mode 100644 admin-ui/src/assets/icons/svg/chart.svg create mode 100644 admin-ui/src/assets/icons/svg/checkbox.svg create mode 100644 admin-ui/src/assets/icons/svg/clipboard.svg create mode 100644 admin-ui/src/assets/icons/svg/code.svg create mode 100644 admin-ui/src/assets/icons/svg/color.svg create mode 100644 admin-ui/src/assets/icons/svg/component.svg create mode 100644 admin-ui/src/assets/icons/svg/dashboard.svg create mode 100644 admin-ui/src/assets/icons/svg/date-range.svg create mode 100644 admin-ui/src/assets/icons/svg/date.svg create mode 100644 admin-ui/src/assets/icons/svg/dict.svg create mode 100644 admin-ui/src/assets/icons/svg/documentation.svg create mode 100644 admin-ui/src/assets/icons/svg/download.svg create mode 100644 admin-ui/src/assets/icons/svg/drag.svg create mode 100644 admin-ui/src/assets/icons/svg/druid.svg create mode 100644 admin-ui/src/assets/icons/svg/edit.svg create mode 100644 admin-ui/src/assets/icons/svg/education.svg create mode 100644 admin-ui/src/assets/icons/svg/email.svg create mode 100644 admin-ui/src/assets/icons/svg/example.svg create mode 100644 admin-ui/src/assets/icons/svg/excel.svg create mode 100644 admin-ui/src/assets/icons/svg/exit-fullscreen.svg create mode 100644 admin-ui/src/assets/icons/svg/eye-open.svg create mode 100644 admin-ui/src/assets/icons/svg/eye.svg create mode 100644 admin-ui/src/assets/icons/svg/form.svg create mode 100644 admin-ui/src/assets/icons/svg/fullscreen.svg create mode 100644 admin-ui/src/assets/icons/svg/github.svg create mode 100644 admin-ui/src/assets/icons/svg/guide.svg create mode 100644 admin-ui/src/assets/icons/svg/icon.svg create mode 100644 admin-ui/src/assets/icons/svg/input.svg create mode 100644 admin-ui/src/assets/icons/svg/international.svg create mode 100644 admin-ui/src/assets/icons/svg/job.svg create mode 100644 admin-ui/src/assets/icons/svg/language.svg create mode 100644 admin-ui/src/assets/icons/svg/link.svg create mode 100644 admin-ui/src/assets/icons/svg/list.svg create mode 100644 admin-ui/src/assets/icons/svg/lock.svg create mode 100644 admin-ui/src/assets/icons/svg/log.svg create mode 100644 admin-ui/src/assets/icons/svg/logininfor.svg create mode 100644 admin-ui/src/assets/icons/svg/message.svg create mode 100644 admin-ui/src/assets/icons/svg/money.svg create mode 100644 admin-ui/src/assets/icons/svg/monitor.svg create mode 100644 admin-ui/src/assets/icons/svg/nested.svg create mode 100644 admin-ui/src/assets/icons/svg/number.svg create mode 100644 admin-ui/src/assets/icons/svg/online.svg create mode 100644 admin-ui/src/assets/icons/svg/password.svg create mode 100644 admin-ui/src/assets/icons/svg/pdf.svg create mode 100644 admin-ui/src/assets/icons/svg/people.svg create mode 100644 admin-ui/src/assets/icons/svg/peoples.svg create mode 100644 admin-ui/src/assets/icons/svg/phone.svg create mode 100644 admin-ui/src/assets/icons/svg/post.svg create mode 100644 admin-ui/src/assets/icons/svg/qq.svg create mode 100644 admin-ui/src/assets/icons/svg/question.svg create mode 100644 admin-ui/src/assets/icons/svg/radio.svg create mode 100644 admin-ui/src/assets/icons/svg/rate.svg create mode 100644 admin-ui/src/assets/icons/svg/redis-list.svg create mode 100644 admin-ui/src/assets/icons/svg/redis.svg create mode 100644 admin-ui/src/assets/icons/svg/row.svg create mode 100644 admin-ui/src/assets/icons/svg/search.svg create mode 100644 admin-ui/src/assets/icons/svg/select.svg create mode 100644 admin-ui/src/assets/icons/svg/server.svg create mode 100644 admin-ui/src/assets/icons/svg/shopping.svg create mode 100644 admin-ui/src/assets/icons/svg/size.svg create mode 100644 admin-ui/src/assets/icons/svg/skill.svg create mode 100644 admin-ui/src/assets/icons/svg/slider.svg create mode 100644 admin-ui/src/assets/icons/svg/star.svg create mode 100644 admin-ui/src/assets/icons/svg/swagger.svg create mode 100644 admin-ui/src/assets/icons/svg/switch.svg create mode 100644 admin-ui/src/assets/icons/svg/system.svg create mode 100644 admin-ui/src/assets/icons/svg/tab.svg create mode 100644 admin-ui/src/assets/icons/svg/table.svg create mode 100644 admin-ui/src/assets/icons/svg/textarea.svg create mode 100644 admin-ui/src/assets/icons/svg/theme.svg create mode 100644 admin-ui/src/assets/icons/svg/time-range.svg create mode 100644 admin-ui/src/assets/icons/svg/time.svg create mode 100644 admin-ui/src/assets/icons/svg/tool.svg create mode 100644 admin-ui/src/assets/icons/svg/tree-table.svg create mode 100644 admin-ui/src/assets/icons/svg/tree.svg create mode 100644 admin-ui/src/assets/icons/svg/upload.svg create mode 100644 admin-ui/src/assets/icons/svg/user.svg create mode 100644 admin-ui/src/assets/icons/svg/validCode.svg create mode 100644 admin-ui/src/assets/icons/svg/wechat.svg create mode 100644 admin-ui/src/assets/icons/svg/zip.svg create mode 100644 admin-ui/src/assets/images/dark.svg create mode 100644 admin-ui/src/assets/images/light.svg create mode 100644 admin-ui/src/assets/styles/btn.scss create mode 100644 admin-ui/src/assets/styles/element-ui.scss create mode 100644 admin-ui/src/assets/styles/index.scss create mode 100644 admin-ui/src/assets/styles/mixin.scss create mode 100644 admin-ui/src/assets/styles/ruoyi.scss create mode 100644 admin-ui/src/assets/styles/sidebar.scss create mode 100644 admin-ui/src/assets/styles/transition.scss create mode 100644 admin-ui/src/assets/styles/variables.module.scss create mode 100644 admin-ui/src/components/Breadcrumb/index.vue create mode 100644 admin-ui/src/components/Crontab/day.vue create mode 100644 admin-ui/src/components/Crontab/hour.vue create mode 100644 admin-ui/src/components/Crontab/index.vue create mode 100644 admin-ui/src/components/Crontab/min.vue create mode 100644 admin-ui/src/components/Crontab/month.vue create mode 100644 admin-ui/src/components/Crontab/result.vue create mode 100644 admin-ui/src/components/Crontab/second.vue create mode 100644 admin-ui/src/components/Crontab/week.vue create mode 100644 admin-ui/src/components/Crontab/year.vue create mode 100644 admin-ui/src/components/DictTag/index.vue create mode 100644 admin-ui/src/components/Editor/index.vue create mode 100644 admin-ui/src/components/FileUpload/index.vue create mode 100644 admin-ui/src/components/Hamburger/index.vue create mode 100644 admin-ui/src/components/HeaderSearch/index.vue create mode 100644 admin-ui/src/components/IconSelect/index.vue create mode 100644 admin-ui/src/components/IconSelect/requireIcons.js create mode 100644 admin-ui/src/components/ImagePreview/index.vue create mode 100644 admin-ui/src/components/ImageUpload/index.vue create mode 100644 admin-ui/src/components/Pagination/index.vue create mode 100644 admin-ui/src/components/ParentView/index.vue create mode 100644 admin-ui/src/components/RightToolbar/index.vue create mode 100644 admin-ui/src/components/SvgIcon/index.vue create mode 100644 admin-ui/src/components/SvgIcon/svgicon.js create mode 100644 admin-ui/src/components/TopNav/index.vue create mode 100644 admin-ui/src/components/TreeSelect/index.vue create mode 100644 admin-ui/src/components/iFrame/index.vue create mode 100644 admin-ui/src/directive/common/copyText.js create mode 100644 admin-ui/src/directive/index.js create mode 100644 admin-ui/src/directive/permission/hasPermi.js create mode 100644 admin-ui/src/directive/permission/hasRole.js create mode 100644 admin-ui/src/layout/components/AppMain.vue create mode 100644 admin-ui/src/layout/components/IframeToggle/index.vue create mode 100644 admin-ui/src/layout/components/InnerLink/index.vue create mode 100644 admin-ui/src/layout/components/Navbar.vue create mode 100644 admin-ui/src/layout/components/Settings/index.vue create mode 100644 admin-ui/src/layout/components/Sidebar/Link.vue create mode 100644 admin-ui/src/layout/components/Sidebar/Logo.vue create mode 100644 admin-ui/src/layout/components/Sidebar/SidebarItem.vue create mode 100644 admin-ui/src/layout/components/Sidebar/index.vue create mode 100644 admin-ui/src/layout/components/TagsView/ScrollPane.vue create mode 100644 admin-ui/src/layout/components/TagsView/index.vue create mode 100644 admin-ui/src/layout/components/index.js create mode 100644 admin-ui/src/layout/index.vue create mode 100644 admin-ui/src/main.js create mode 100644 admin-ui/src/permission.js create mode 100644 admin-ui/src/plugins/auth.js create mode 100644 admin-ui/src/plugins/cache.js create mode 100644 admin-ui/src/plugins/download.js create mode 100644 admin-ui/src/plugins/index.js create mode 100644 admin-ui/src/plugins/modal.js create mode 100644 admin-ui/src/plugins/tab.js create mode 100644 admin-ui/src/router/index.js create mode 100644 admin-ui/src/settings.js create mode 100644 admin-ui/src/store/index.js create mode 100644 admin-ui/src/store/modules/app.js create mode 100644 admin-ui/src/store/modules/dict.js create mode 100644 admin-ui/src/store/modules/permission.js create mode 100644 admin-ui/src/store/modules/settings.js create mode 100644 admin-ui/src/store/modules/tagsView.js create mode 100644 admin-ui/src/store/modules/user.js create mode 100644 admin-ui/src/utils/auth.js create mode 100644 admin-ui/src/utils/dict.js create mode 100644 admin-ui/src/utils/dynamicTitle.js create mode 100644 admin-ui/src/utils/errorCode.js create mode 100644 admin-ui/src/utils/index.js create mode 100644 admin-ui/src/utils/jsencrypt.js create mode 100644 admin-ui/src/utils/permission.js create mode 100644 admin-ui/src/utils/request.js create mode 100644 admin-ui/src/utils/ruoyi.js create mode 100644 admin-ui/src/utils/scroll-to.js create mode 100644 admin-ui/src/utils/theme.js create mode 100644 admin-ui/src/utils/validate.js create mode 100644 admin-ui/src/views/error/401.vue create mode 100644 admin-ui/src/views/error/404.vue create mode 100644 admin-ui/src/views/index.vue create mode 100644 admin-ui/src/views/login.vue create mode 100644 admin-ui/src/views/redirect/index.vue create mode 100644 admin-ui/src/views/register.vue create mode 100644 admin-ui/src/views/system/dept/index.vue create mode 100644 admin-ui/src/views/system/menu/index.vue create mode 100644 admin-ui/src/views/system/role/authUser.vue create mode 100644 admin-ui/src/views/system/role/index.vue create mode 100644 admin-ui/src/views/system/role/selectUser.vue create mode 100644 admin-ui/src/views/system/user/authRole.vue create mode 100644 admin-ui/src/views/system/user/index.vue create mode 100644 admin-ui/src/views/system/user/profile/index.vue create mode 100644 admin-ui/src/views/system/user/profile/resetPwd.vue create mode 100644 admin-ui/src/views/system/user/profile/userAvatar.vue create mode 100644 admin-ui/src/views/system/user/profile/userInfo.vue create mode 100644 admin-ui/vite.config.js create mode 100644 admin-ui/vite/plugins/auto-import.js create mode 100644 admin-ui/vite/plugins/compression.js create mode 100644 admin-ui/vite/plugins/index.js create mode 100644 admin-ui/vite/plugins/setup-extend.js create mode 100644 admin-ui/vite/plugins/svg-icon.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..6016170 --- /dev/null +++ b/README.md @@ -0,0 +1,146 @@ +

django-ruoyi-admin

+

基于django+ 若依(Vue3版本)快速开发框架(v1.0.1)

+ +

+ 👉 个人网站:http://124.71.212.219:8028/ 👈 +

+ +

+ + + + + +

+ +### 平台介绍 + +若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。[若依框架地址]([Vue3](https://v3.cn.vuejs.org)), +但目前主流的若以框架是基于SpringBoot的java开发语言,企业开发前端常用的是若依框架,而后端没有一个属于python版本的后端,因此萌生了调试一套适合python程序员的快速开发框架,删除广告页面和日常开发者不必要的功能,只保留项目的最核心的配置模块,减少初始化的方式,做到入手既可以开发功能 + +python主流框架请查看不同的分支(django+mysql,flask+mongo,sanic-mongo) + + +### 技术栈介绍 + +* 前端技术栈: [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) +若依框架版本。 +* 后端技术栈: [django](https://www.djangoproject.com/) + [mysql](https://www.mysql.com/) + [redis](https://redis.io/) 实现。 + + + + + +
+ +### 框架能力 +* 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +* 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +* 岗位管理:配置系统用户所属担任职务。 +* 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 + +### 代码优化 + +* 后端:收集日常的常用方法,增加常用的企业微信机器人通知,数据加解密等常用方法 +* 后端:数据库配置增加nacos和本地config的配置的2种配置,多种配置方式 +* 后端:配置数据库后,项目启动直接初始化相关数据,不需要导入sql的方式,方便快捷开发进度 +* 前端:删除不必要的广告页面,和不必要的功能,比如日志,人员职位,登陆等相关信息,只保留用户,角色,目录,部门核心的模块功能 +* 前端:收集封装日常中大佬们封装的一些方法和看到的一些好的方法,实现工具箱似的开发,开箱即用 +* 前端:优化若依框架的部分ui和提取字段,如title,base_path等变为env配置字段和调试时候的vite代理等均有展示 + +### 前端部署 + +``` +# 本地部署 +# 安装依赖(设置镜像源) +yarn --registry=https://registry.npmmirror.com + +# 启动服务 +yarn run dev + +# 打包构建 +yarn build:prod + +# 前端访问地址 +http://localhost:80 + +# api地址修改: +vite.config.js文件 server.proxy.target指向后端地址 + +======================================================================= +# 线上docker部署 +# 前提确认宿主机含有node环境,(调试环境) node_version = v21.1.0, +# 安装了yarn 和vite环境 +# npm install -g yarn vite + +# 安装依赖 +yarn --registry=https://registry.npmmirror.com + +# 启动服务 +yarn run dev + +# 打包构建 +yarn build:prod + +# 前端访问地址 +http://localhost:80 + +# api地址修改: +.env.production文件 VITE_APP_BASE_API 属性 + +# 构建命令 +sh build.sh +``` + +### 后端部署 + +``` +本地部署 +# 进入目录 +cd admin-api + +# 安装依赖 +pip install -r requirements.txt + +# 配置数据库 +/config.py 或者 配置nacos地址 (配置mongo和redis的数据) + +# 启动服务 +python mange.py runserver 0.0.0.0:8000 + +======================================================================= +# docker部署(docker-compose) +docker-compose build && docker-compose up -d + +# 或者执行脚本构建(gunicorn部署,已内置调试) +sh build.sh + +内置一个超级管理员账号 +superAdmin/superAdmin +``` + +### 在线体验 + +演示地址:[http://124.71.212.219:8101/#/login](http://124.71.212.219:8101/#/login) + +账号密码:superAdmin/superAdmin + +如果能帮助到您,快速的构建您的项目,麻烦帮我star一下吧,谢谢咯,如果有问题的请加我微信 + +## 演示图 + +
+ + + + + + + + + + + + + +
\ No newline at end of file diff --git a/admin-api/.gitignore b/admin-api/.gitignore new file mode 100644 index 0000000..79a1148 --- /dev/null +++ b/admin-api/.gitignore @@ -0,0 +1,8 @@ +.idea +/chrome +/logs +/meta +/venv +/static +*.pyc +/excel \ No newline at end of file diff --git a/admin-api/Dockerfile b/admin-api/Dockerfile new file mode 100644 index 0000000..f4cc1ba --- /dev/null +++ b/admin-api/Dockerfile @@ -0,0 +1,27 @@ +FROM python:3.7 +WORKDIR /app +COPY . /app +EXPOSE 8085 + +# 安装依赖 +RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ +RUN python -m pip install --upgrade pip +RUN python -m pip install gunicorn +RUN python -m pip install greenlet +RUN python -m pip install eventlet +RUN python -m pip install gevent +RUN python -m pip install -r requirements.txt + +# 创建数据 +RUN python createDatabase.py +RUN python manage.py makemigrations +RUN python manage.py migrate +RUN python initDatabase.py + +# 修改时区 +RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + +# gunicorn部署 需要部署nginx 存在跨域问题, 配置文件 +CMD ["gunicorn" ,"application.wsgi", "-c", "gunicorn.conf.py"] + +# CMD ["python" ,"manage.py", "runserver", "0.0.0.0:8085"] diff --git a/admin-api/application/__init__.py b/admin-api/application/__init__.py new file mode 100644 index 0000000..c45523b --- /dev/null +++ b/admin-api/application/__init__.py @@ -0,0 +1,2 @@ +import pymysql +pymysql.install_as_MySQLdb() \ No newline at end of file diff --git a/admin-api/application/asgi.py b/admin-api/application/asgi.py new file mode 100644 index 0000000..256c1bc --- /dev/null +++ b/admin-api/application/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for application project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') + +application = get_asgi_application() diff --git a/admin-api/application/settings.py b/admin-api/application/settings.py new file mode 100644 index 0000000..5130b36 --- /dev/null +++ b/admin-api/application/settings.py @@ -0,0 +1,110 @@ +""" +Django settings for application project. + +Generated by 'django-admin startproject' using Django 3.2.25. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.2/ref/settings/ +""" + +from pathlib import Path + +from config import config + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-68!wtv#sj9)8*eu7gjr(*9m6v3veg#de!e2(51t)04m$%7abhj' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = config.DEBUG + +ALLOWED_HOSTS = ["*"] + +# Application definition + +INSTALLED_APPS = ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', + 'django.contrib.staticfiles', "django_apscheduler", 'corsheaders', "web.apps.WebConfig" + "web", ] + +MIDDLEWARE = ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', + 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middleware.myMiddleware.AuthMiddleware', 'middleware.myMiddleware.LogMiddleware', ] + +ROOT_URLCONF = 'application.urls' + +TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { + 'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] + +WSGI_APPLICATION = 'application.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases + +DATABASES = {'default': {'ENGINE': config.MYSQL_ENGINE, 'HOST': config.MYSQL_HOST, # 数据库ip + 'PORT': config.MYSQL_PORT, # 数据库端口 + 'USER': config.MYSQL_USER, # 用户名 + 'PASSWORD': config.MYSQL_PASSWORD, # 密码 + 'NAME': config.MYSQL_DB, # 数据库名 + }} + +CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache", "LOCATION": f'redis://:{config.REDIS_PASSWORD or ""}@{config.REDIS_HOST}:6379', + "DECODE_RESPONSES": True, "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient", + "CONNECTION_POOL_KWARGS": {"max_connections": 100, 'decode_responses': True}, + "PASSWORD": config.REDIS_PASSWORD, }}} + +# Password validation +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, + {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, + {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, + {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] + +# Internationalization +# https://docs.djangoproject.com/en/3.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/3.2/howto/static-files/ + +STATIC_URL = '/static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# 允许所有域名跨域(优先选择) +CORS_ORIGIN_ALLOW_ALL = True + +# 跨域白名单请求方式 +CORS_ALLOW_METHODS = ('DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW',) + +# 跨域白名单请求头 +CORS_ALL_HEADERS = ('XMLHttpRequest', 'accept-encoding', 'authorization', 'content-type', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with') + +# 关闭浏览器退出登录 +SESSION_EXPIRE_AT_BROWSER_CLOSE = True + +# 解决浏览器不能设置cookie问题 +SESSION_COOKIE_SAMESITE = None +X_FRAME_OPTIONS = 'ALLOWALL' diff --git a/admin-api/application/urls.py b/admin-api/application/urls.py new file mode 100644 index 0000000..c768fed --- /dev/null +++ b/admin-api/application/urls.py @@ -0,0 +1,21 @@ +"""application URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/3.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.urls import path, include + +urlpatterns = [ + path('api/', include('web.urls')), + path('api/system/', include('web.system.urls')), +] diff --git a/admin-api/application/wsgi.py b/admin-api/application/wsgi.py new file mode 100644 index 0000000..89d4bec --- /dev/null +++ b/admin-api/application/wsgi.py @@ -0,0 +1,15 @@ +""" +WSGI config for application project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ +""" + +import os +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') + +application = get_wsgi_application() diff --git a/admin-api/build.sh b/admin-api/build.sh new file mode 100644 index 0000000..4238d63 --- /dev/null +++ b/admin-api/build.sh @@ -0,0 +1,3 @@ +git pull +docker-compose build +docker-compose up -d \ No newline at end of file diff --git a/admin-api/config.py b/admin-api/config.py new file mode 100644 index 0000000..4dbc354 --- /dev/null +++ b/admin-api/config.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +""" +@Author:mengying +@file: config.py +@date:2023/12/18 9:35 +@email: 652044581@qq.com +@desc: +""" +import nacos +from addict import Dict +import json + + +class Localconfig: + """本地配置(二选一)""" + + # 项目的名称 + PROJECT_NAME = "django-ruoyi-admin" + + # 配置redis缓存地址 + REDIS_HOST = '124.71.212.219' + REDIS_PORT = 6379 + REDIS_DB = 0 + REDIS_PASSWORD = "Zds2Xacb0kbiSGcs" + + # 配置mongo数据库 + MYSQL_DB = "django_ruoyi_admin" # 注: 数据库名不能用-特殊字符 + MYSQL_HOST = "124.71.212.219" + MYSQL_PORT = 3306 + MYSQL_USER = "root" + MYSQL_PASSWORD = "tpZCI6IiJ9" + MYSQL_ENGINE = 'django.db.backends.mysql' + + # 加密随机串(hash-md5) + ENCRYPT_STRING = "c-QULHn+u=-BUSQ$" + + DEBUG = False + + @classmethod + def get_server_config(cls): + return {item: getattr(cls, item) for item in dir(cls)} + + +class NacosClient: + """nacos配置(二选一)""" + + def __init__(self, addr: str = None, namespace: str = None, data_id: str = None, group_id: str = None, + username: str = "nacos", password: str = "nacos"): + self.addr = addr or "120.46.187.114:8848" + self.namespace = namespace or "7d35aedc-ec57-48c8-8489-9974d19a2942" + self.data_id = data_id or "sigin" + self.group_id = group_id or "dev" + self.client = nacos.NacosClient(self.addr, namespace=self.namespace, username=username, password=password) + + def get_server_config(self): + print(self.client.get_config(self.data_id, self.group_id)) + return json.loads(self.client.get_config(self.data_id, self.group_id)) + + +# nacos的配置 +# config = Dict(NacosClient().get_server_config()) + +# 本地的配置 +config = Dict(Localconfig.get_server_config()) + + +if __name__ == '__main__': + print(config.MYSQL_DB) diff --git a/admin-api/createDatabase.py b/admin-api/createDatabase.py new file mode 100644 index 0000000..4456064 --- /dev/null +++ b/admin-api/createDatabase.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/5/31 17:31 +@Email : 652044581@qq.com +@Desc : 创建数据库 +""" +import pymysql + +from config import config + + +def create_database(): + """项目启动自动创建数据表""" + connection = pymysql.connect(host=config.MYSQL_HOST, port=config.MYSQL_PORT, user=config.MYSQL_USER, passwd=config.MYSQL_PASSWORD) + create_database_sql = f"CREATE DATABASE IF NOT EXISTS {config.MYSQL_DB} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + try: + # 创建游标对象 + with connection.cursor() as cursor: + # 执行SQL语句 + cursor.execute(create_database_sql) + # 提交事务 + connection.commit() + except pymysql.MySQLError as e: + print(f"Error: {e}") + finally: + # 关闭数据库连接 + connection.close() + + +# 初始化创建数据库 +create_database() diff --git a/admin-api/crontab/myScheduler.py b/admin-api/crontab/myScheduler.py new file mode 100644 index 0000000..c155f2f --- /dev/null +++ b/admin-api/crontab/myScheduler.py @@ -0,0 +1,20 @@ +from apscheduler.schedulers.background import BackgroundScheduler +from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job +import uuid + +import datetime + +scheduler = BackgroundScheduler() +scheduler.add_jobstore(DjangoJobStore(), "default") + +run_date = datetime.datetime.now() + datetime.timedelta(seconds=20) + + +@register_job(scheduler, "date", id=uuid.uuid4().hex, run_date=run_date, replace_existing=True, + timezone='Asia/Shanghai') +def setUp_database_scheduler(): + print("Setting up database scheduler") + + +register_events(scheduler) +scheduler.start() diff --git a/admin-api/database/core.py b/admin-api/database/core.py new file mode 100644 index 0000000..e7205e8 --- /dev/null +++ b/admin-api/database/core.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/5/30 15:39 +@Email : 652044581@qq.com +@Desc : 功能描述 +""" +from django.db import models + + +class CoreModel(models.Model): + """ + 核心标准抽象模型 + """ + id = models.BigAutoField(primary_key=True, help_text="Id", verbose_name="Id") + update_time = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", verbose_name="修改时间") + create_time = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间", verbose_name="创建时间") + remark = models.CharField(max_length=64, blank=True, verbose_name="备注信息", help_text="备注信息") + createBy = models.CharField(max_length=64, blank=True, verbose_name="创建者", help_text="创建者") + objects = models.Manager() + + class Meta: + abstract = True + verbose_name = '核心模型' + verbose_name_plural = verbose_name diff --git a/admin-api/docker-compose.yaml b/admin-api/docker-compose.yaml new file mode 100644 index 0000000..b6403f1 --- /dev/null +++ b/admin-api/docker-compose.yaml @@ -0,0 +1,21 @@ +version: '3.0' + +services: + + django-vue-api-std: + + build: + context: . + dockerfile: Dockerfile + + image: django-vue-api-image-std + + container_name: django-vue-api-container-std + + volumes: + - /opt/django-vue-admin/logs:/app/logs + + ports: + - "8090:8085" + + restart: always \ No newline at end of file diff --git a/admin-api/gunicorn.conf.py b/admin-api/gunicorn.conf.py new file mode 100644 index 0000000..a83b460 --- /dev/null +++ b/admin-api/gunicorn.conf.py @@ -0,0 +1,42 @@ +# 多进程 + +"""gunicorn+gevent 的配置文件""" + +timeout = 60 * 2 + +# 预加载资源 +# preload_app = True +# 绑定 ip + 端口 +bind = "0.0.0.0:8085" +# 进程数 = cup数量 * 2 + 1 +workers = 4 # multiprocessing.cpu_count() * 2 + 1 + +# 线程数 = cup数量 * 2 +threads = 20 + +max_requests = 1000 + +# 等待队列最大长度,超过这个长度的链接将被拒绝连接 +backlog = 2048 + +# 工作模式--协程 +worker_class = "gevent" + +# 最大客户客户端并发数量,对使用线程和协程的worker的工作有影响 +# 服务器配置设置的值 1200:中小型项目 上万并发: 中大型 +# 服务器硬件:宽带+数据库+内存 +# 服务器的架构:集群 主从 +worker_connections = 1200 + +# 进程名称 +proc_name = 'w2p.pid' +# 进程pid记录文件 +pidfile = 'app_run.log' +# 日志等级 +loglevel = 'debug' +# 日志文件名 +logfile = 'debug.log' +# 访问记录 +accesslog = 'access.log' +# 访问记录格式 +access_log_format = '%(h)s %(t)s %(U)s %(q)s' diff --git a/admin-api/initDatabase.py b/admin-api/initDatabase.py new file mode 100644 index 0000000..d370d4d --- /dev/null +++ b/admin-api/initDatabase.py @@ -0,0 +1,386 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/5/31 17:17 +@Email : 652044581@qq.com +@Desc : 初始化数据 +""" +import os, django + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') +django.setup() + +import logging +from utils.mySnowflake import Sf +from web.models import SystemInit +from web.models import SystemDept, SystemRole, SystemUser, SystemMenu, SystemUserRole +from django_redis import get_redis_connection +from utils.myEnum import SystemUserTypeEnum +from config import config +from utils.myEncrypt import HashCipher + +from redis import Redis + +RedisClient: Redis = get_redis_connection() +logger = logging.getLogger(__file__) + + +class DatabaseUtils(object): + REDIS_KEY = 'init_database' + + @classmethod + def init_database(cls): + """初始化数据库""" + + # 多节点初始化 + if not RedisClient.setnx(cls.REDIS_KEY, cls.REDIS_KEY): + return + + RedisClient.expire(cls.REDIS_KEY, 10) + hasInit: bool = cls.initFlag() + deptId = Sf.generate() + roleId = Sf.generate() + userId = Sf.generate() + + if not hasInit: + cls.initDept(deptId) + cls.initRole(roleId) + cls.initUser(userId) + cls.initUserRole(userId, roleId) + cls.initMenu() + + RedisClient.delete(cls.REDIS_KEY) + logger.info("init database successfully") + + @classmethod + def initDept(cls, deptId): + initDeptData = { + "createBy": "superAdmin", + "deptId": deptId, + "ancestors": "0", + "parentId": "0", + "deptName": "宇驰商贸有限公司", + "orderNum": 0, + "leader": "admin", + "phone": "17783098377", + "email": "652044581@qq.com", + "status": "0", + "delFlag": "0", + } + SystemDept(**initDeptData).save() + + @classmethod + def initRole(cls, roleId): + """初始化角色超级管理员""" + initRoleData = { + "createBy": "superAdmin", + "roleId": roleId, + "roleName": "超级管理员", + "roleAdmin": True, + "roleKey": "superAdmin", + "roleSort": "0", + "status": "0", + "delFlag": "0", + } + SystemRole(**initRoleData).save() + + @classmethod + def initUser(cls, userId): + initUserData = {"userId": userId, + "username": "superAdmin", + "nickName": "superAdmin", + "password": HashCipher.md5(config.ENCRYPT_STRING + "superAdmin"), + "phone": "17783098375", + "email": "652044581@qq.com", + "status": "0", + "userType": SystemUserTypeEnum.p1.value + } + SystemUser(**initUserData).save() + + @classmethod + def initUserRole(cls, userId, roleId): + """初始化用户角色关系""" + initUserRoleData = {"userId": userId, "roleId": roleId} + SystemUserRole(**initUserRoleData).save() + + @classmethod + def initMenu(cls, ): + """初始化前端菜单""" + menuParentId = Sf.generate() + menuUserId = Sf.generate() + menuRoleId = Sf.generate() + menuMenuId = Sf.generate() + menuDeptId = Sf.generate() + initMenuData = [ + { + "menuId": menuParentId, + "menuName": "系统管理", + "parentId": "0", + "orderNum": 3, + "path": "system", + "component": "", + "perms": "", + "query": "", + "menuType": "M", + "icon": "system", + }, + { + "menuId": menuUserId, + "menuName": "用户管理", + "parentId": menuParentId, + "orderNum": 1, + "path": "user", + "component": "system/user/index", + "perms": "system:user:list", + "query": "", + "menuType": "C", + "icon": "user", + }, + + { + "menuId": menuRoleId, + "menuName": "角色管理", + "parentId": menuParentId, + "orderNum": 2, + "path": "role", + "component": "system/role/index", + "perms": "system:role:list", + "query": "", + "menuType": "C", + "icon": "peoples", + }, + { + "menuId": menuMenuId, + "menuName": "菜单管理", + "parentId": menuParentId, + "orderNum": 3, + "path": "menu", + "component": "system/menu/index", + "perms": "system:menu:list", + "query": "", + "menuType": "C", + "icon": "tree-table", + }, + { + "menuId": menuDeptId, + "menuName": "部门管理", + "parentId": menuParentId, + "orderNum": 4, + "path": "dept", + "component": "system/dept/index", + "perms": "system:dept:list", + "query": "", + "menuType": "C", + "icon": "tree", + }, + { + "menuId": Sf.generate(), + "menuName": "用户查询", + "parentId": menuUserId, + "orderNum": 1, + "path": "", + "component": "", + "perms": "system:user:query", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "用户新增", + "parentId": menuUserId, + "orderNum": 2, + "path": "", + "component": "", + "perms": "system:user:add", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "用户修改", + "parentId": menuUserId, + "orderNum": 3, + "path": "", + "component": "", + "perms": "system:user:edit", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "用户删除", + "parentId": menuUserId, + "orderNum": 4, + "path": "", + "component": "", + "perms": "system:user:remove", + "query": "", + "menuType": "F", + "icon": "#", + }, + + { + "menuId": Sf.generate(), + "menuName": "角色查询", + "parentId": menuRoleId, + "orderNum": 1, + "path": "", + "component": "", + "perms": "system:role:query", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "角色新增", + "parentId": menuRoleId, + "orderNum": 2, + "path": "", + "component": "", + "perms": "system:role:add", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "角色修改", + "parentId": menuRoleId, + "orderNum": 3, + "path": "", + "component": "", + "perms": "system:role:edit", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "角色删除", + "parentId": menuRoleId, + "orderNum": 4, + "path": "", + "component": "", + "perms": "system:role:remove", + "query": "", + "menuType": "F", + "icon": "#", + }, + + { + "menuId": Sf.generate(), + "menuName": "菜单查询", + "parentId": menuMenuId, + "orderNum": 1, + "path": "", + "component": "", + "perms": "system:menu:query", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "菜单新增", + "parentId": menuMenuId, + "orderNum": 2, + "path": "", + "component": "", + "perms": "system:menu:add", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "菜单修改", + "parentId": menuMenuId, + "orderNum": 3, + "path": "", + "component": "", + "perms": "system:menu:edit", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "菜单删除", + "parentId": menuMenuId, + "orderNum": 4, + "path": "", + "component": "", + "perms": "system:menu:remove", + "query": "", + "menuType": "F", + "icon": "#", + }, + + { + "menuId": Sf.generate(), + "menuName": "部门查询", + "parentId": menuDeptId, + "orderNum": 1, + "path": "", + "component": "", + "perms": "system:dept:query", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "部门新增", + "parentId": menuDeptId, + "orderNum": 2, + "path": "", + "component": "", + "perms": "system:dept:add", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "部门修改", + "parentId": menuDeptId, + "orderNum": 3, + "path": "", + "component": "", + "perms": "system:dept:edit", + "query": "", + "menuType": "F", + "icon": "#", + }, + { + "menuId": Sf.generate(), + "menuName": "部门删除", + "parentId": menuDeptId, + "orderNum": 4, + "path": "", + "component": "", + "perms": "system:dept:remove", + "query": "", + "menuType": "F", + "icon": "#", + }, + ] + for item in initMenuData: + SystemMenu(**item).save() + + @classmethod + def initFlag(cls): + """防止多次初始化文件""" + init = SystemInit.objects.all() + if not init: + SystemInit(Init=True).save() + return False + else: + return True + + +DatabaseUtils.init_database() diff --git a/admin-api/manage.py b/admin-api/manage.py new file mode 100644 index 0000000..a773519 --- /dev/null +++ b/admin-api/manage.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError("Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?") from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/admin-api/middleware/myAuthorization.py b/admin-api/middleware/myAuthorization.py new file mode 100644 index 0000000..d576617 --- /dev/null +++ b/admin-api/middleware/myAuthorization.py @@ -0,0 +1,50 @@ +# -*- coding: -*- +""" +@Author:mengying +@file: myAuthorization.py +@date:2023/6/14 16:46 +@email: 652044581@qq.com +@desc: 授权相关 +""" +import json + +from django_redis import get_redis_connection + + +class CacheKeys: + TOKEN_NAME = "Authorization" + + +class Authorization: + + @staticmethod + def get_user_info(request): + """从header中获取访问人员信息放在header中""" + RedisClient = get_redis_connection() + + token = request.headers.get(CacheKeys.TOKEN_NAME, '') + + if not token: + setattr(request.headers, "user_info", {}) + return None + + user = RedisClient.get(token) + RedisClient.expire(token, 30 * 60) + + if user: + user = json.loads(user) + user["token"] = token + else: + user = {} + + setattr(request.headers, "user_info", user) + + @staticmethod + def white_list_check(request): + """判断访问名路径是否是白名单""" + + white_list = ['/api/login', '/api/captchaImage', '/api/logout'] + if request.path in white_list: + return True + else: + return False diff --git a/admin-api/middleware/myMiddleware.py b/admin-api/middleware/myMiddleware.py new file mode 100644 index 0000000..3038700 --- /dev/null +++ b/admin-api/middleware/myMiddleware.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/5/30 14:16 +@Email : 652044581@qq.com +@Desc : 功能描述 +""" +import logging +import time +import traceback +import uuid + +from django.http.response import JsonResponse + +from middleware.myAuthorization import Authorization +from utils.myResFormat import ResultJson, ResultCode + +logger = logging.getLogger(__file__) + +from django.utils.deprecation import MiddlewareMixin + + +class AuthMiddleware(MiddlewareMixin): + """用户认证中间件""" + + def process_request(self, request): + # 获取用户信息 + Authorization.get_user_info(request) + + # 检查白名单 + if not Authorization.white_list_check(request): + user_info = getattr(request.headers, 'user_info', {}) + if not user_info: + return JsonResponse(ResultJson(ResultCode.TOKEN_ERROR).result) + + def process_response(self, request, response): # 基于请求响应 + return response + + def process_exception(self, request, exception): + + formatter = ["接口地址 : %s" % request.get_full_path(), "请求方式 : %s" % request.method, "请求参数 : body: %s" % request.body.decode(), + "用户信息 : user: %s" % str(getattr(request.headers, 'user_info', {})), "报错信息 : %s" % str(traceback.format_exc())] + error_message = "\n".join(formatter) + logger.error(error_message) + return JsonResponse(ResultJson(ResultCode.SERVER_ERROR, description=str(exception)).result) + + +class LogMiddleware(MiddlewareMixin): + """记录日志中间件""" + + def process_request(self, request): + uid = uuid.uuid4().hex + setattr(request.headers, "my-duration", time.time()) + setattr(request.headers, "uid", uid) + self.recordsRequest(uid, request.get_full_path(), request.method, request.body.decode()) + + def process_response(self, request, response): # 基于请求响应 + duration = time.time() - getattr(request.headers, "my-duration") + uid = getattr(request.headers, "uid") + self.recordsResponse(uid, request.get_full_path(), response.content.decode(), duration) + return response + + @classmethod + def white_path(cls, path): + request_white_path = [] + return path in request_white_path + + @classmethod + def recordsRequest(cls, uid, path, method, data): + request_info = '链路id: %s 接口: %s 请求方式: %s body参数: %s' % (uid, path, method, data) + if cls.white_path(path): + return + logger.info(str(request_info)) + + @classmethod + def recordsResponse(cls, uid, path, data, duration=None): + response_info = '链路id: %s 接口: %s 返回数据: %s 耗时: %s ' % (uid, path, data, duration) + if cls.white_path(path): + return + logger.info(str(response_info)) diff --git a/admin-api/requirements.txt b/admin-api/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..c80be7835eeea9dcef91308ddde896c8bfa1bcdf GIT binary patch literal 994 zcma)*O;5sL5QO(^;!lCtA{q}KOgtG)Fqn8We9D)l@?!Y-@#-_XLLquEO)0Rmvoo`A zzdk$G=NenjmUhjRTiwpN&+ODr?8aKwrZ%zxs1KX*TsW=)CIcn3kR40*3eN(>aF4j8 zp6}}$E8wazX>4!c<}k+8m{_-lW4o~RY-%Nl1&9R8mhS~UV?Kv`msU-e-psphZ9-px zil|DVs<}12-an|-X~wjT|HNn@SsGLo$^SoMjkTmNba~#sVL<@HbGSx zA0mZII3B{<@r+hJak@`5!_Cg||2k{Gl)Te2&SJfW4 z+xBSp`+9I|Los>ll^nj@vyI;0xmPDPp=f=;Cy${f**i*0Txz!i$3)-mv@g+9(y!C@ z0%DE#0l&nl1gaBJ`B-v>`*14Tc+-xxs;+!`)Mt*UHob+n MAX_WORKER_ID or worker_id < 0: + raise ValueError('worker_id 值越界') + if datacenter_id > MAX_DATACENTER_ID or datacenter_id < 0: + raise ValueError('datacenter_id 值越界') + + self.worker_id = worker_id + self.datacenter_id = datacenter_id + self.sequence = sequence + + self.last_timestamp = -1 # 上次计算的时间戳 + + def _gen_timestamp(self): + """ + 生成整数时间戳。 + :return: + """ + return int(time.time() * 1000) + + def generate(self) -> str: + """ + 获取新的ID. + :return: + """ + # 获取当前时间戳 + timestamp = self._gen_timestamp() + + # 时钟回拨的情况 + if timestamp < self.last_timestamp: + raise Exception("clock is moving backwards") + + if timestamp == self.last_timestamp: + # 同一毫秒的处理。 + self.sequence = (self.sequence + 1) & SEQUENCE_MASK + if self.sequence == 0: + timestamp = self._til_next_millis(self.last_timestamp) + else: + self.sequence = 0 + + self.last_timestamp = timestamp + + new_id = (((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (self.datacenter_id << DATACENTER_ID_SHIFT) | ( + self.worker_id << WORKER_ID_SHIFT)) | self.sequence + return str(new_id) + + def _til_next_millis(self, last_timestamp): + """ + 等到下一毫秒。 + :param last_timestamp: + :return: + """ + timestamp = self._gen_timestamp() + while timestamp <= last_timestamp: + timestamp = self._gen_timestamp() + return timestamp + + +Sf = SnowIdWorker() + +if __name__ == '__main__': + for i in range(1000): + print(Sf.generate()) diff --git a/admin-api/utils/myTimeFormat.py b/admin-api/utils/myTimeFormat.py new file mode 100644 index 0000000..6e6c2f4 --- /dev/null +++ b/admin-api/utils/myTimeFormat.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +@Author: 孟颖 +@email: 652044581@qq.com +@date: 2023/4/23 10:03 +@desc: 时间类,生成各类的时间和时间格式转换 +""" +import time +from datetime import datetime, timedelta + + +class MyTimeUtils: + dateTimeType = '%Y-%m-%d %H:%M:%S' + dateType = '%Y-%m-%d' + timeType = '%H:%M:%S' + fileTimeType = "%Y%m%d%H%M%S%f" + fileTimeShortType = "%Y%m%d%H%M%S" + + @classmethod + def TimeFormat(cls, now_time: datetime = datetime.now(), timeType: str = dateTimeType) -> str: + return now_time.strftime(timeType) + + @classmethod + def TimeFormatCh(cls, now_time: datetime = datetime.now()) -> str: + ch_time = now_time.strftime(cls.dateType) + return "%s年%s月%s日" % tuple(ch_time.split("-")) + + @classmethod + def TimestampFormat(cls, long: bool = False) -> int: + return int(time.time() * 1000) if long else int(time.time()) + + @classmethod + def TimeOffsetFormat(cls, start_time: datetime = datetime.now(), days: int = 0, hour: int = 0, minute: int = 0, second: int = 0, + timeType: str = dateTimeType) -> str: + offsetDateTime = start_time + timedelta(days=days, hours=hour, minutes=minute, seconds=second) + return cls.TimeFormat(offsetDateTime, timeType) + + +if __name__ == '__main__': + print(MyTimeUtils.TimeOffsetFormat(days=-1, timeType=MyTimeUtils.fileTimeType)) + print(MyTimeUtils.TimeFormatCh()) diff --git a/admin-api/web/__init__.py b/admin-api/web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/admin-api/web/admin.py b/admin-api/web/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/admin-api/web/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/admin-api/web/apps.py b/admin-api/web/apps.py new file mode 100644 index 0000000..fa72239 --- /dev/null +++ b/admin-api/web/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class WebConfigweb(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'web' diff --git a/admin-api/web/captchaImage.py b/admin-api/web/captchaImage.py new file mode 100644 index 0000000..246ef40 --- /dev/null +++ b/admin-api/web/captchaImage.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +""" +@Author: 孟颖 +@email: 652044581@qq.com +@date: 2023/4/13 13:36 +@desc: 生成验证码 +""" +import pathlib +import random +from PIL import Image, ImageDraw, ImageFont +from io import BytesIO +import base64 +from pathlib import Path + + +class CaptchaImage: + + def __init__(self, width=130, height=35, string_count=4, font_size=30, noise_line=3, noise_point=30): + """ + :param width: 图片宽度 + :param height: 图片高度 + :param string_count: 验证码的数量 + :param font_size: 字体的大小 + :param noise_line: 噪声线的数量 + :param noise_point: 噪声点的数量 + """ + self.width = width + self.height = height + self.string_count = string_count + self.font_size = font_size + self.noise_line = noise_line + self.noise_point = noise_point + + # 生成验证码 + def generate(self, width=120, height=35): + image = self.background() + captcha_string, image = self.draw_string(image) + image: Image = self.noise(image) + image = image.resize((width, height), resample=Image.BICUBIC) + output_buffer = BytesIO() + image.save(output_buffer, format='png') + binary_data = output_buffer.getvalue() + image_base64 = self.io2base64(binary_data) + return captcha_string, image_base64 + + # io转base64 + def io2base64(self, content: bytes): + encode_data = base64.b64encode(content) + return str(encode_data, encoding='utf-8') + + # 生成背景 + def background(self): + background_color = (255, 255, 255) + image = Image.new('RGB', (self.width, self.height), background_color) + return image + + # 随机颜色 + def random_color(self): + c1 = random.randint(0, 200) + c2 = random.randint(0, 200) + c3 = random.randint(0, 200) + return c1, c2, c3 + + # 生成随机字符串 + def random_string(self): + random_num = str(random.randint(0, 9)) + random_low_alpha = chr(random.randint(97, 122)) + return random.choice([random_num, random_low_alpha]) + + # 合成文字 + def draw_string(self, image: Image): + draw = ImageDraw.Draw(image) + font_file = pathlib.Path.joinpath(Path(__file__).parent, "static/fontBold.ttf").as_posix() + font = ImageFont.truetype(font=font_file, size=self.font_size) + string_container = [] + for i in range(self.string_count): + random_char = self.random_string() + draw.text((10 + i * 30, -2), random_char, self.random_color(), font=font) + string_container.append(random_char) + captcha_string = "".join(string_container) + return captcha_string, image + + # 生成噪声 + def noise(self, image: Image): + + draw = ImageDraw.Draw(image) + # 噪声线 + for i in range(self.noise_line): + x1 = random.randint(0, self.width) + x2 = random.randint(0, self.width) + y1 = random.randint(0, self.height) + y2 = random.randint(0, self.height) + draw.line((x1, y1, x2, y2), fill=self.random_color()) + + # 噪声点 + for i in range(self.noise_point): + draw.point([random.randint(0, self.width), random.randint(0, self.height)], fill=self.random_color()) + x = random.randint(0, self.width) + y = random.randint(0, self.height) + draw.arc((x, y, x + 4, y + 4), 0, 90, fill=self.random_color()) + + return image + + +if __name__ == '__main__': + captcha = CaptchaImage() + + # 生成验证码图片和字符串 + captcha_string, image_base64 = captcha.generate(width=108, height=36) diff --git a/admin-api/web/migrations/0001_initial.py b/admin-api/web/migrations/0001_initial.py new file mode 100644 index 0000000..fd35f32 --- /dev/null +++ b/admin-api/web/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.25 on 2024-05-31 04:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='SystemDept', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('parentId', models.CharField(default='', help_text='父id', max_length=64, verbose_name='父id')), + ('deptName', models.CharField(default='', help_text='部门名称', max_length=64, verbose_name='部门名称')), + ('deptId', models.CharField(default='', help_text='部门id', max_length=64, unique=True, verbose_name='部门id')), + ('orderNum', models.IntegerField(default=0, help_text='排序', verbose_name='排序')), + ('leader', models.CharField(default='', help_text='负责人', max_length=64, verbose_name='负责人')), + ('phone', models.CharField(default='', help_text='联系电话', max_length=64, verbose_name='联系电话')), + ('email', models.CharField(default='', help_text='邮箱', max_length=64, verbose_name='邮箱')), + ('status', models.CharField(default='', help_text='启用状态 (0正常 1停用)', max_length=64, verbose_name='启用状态')), + ('delFlag', models.CharField(default='', help_text='是否删除 (0存在 2删除)', max_length=64, verbose_name='是否删除')), + ('ancestors', models.CharField(default='', help_text='上级目录id', max_length=64, verbose_name='上级目录id')), + ('createBy', models.CharField(default='', help_text='创建者', max_length=64, verbose_name='创建者')), + ], + options={ + 'verbose_name': '部门管理', + 'db_table': 'system_dept', + }, + ), + ] diff --git a/admin-api/web/migrations/0002_auto_20240531_1456.py b/admin-api/web/migrations/0002_auto_20240531_1456.py new file mode 100644 index 0000000..d62a8f9 --- /dev/null +++ b/admin-api/web/migrations/0002_auto_20240531_1456.py @@ -0,0 +1,174 @@ +# Generated by Django 3.2.25 on 2024-05-31 06:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='SystemInit', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('Init', models.BooleanField(blank=True, default=False, help_text='是否已经初始化数据库')), + ], + options={ + 'verbose_name': '核心模型', + 'verbose_name_plural': '核心模型', + 'abstract': False, + }, + ), + migrations.CreateModel( + name='SystemMenu', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('menuId', models.CharField(default='', help_text='菜单ID', max_length=64, unique=True, verbose_name='菜单ID')), + ('menuName', models.CharField(default='', help_text='菜单名称', max_length=64, verbose_name='菜单名称')), + ('parentId', models.CharField(default='', help_text='父菜单ID', max_length=64, verbose_name='父菜单ID')), + ('orderNum', models.IntegerField(default=0, help_text='显示顺序', verbose_name='显示顺序')), + ('path', models.CharField(default='', help_text='路由地址', max_length=64, verbose_name='路由地址')), + ('component', models.CharField(default='', help_text='组件路径', max_length=64, verbose_name='组件路径')), + ('query', models.CharField(default='', help_text='路由参数', max_length=64, verbose_name='路由参数')), + ('isFrame', models.CharField(default='', help_text='是否为外链(0是 1否)', max_length=4, verbose_name='是否为外链(0是 1否)')), + ('isCache', models.CharField(default='', help_text='是否缓存(0缓存 1不缓存)', max_length=4, verbose_name='是否缓存(0缓存 1不缓存)')), + ('visible', models.CharField(default='', help_text='菜单状态(0显示 1隐藏)', max_length=4, verbose_name='菜单状态(0显示 1隐藏)')), + ('menuType', models.CharField(default='', help_text='菜单类型(M目录 C菜单 F按钮)', max_length=4, verbose_name='菜单类型(M目录 C菜单 F按钮)')), + ('status', models.CharField(default='', help_text='菜单状态(0正常 1停用)', max_length=4, verbose_name='菜单状态(0正常 1停用)')), + ('perms', models.CharField(default='', help_text='权限标识', max_length=32, verbose_name='权限标识')), + ('icon', models.CharField(default='', help_text='菜单图', max_length=32, verbose_name='菜单图')), + ], + options={ + 'verbose_name': '目录管理', + 'db_table': 'system_menu', + }, + ), + migrations.CreateModel( + name='SystemRole', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('roleId', models.CharField(default='', help_text='角色id', max_length=64, unique=True, verbose_name='角色id')), + ('roleName', models.CharField(default='', help_text='角色名称', max_length=64, verbose_name='角色名称')), + ('roleKey', models.CharField(default='', help_text='角色权限字符', max_length=64, verbose_name='角色权限字符')), + ('roleSort', models.IntegerField(default=0, help_text='角色排序', verbose_name='角色排序')), + ('roleAdmin', models.BooleanField(default=False, help_text='是否是超级管理员', max_length=64, verbose_name='是否是超级管理员')), + ('status', models.CharField(default='0', help_text='启用状态 (0正常 1停用)', max_length=4, verbose_name='启用状态 (0正常 1停用)')), + ('menuCheckStrictly', models.BooleanField(default=True, help_text='菜单树选择项是否关联显示', verbose_name='菜单树选择项是否关联显示')), + ('deptCheckStrictly', models.BooleanField(default=True, help_text='部门树选择项是否关联显示', verbose_name='部门树选择项是否关联显示')), + ('delFlag', models.CharField(default='0', help_text='是否删除 (0代表存在 2代表删除)', max_length=4, verbose_name='是否删除 (0代表存在 2代表删除)')), + ], + options={ + 'verbose_name': '角色管理', + 'db_table': 'system_role', + }, + ), + migrations.CreateModel( + name='SystemRoleMenu', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('menuId', models.CharField(default='', help_text='菜单id', max_length=64, verbose_name='菜单id')), + ('roleId', models.CharField(default='', help_text='角色id', max_length=64, verbose_name='角色id')), + ], + options={ + 'verbose_name': '角色与目录关系映射', + 'db_table': 'system_role_menu', + }, + ), + migrations.CreateModel( + name='SystemUser', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('userId', models.CharField(default='', help_text='用户id', max_length=64, unique=True, verbose_name='用户id')), + ('deptId', models.CharField(default='', help_text='部门id', max_length=64, verbose_name='部门id')), + ('username', models.CharField(default='', help_text='用户账号', max_length=64, verbose_name='用户账号')), + ('nickName', models.CharField(default='', help_text='用户昵称', max_length=64, verbose_name='用户昵称')), + ('userType', models.CharField(default=False, help_text='用户类型(00系统用户)', max_length=4, verbose_name='用户类型(00系统用户)')), + ('email', models.CharField(default='', help_text='邮箱', max_length=64, verbose_name='邮箱')), + ('phone', models.CharField(default='', help_text='手机号码', max_length=64, verbose_name='手机号码')), + ('avatar', models.CharField(default='', help_text='头像', max_length=64, verbose_name='头像')), + ('password', models.CharField(default='', help_text='密码(加密后)', max_length=64, verbose_name='密码(加密后)')), + ('status', models.CharField(default='0', help_text='帐号状态(0正常 1停用)', max_length=4, verbose_name='帐号状态(0正常 1停用)')), + ('delFlag', models.CharField(default='0', help_text='删除标志(0代表存在 2代表删除)', max_length=4, verbose_name='删除标志(0代表存在 2代表删除)')), + ('loginIp', models.CharField(default='', help_text='最后登陆ip', max_length=64, verbose_name='最后登陆ip')), + ('loginDate', models.CharField(default='', help_text='最后登陆日期', max_length=64, verbose_name='最后登陆日期')), + ], + options={ + 'verbose_name': '用户管理', + 'db_table': 'system_user', + }, + ), + migrations.CreateModel( + name='SystemUserRole', + fields=[ + ('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')), + ('create_time', models.DateTimeField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')), + ('remark', models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息')), + ('createBy', models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者')), + ('userId', models.CharField(default='', help_text='用户id', max_length=64, verbose_name='菜单id')), + ('roleId', models.CharField(default='', help_text='角色id', max_length=64, verbose_name='角色id')), + ], + options={ + 'verbose_name': '角色与人员关系映射', + 'db_table': 'system_role_user', + }, + ), + migrations.AddField( + model_name='systemdept', + name='remark', + field=models.CharField(blank=True, help_text='备注信息', max_length=64, verbose_name='备注信息'), + ), + migrations.AlterField( + model_name='systemdept', + name='createBy', + field=models.CharField(blank=True, help_text='创建者', max_length=64, verbose_name='创建者'), + ), + migrations.AlterField( + model_name='systemdept', + name='delFlag', + field=models.CharField(default='0', help_text='是否删除 (0存在 2删除)', max_length=4, verbose_name='是否删除'), + ), + migrations.AlterField( + model_name='systemdept', + name='email', + field=models.CharField(default='', help_text='邮箱', max_length=32, verbose_name='邮箱'), + ), + migrations.AlterField( + model_name='systemdept', + name='leader', + field=models.CharField(default='', help_text='负责人', max_length=32, verbose_name='负责人'), + ), + migrations.AlterField( + model_name='systemdept', + name='phone', + field=models.CharField(default='', help_text='联系电话', max_length=32, verbose_name='联系电话'), + ), + migrations.AlterField( + model_name='systemdept', + name='status', + field=models.CharField(default='0', help_text='启用状态 (0正常 1停用)', max_length=4, verbose_name='启用状态'), + ), + ] diff --git a/admin-api/web/migrations/0003_auto_20240531_2104.py b/admin-api/web/migrations/0003_auto_20240531_2104.py new file mode 100644 index 0000000..5f7b09b --- /dev/null +++ b/admin-api/web/migrations/0003_auto_20240531_2104.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.25 on 2024-05-31 13:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0002_auto_20240531_1456'), + ] + + operations = [ + migrations.AlterModelOptions( + name='systeminit', + options={'verbose_name': '部门管理'}, + ), + migrations.AlterModelTable( + name='systeminit', + table='system_init', + ), + ] diff --git a/admin-api/web/migrations/0004_auto_20240614_1628.py b/admin-api/web/migrations/0004_auto_20240614_1628.py new file mode 100644 index 0000000..27cdf7b --- /dev/null +++ b/admin-api/web/migrations/0004_auto_20240614_1628.py @@ -0,0 +1,58 @@ +# Generated by Django 3.2.25 on 2024-06-14 08:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('web', '0003_auto_20240531_2104'), + ] + + operations = [ + migrations.AlterField( + model_name='systemmenu', + name='isCache', + field=models.CharField(default='0', help_text='是否缓存(0缓存 1不缓存)', max_length=4, verbose_name='是否缓存(0缓存 1不缓存)'), + ), + migrations.AlterField( + model_name='systemmenu', + name='isFrame', + field=models.CharField(default='1', help_text='是否为外链(0是 1否)', max_length=4, verbose_name='是否为外链(0是 1否)'), + ), + migrations.AlterField( + model_name='systemmenu', + name='status', + field=models.CharField(default='0', help_text='菜单状态(0正常 1停用)', max_length=4, verbose_name='菜单状态(0正常 1停用)'), + ), + migrations.AlterField( + model_name='systemmenu', + name='visible', + field=models.CharField(default='0', help_text='菜单状态(0显示 1隐藏)', max_length=4, verbose_name='菜单状态(0显示 1隐藏)'), + ), + migrations.AlterField( + model_name='systemuser', + name='userType', + field=models.CharField(default='00', help_text='用户类型(00系统用户)', max_length=4, verbose_name='用户类型(00系统用户)'), + ), + migrations.AddIndex( + model_name='systemdept', + index=models.Index(fields=['deptId'], name='SystemDept_deptId'), + ), + migrations.AddIndex( + model_name='systemmenu', + index=models.Index(fields=['menuId'], name='SystemMenu_menuId'), + ), + migrations.AddIndex( + model_name='systemrole', + index=models.Index(fields=['roleId'], name='SystemRole_roleId'), + ), + migrations.AddIndex( + model_name='systemrolemenu', + index=models.Index(fields=['roleId'], name='SystemRoleMenu_roleId'), + ), + migrations.AddIndex( + model_name='systemuser', + index=models.Index(fields=['userId'], name='SystemUser_userId'), + ), + ] diff --git a/admin-api/web/migrations/__init__.py b/admin-api/web/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/admin-api/web/models.py b/admin-api/web/models.py new file mode 100644 index 0000000..e6de983 --- /dev/null +++ b/admin-api/web/models.py @@ -0,0 +1,108 @@ +from django.db import models + +from database.core import CoreModel + + +class SystemInit(CoreModel): + Init = models.BooleanField(default=False, blank=True, help_text="是否已经初始化数据库") + + class Meta: + db_table = 'system_init' + verbose_name = '部门管理' + + +class SystemDept(CoreModel): + parentId = models.CharField(max_length=64, default="", verbose_name="父id", help_text="父id") + deptName = models.CharField(max_length=64, default="", verbose_name="部门名称", help_text="部门名称") + deptId = models.CharField(unique=True, max_length=64, default="", verbose_name="部门id", help_text="部门id") + orderNum = models.IntegerField(default=0, verbose_name="排序", help_text="排序") + leader = models.CharField(max_length=32, default="", verbose_name="负责人", help_text="负责人") + phone = models.CharField(max_length=32, default="", verbose_name="联系电话", help_text="联系电话") + email = models.CharField(max_length=32, default="", verbose_name="邮箱", help_text="邮箱") + status = models.CharField(max_length=4, default="0", verbose_name="启用状态", help_text="启用状态 (0正常 1停用)") + delFlag = models.CharField(max_length=4, default="0", verbose_name="是否删除", help_text="是否删除 (0存在 2删除)") + ancestors = models.CharField(max_length=64, default="", verbose_name="上级目录id", help_text="上级目录id") + + class Meta: + indexes = [models.Index(fields=['deptId'], name='SystemDept_deptId')] + db_table = 'system_dept' + verbose_name = '部门管理' + + +class SystemMenu(CoreModel): + menuId = models.CharField(unique=True, max_length=64, default="", verbose_name="菜单ID", help_text="菜单ID") + menuName = models.CharField(max_length=64, default="", verbose_name="菜单名称", help_text="菜单名称") + parentId = models.CharField(max_length=64, default="", verbose_name="父菜单ID", help_text="父菜单ID") + orderNum = models.IntegerField(default=0, verbose_name="显示顺序", help_text="显示顺序") + path = models.CharField(max_length=64, default="", verbose_name="路由地址", help_text="路由地址") + component = models.CharField(max_length=64, default="", verbose_name="组件路径", help_text="组件路径") + query = models.CharField(max_length=64, default="", verbose_name="路由参数", help_text="路由参数") + isFrame = models.CharField(max_length=4, default="1", verbose_name="是否为外链(0是 1否)", help_text="是否为外链(0是 1否)") + isCache = models.CharField(max_length=4, default="0", verbose_name="是否缓存(0缓存 1不缓存)", help_text="是否缓存(0缓存 1不缓存)") + visible = models.CharField(max_length=4, default="0", verbose_name="菜单状态(0显示 1隐藏)", help_text="菜单状态(0显示 1隐藏)") + menuType = models.CharField(max_length=4, default="", verbose_name="菜单类型(M目录 C菜单 F按钮)", help_text="菜单类型(M目录 C菜单 F按钮)") + status = models.CharField(max_length=4, default="0", verbose_name="菜单状态(0正常 1停用)", help_text="菜单状态(0正常 1停用)") + perms = models.CharField(max_length=32, default="", verbose_name="权限标识", help_text="权限标识") + icon = models.CharField(max_length=32, default="", verbose_name="菜单图", help_text="菜单图") + + class Meta: + db_table = 'system_menu' + verbose_name = '目录管理' + indexes = [models.Index(fields=['menuId'], name='SystemMenu_menuId')] + + +class SystemRole(CoreModel): + roleId = models.CharField(unique=True, max_length=64, default="", verbose_name="角色id", help_text="角色id") + roleName = models.CharField(max_length=64, default="", verbose_name="角色名称", help_text="角色名称") + roleKey = models.CharField(max_length=64, default="", verbose_name="角色权限字符", help_text="角色权限字符") + roleSort = models.IntegerField(default=0, verbose_name="角色排序", help_text="角色排序") + roleAdmin = models.BooleanField(max_length=64, default=False, verbose_name="是否是超级管理员", help_text="是否是超级管理员") + status = models.CharField(max_length=4, default="0", verbose_name="启用状态 (0正常 1停用)", help_text="启用状态 (0正常 1停用)") + menuCheckStrictly = models.BooleanField(default=True, verbose_name="菜单树选择项是否关联显示", help_text="菜单树选择项是否关联显示") + deptCheckStrictly = models.BooleanField(default=True, verbose_name="部门树选择项是否关联显示", help_text="部门树选择项是否关联显示") + delFlag = models.CharField(max_length=4, default="0", verbose_name="是否删除 (0代表存在 2代表删除)", help_text="是否删除 (0代表存在 2代表删除)") + + class Meta: + db_table = 'system_role' + verbose_name = '角色管理' + indexes = [models.Index(fields=['roleId'], name='SystemRole_roleId')] + + +class SystemUser(CoreModel): + userId = models.CharField(unique=True, max_length=64, default="", verbose_name="用户id", help_text="用户id") + deptId = models.CharField(max_length=64, default="", verbose_name="部门id", help_text="部门id") + username = models.CharField(max_length=64, default="", verbose_name="用户账号", help_text="用户账号") + nickName = models.CharField(max_length=64, default="", verbose_name="用户昵称", help_text="用户昵称") + userType = models.CharField(max_length=4, default="00", verbose_name="用户类型(00系统用户)", help_text="用户类型(00系统用户)") + email = models.CharField(max_length=64, default="", verbose_name="邮箱", help_text="邮箱") + phone = models.CharField(max_length=64, default="", verbose_name="手机号码", help_text="手机号码") + avatar = models.CharField(max_length=64, default="", verbose_name="头像", help_text="头像") + password = models.CharField(max_length=64, default="", verbose_name="密码(加密后)", help_text="密码(加密后)") + status = models.CharField(max_length=4, default="0", verbose_name="帐号状态(0正常 1停用)", help_text="帐号状态(0正常 1停用)") + delFlag = models.CharField(max_length=4, default="0", verbose_name="删除标志(0代表存在 2代表删除)", help_text="删除标志(0代表存在 2代表删除)") + loginIp = models.CharField(max_length=64, default="", verbose_name="最后登陆ip", help_text="最后登陆ip") + loginDate = models.CharField(max_length=64, default="", verbose_name="最后登陆日期", help_text="最后登陆日期") + + class Meta: + db_table = 'system_user' + verbose_name = '用户管理' + indexes = [models.Index(fields=['userId'], name='SystemUser_userId')] + + +class SystemRoleMenu(CoreModel): + menuId = models.CharField(max_length=64, default="", verbose_name="菜单id", help_text="菜单id") + roleId = models.CharField(max_length=64, default="", verbose_name="角色id", help_text="角色id") + + class Meta: + db_table = 'system_role_menu' + verbose_name = '角色与目录关系映射' + indexes = [models.Index(fields=['roleId'], name='SystemRoleMenu_roleId')] + + +class SystemUserRole(CoreModel): + userId = models.CharField(max_length=64, default="", verbose_name="菜单id", help_text="用户id") + roleId = models.CharField(max_length=64, default="", verbose_name="角色id", help_text="角色id") + + class Meta: + db_table = 'system_role_user' + verbose_name = '角色与人员关系映射' diff --git a/admin-api/web/paginator.py b/admin-api/web/paginator.py new file mode 100644 index 0000000..e2f6c3a --- /dev/null +++ b/admin-api/web/paginator.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/6/13 14:27 +@Email : 652044581@qq.com +@Desc : 分页器 +""" +from rest_framework.exceptions import NotFound +from rest_framework.pagination import PageNumberPagination + + +class StandardResultsSetPagination(PageNumberPagination): + # 默认每页显示的数据条数 + page_size = 10 + + # 获取URL参数中设置的每页显示数据条数 + page_size_query_param = 'pageSize' + + # 获取URL参数中传入的页码key + page_query_param = 'pageNum' + + # 最大支持的每页显示的数据条数 + max_page_size = 50 + + def paginate_queryset_data(self, queryset, request, view=None, serializer=None): + try: + queryset = super().paginate_queryset(queryset, request=request, view=view) + ser = serializer(queryset, many=True) + return ser.data + except NotFound as e: + return [] + + def paginate_queryset_count(self, queryset, request, view=None, serializer=None): + try: + res = {} + queryset = super().paginate_queryset(queryset, request=request, view=view) + ser = serializer(queryset, many=True) + res["data"] = ser.data + res["count"] = self.page.paginator.count + return res + except NotFound as e: + return {} diff --git a/admin-api/web/serializer.py b/admin-api/web/serializer.py new file mode 100644 index 0000000..41c058b --- /dev/null +++ b/admin-api/web/serializer.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +""" +@Author :mengying +@Date :2024/6/3 17:19 +@Email : 652044581@qq.com +@Desc : 功能描述 +""" +from rest_framework import serializers + +from web.models import SystemUser, SystemUserRole, SystemMenu, SystemRole, SystemDept + + +class SystemUserSerializer(serializers.ModelSerializer): + update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + + class Meta: + model = SystemUser + fields = '__all__' + + +class SystemDeptSerializer(serializers.ModelSerializer): + update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + + class Meta: + model = SystemDept + fields = '__all__' + + +class SystemRoleSerializer(serializers.ModelSerializer): + update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + + class Meta: + model = SystemRole + fields = '__all__' + + +class SystemMenuSerializer(serializers.ModelSerializer): + update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + + class Meta: + model = SystemMenu + fields = '__all__' + + +class SystemUserRoleSerializer(serializers.ModelSerializer): + update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', read_only=True) + + class Meta: + model = SystemUserRole + fields = '__all__' diff --git a/admin-api/web/static/fontBold.ttf b/admin-api/web/static/fontBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..02bb4a6843e9de3475094ad90915091eb0c7ebb7 GIT binary patch literal 705684 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

JE6cYFxc8V-|I4H+?|!8sU*ST^q-@ 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�LFDqVKgtCJCXI6b{Xqg+U)Xg!fjL02(<3Y`=3 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

_}%z)2hqf#Y{Bh4M-*hPA^b-aDqV42 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
  1. @NwB2q26WbRhy_ZzlF;VsA-B20UP2+`_)Ng?({L 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 literal 0 HcmV?d00001 diff --git a/admin-api/web/system/urls.py b/admin-api/web/system/urls.py new file mode 100644 index 0000000..9e6e5a1 --- /dev/null +++ b/admin-api/web/system/urls.py @@ -0,0 +1,48 @@ +from django.urls import path, re_path + +from web.system import views as systemView + +urlpatterns = [ + + # 部门相关 + path('dept/list', systemView.DeptListView.as_view(), name="部门列表"), + path('dept', systemView.DeptCreateView.as_view(), name="部门新增/修改"), + re_path('dept/(?P[0-9]+$)', systemView.DeptDetailView.as_view(), name="部门详情/删除"), + re_path('dept/list/exclude/(?P[0-9]+$)', systemView.DeptExcludeView.as_view(), name="部门排除查询"), + + # 角色相关 + path('role/list', systemView.RoleListView.as_view(), name="角色列表"), + path('role', systemView.RoleCreateView.as_view(), name="角色新增"), + path('role/changeStatus', systemView.RoleStatusView.as_view(), name="角色状态修改"), + re_path('role/(?P[0-9]+$)', systemView.RoleDetailView.as_view(), name="角色新增"), + + # 角色认证 + path('role/authUser/allocatedList', systemView.AuthUserAllocatedListView.as_view(), name="分配用户列表"), + path('role/authUser/cancel', systemView.AuthUserCancelView.as_view(), name="角色取消人员授权"), + path('role/authUser/cancelAll', systemView.AuthUserCancelAllView.as_view(), name="批量取消授权"), + path('role/authUser/unallocatedList', systemView.AuthUserUnallocatedListView.as_view(), name="未授权用户列表"), + path('role/authUser/selectAll', systemView.AuthUserSelectAllView.as_view(), name="批量绑定角色人员"), + + # 用户相关 + re_path('user/authRole/(?P[0-9]+$)', systemView.AuthRoleView.as_view(), name="用户角色绑定"), + path('user/authRole', systemView.AuthRoleView.as_view(), name="用户角色绑定修改"), + path('user/list', systemView.UserListView.as_view(), name="用户列表"), + path('user/deptTree', systemView.UserDeptTreeView.as_view(), name="用户列表"), + path('user/changeStatus', systemView.UserStatusView.as_view(), name="用户状态修改"), + path('user/', systemView.UserCreateView.as_view(), name="用户新增"), + re_path('user/(?P[0-9 ,]+$)', systemView.UserDetailView.as_view(), name="用户详情/删除"), + path('user/resetPwd', systemView.UserResetPwdView.as_view(), name="重置密码"), + + # 个人中心 + path('user/profile/updatePwd', systemView.UserUpdatePwdView.as_view(), name="修改密码"), + path('user/profile', systemView.UserProfileView.as_view(), name="个人中心"), + path('user/profile/avatar', systemView.UserProfileAvatarView.as_view(), name="修改头像"), + + # 目录相关 + path('menu/list', systemView.MenuListView.as_view(), name="目录列表"), + re_path('menu/(?P[0-9]+$)', systemView.MenuDetailView.as_view(), name="目录详情/删除"), + path('menu', systemView.MenuCreateView.as_view(), name="目录新增"), + path('menu/treeselect', systemView.MenuTreeSelectView.as_view(), name="树选择器"), + re_path('menu/roleMenuTreeselect/(?P[0-9]+$)', systemView.MenuRoleTreeSelectView.as_view(), name="已选择的树选择器"), + +] diff --git a/admin-api/web/system/views.py b/admin-api/web/system/views.py new file mode 100644 index 0000000..7440ec7 --- /dev/null +++ b/admin-api/web/system/views.py @@ -0,0 +1,776 @@ +import json +from functools import wraps + +from addict import Dict +from django.db.models import Q +from django.http.response import JsonResponse +from django_redis import get_redis_connection +from rest_framework.request import Request +from rest_framework.views import APIView + +from config import config +from utils.myDataUtils import TreeBuilder +from utils.myEncrypt import HashCipher +from utils.myEnum import SystemDelEnum, SystemStatusEnum, SystemUserTypeEnum +from utils.myResFormat import ResultJson, ResultCode +from utils.mySnowflake import Sf +from web.models import SystemDept, SystemUser, SystemRole, SystemUserRole, SystemMenu, SystemRoleMenu +from web.paginator import StandardResultsSetPagination +from web.serializer import SystemDeptSerializer, SystemUserSerializer, SystemRoleSerializer, SystemMenuSerializer + +RedisClient = get_redis_connection() + + +# 检验权限字符串的装饰器 +def permAuth(perKey): + def decorator(function): + @wraps(function) + def decorated_function(self, *args, **kwargs): + # 获取token中的用户权限 + user_info = {} + for item in args: + if isinstance(item, Request): + user_info = item.headers.user_info + user_permissions = user_info.get("permissions", []) + + # 判断是否有权限 + if "*:*:*" in user_permissions or perKey in user_permissions: + response = function(self, *args, **kwargs) + return response + else: + return JsonResponse(ResultJson(ret=ResultCode.PRE_AUTH_ERROR).result) + + return decorated_function + + return decorator + + +def response2json(response) -> dict: + return json.loads(response.content.decode()) + + +class DeptListView(APIView): + """【系统部门】列表接口""" + + @permAuth("system:dept:list") + def get(self, request, *args, **kwargs): + deptName: str = request.GET.get('deptName') + status: str = request.GET.get('status') + + q = Q() + q.connector = 'AND' + + if deptName: + q.children.append(('deptName', deptName)) + + if status: + q.children.append(('status', status)) + + q.children.append(('delFlag', SystemDelEnum.p0.value)) + + dept = SystemDept.objects.filter(q) + deptData = SystemDeptSerializer(instance=dept, many=True).data + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=deptData).result) + + +class DeptCreateView(APIView): + """【系统部门】新增部门""" + + @permAuth("system:dept:add") + def post(self, request, *args, **kwargs): + + data: dict = request.data + + parentId = request.data.get('parentId') + + dept_obj = SystemDept.objects.filter(deptId=parentId) + if not dept_obj: + raise Exception("未找到系统部门父级id") + + dept_obj = dept_obj.first() + data["ancestors"] = dept_obj.ancestors + "," + dept_obj.deptId + data["deptId"] = Sf.generate() + + # 判断同一父级部门下不重名 + deptNameExist = SystemDept.objects.filter(deptName=data.get("deptName"), parentId=data.get("parentId")) + if deptNameExist: + return JsonResponse(ResultJson(ret=ResultCode.DEPT_ERROR).result) + + SystemDept.objects.create(**data) + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=data).result) + + + @permAuth("system:dept:edit") + def put(self, request, *args, **kwargs): + data: dict = request.data + deptId = data.get('deptId') + + deptData = SystemDept.objects.get(deptId=deptId) + + # 判断原始目录的父级id是否变化 + if deptData.parentId == data.get('parentId'): + SystemDept.objects.filter(deptId=deptId).update(**data) + else: + # 处理本条数据的上级关联关系 + parentId = data.get('parentId') + parentData = SystemDept.objects.get(deptId=parentId) + repAncestors = parentData.ancestors + "," + parentId + data['ancestors'] = repAncestors + SystemDept.objects.filter(deptId=deptId).update(**data) + + # 处理下级关联的路径问题 + oldAncestors = deptData.ancestors + "," + deptData.deptId + SystemDeptDataList = SystemDept.objects.filter(ancestors__contains=oldAncestors, delFlag=SystemDelEnum.p0.value) + for item in SystemDeptDataList: + new_ancestors = item.ancestors + new_ancestors = str(new_ancestors).replace(oldAncestors, repAncestors + "," + deptData.deptId) + item.ancestors = new_ancestors + item.save() + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class DeptDetailView(APIView): + """【系统部门】新增部门""" + + @permAuth("system:dept:query") + def get(self, request, deptId, *args, **kwargs): + """【系统部门】部门详情""" + data = SystemDept.objects.get(deptId=deptId, delFlag=SystemDelEnum.p0.value) + ser = SystemDeptSerializer(instance=data) + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=ser.data).result) + + @permAuth("system:dept:remove") + def delete(self, request, deptId, *args, **kwargs): + # 更新部门状态 + SystemDept.objects.filter(deptId=deptId).update(delFlag=SystemDelEnum.p1.value) + + # 更新人员绑定部门 + SystemUser.objects.filter(deptId=deptId).update(deptId="") + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class DeptExcludeView(APIView): + """【系统部门】排除查询""" + + @permAuth("system:dept:query") + def get(self, request, deptId, *args, **kwargs): + # 查询部门id不是指定id或者ancestors不包含该id,且状态未删除的数据 + userData = SystemDept.objects.filter(delFlag=SystemDelEnum.p0.value, status=SystemStatusEnum.p0.value).exclude(deptId=deptId, + ancestors__contains=deptId) + ser = SystemDeptSerializer(instance=userData, many=True) + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=ser.data).result) + + +class RoleListView(APIView): + """【系统角色】列表接口""" + + def get(self, request, *args, **kwargs): + roleName: str = request.GET.get('roleName') + roleKey: str = request.GET.get('roleKey') + status: str = request.GET.get('status') + + q = Q() + q.connector = 'AND' + + if roleName: + q.children.append(('roleName', roleName)) + + if roleKey: + q.children.append(('roleKey', roleKey)) + + if status: + q.children.append(('status', status)) + + q.children.append(('roleAdmin', False)) + q.children.append(('delFlag', SystemDelEnum.p0.value)) + + roleData = SystemRole.objects.filter(q).order_by('roleSort') + + paginator = StandardResultsSetPagination() + role_list = paginator.paginate_queryset_count(roleData, self.request, view=self, serializer=SystemRoleSerializer) + + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=role_list).result) + + +class RoleCreateView(APIView): + """【系统角色】新增接口""" + + def post(self, request, *args, **kwargs): + data: dict = request.data + roleKey = data.get("roleKey") + roleName = data.get("roleName") + menuIds = data.pop("menuIds", []) + roleId = Sf.generate() + data["roleId"] = roleId + + roleData = SystemRole.objects.filter(Q(roleKey=roleKey, delFlag=SystemDelEnum.p0.value) | Q(roleName=roleName, delFlag=SystemDelEnum.p0.value)) + + if roleData: + return JsonResponse(ResultJson(ret=ResultCode.ROLE_ERROR).result) + + # 删除原始的关系 + SystemRoleMenu.objects.filter(roleId=roleId).delete() + for menuId in menuIds: + SystemRoleMenu.objects.create(menuId=menuId, roleId=roleId) + + # 创建角色数据 + SystemRole.objects.create(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + def put(self, request, *args, **kwargs): + data: dict = request.data + roleId = data.get("roleId") + menuIds = data.pop("menuIds", []) + roleAdmin = data.pop("roleAdmin", False) + + # 删除原始的关系 + SystemRoleMenu.objects.filter(roleId=roleId).delete() + for menuId in menuIds: + SystemRoleMenu.objects.create(menuId=menuId, roleId=roleId) + + # 更新角色数据 + SystemRole.objects.filter(roleId=roleId).update(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class RoleStatusView(APIView): + """【系统角色】修改状态""" + + def put(self, request): + data: dict = request.data + roleId = data.get("roleId") + SystemRole.objects.filter(roleId=roleId).update(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class RoleDetailView(APIView): + @permAuth("system:role:query") + def get(self, request, roleId: str): + """【系统角色】获取角色信息""" + + roleData = SystemRole.objects.get(roleId=roleId) + roleData = SystemRoleSerializer(instance=roleData).data + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=roleData).result) + + @permAuth("system:role:remove") + def delete(self, request, roleId: str): + """【系统角色】获取删除角色信息""" + + roleIds = roleId.split(',') + SystemRole.objects.filter(roleId__in=roleIds).update(delFlag=SystemDelEnum.p1.value) + + SystemUserRole.objects.filter(roleId__in=roleIds).delete() + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class AuthUserCancelView(APIView): + def put(self, request): + """【系统角色】取消角色人员授权""" + # 处理角色用户关系 + roleId: str = request.data.get('roleId') + userId: str = request.data.get('userId') + + # 判断是批量删除还是单个删除 + SystemUserRole.objects.filter(roleId=roleId, userId=userId).delete() + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class AuthUserAllocatedListView(APIView): + + def get(self, request): + """【系统角色】给角色分配人员""" + roleId: str = request.GET.get('roleId') + username: str = request.GET.get('username') + phone: str = request.GET.get('phone') + + UserRoleIds = SystemUserRole.objects.filter(roleId=roleId) + + q = Q() + q.connector = 'AND' + + if username: + q.children.append(('username', username)) + + if phone: + q.children.append(('phone', phone)) + + q.children.append(('userId__in', [item.userId for item in UserRoleIds])) + q.children.append(('delFlag', SystemDelEnum.p0.value)) + q.children.append(('userType', SystemUserTypeEnum.p0.value)) + + userData = SystemUser.objects.filter(q) + + paginator = StandardResultsSetPagination() + + # 组装人员的部门信息 + userData = paginator.paginate_queryset_count(userData, self.request, view=self, serializer=SystemUserSerializer) + for item in userData.get("data", []): + deptId = item.get('deptId') + if not deptId: + item["dept"] = {} + else: + deptData = SystemDept.objects.get(deptId=deptId) + item["dept"] = SystemDeptSerializer(instance=deptData).data + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=userData).result) + + +class AuthUserUnallocatedListView(APIView): + + def get(self, request): + """【系统角色】获取未授权用户列表""" + roleId: str = request.GET.get('roleId') + username: str = request.GET.get('username') + phone: str = request.GET.get('phone') + + UserRoleIds = SystemUserRole.objects.filter(roleId=roleId) + + q = Q() + q.connector = 'AND' + + if username: + q.children.append(('username', username)) + + if phone: + q.children.append(('phone', phone)) + + q.children.append(('delFlag', SystemDelEnum.p0.value)) + q.children.append(('userType', SystemUserTypeEnum.p0.value)) + + userData = SystemUser.objects.filter(q).exclude(userId__in=[item.userId for item in UserRoleIds]) + + paginator = StandardResultsSetPagination() + + # 组装人员的部门信息 + userData = paginator.paginate_queryset_count(userData, self.request, view=self, serializer=SystemUserSerializer) + for item in userData.get("data", []): + deptId = item.get('deptId') + if not deptId: + item["dept"] = {} + else: + deptData = SystemDept.objects.get(deptId=deptId) + item["dept"] = SystemDeptSerializer(instance=deptData).data + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=userData).result) + + +class AuthUserSelectAllView(APIView): + def put(self, request): + """【系统角色】批量绑定角色人员""" + roleId: str = request.data.get('roleId') + userIds: str = request.data.get('userIds') + userIdList = userIds.split(',') + + # 批量插入用户关系 + for userId in userIdList: + SystemUserRole.objects.create(**dict(userId=userId, roleId=roleId)) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class AuthUserCancelAllView(APIView): + def put(self, request): + """【系统角色】批量取消角色人员授权""" + # 处理角色用户关系 + roleId: str = request.data.get('roleId') + userIds: str = request.data.get('userIds') + userIdList = userIds.split(',') + + # 判断是批量删除还是单个删除 + SystemUserRole.objects.filter(roleId=roleId, userId__in=userIdList).delete() + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class UserListView(APIView): + """【系统用户】列表接口""" + + @permAuth("system:user:list") + def get(self, request): + + deptId: str = request.GET.get('deptId') + username: str = request.GET.get('username') + phone: str = request.GET.get('phone') + status: str = request.GET.get('status') + + q = Q() + q.connector = 'AND' + + if deptId: + deptData = SystemDept.objects.filter(ancestors__contains=deptId) + deptIds = [item.deptId for item in deptData] + deptIds.append(deptId) + q.children.append(('deptId__in', deptIds)) + + if username: + q.children.append(('username', username)) + + if phone: + q.children.append(('phone', phone)) + + if status: + q.children.append(('status', status)) + + q.children.append(('delFlag', SystemDelEnum.p0.value)) + q.children.append(('userType', SystemUserTypeEnum.p0.value)) + + userData = SystemUser.objects.filter(q) + + # 分页 + paginator = StandardResultsSetPagination() + userData = paginator.paginate_queryset_count(userData, self.request, view=self, serializer=SystemUserSerializer) + + # 组装人员的部门信息 + for item in userData.get("data", []): + deptId = item.get('deptId') + if not deptId: + item["dept"] = {} + else: + deptData = SystemDept.objects.get(deptId=deptId) + item["dept"] = SystemDeptSerializer(instance=deptData).data + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=userData).result) + + +class UserDeptTreeView(APIView): + """【系统用户】部门的结构树""" + + @classmethod + def deptFormat(cls, SystemDeptList): + container = [] + for item in SystemDeptList: + deptItem = {"id": item.get("deptId"), "parentId": item.get("parentId"), "label": item.get("deptName"), } + container.append(deptItem) + return container + + def get(self, request): + # 查询全部数据 + deptData = SystemDept.objects.filter(delFlag=SystemDelEnum.p0.value, status=SystemStatusEnum.p0.value) + + # 组装前端所需要的数据结构 + SystemDeptList = SystemDeptSerializer(instance=deptData, many=True) + DeptList = self.deptFormat(SystemDeptList.data) + + # 组装成树的结构 + TreeData = TreeBuilder(DeptList).build(parentKey="parentId", ownerKey="id", topParent="0") + TreeDataList = list(TreeData.values()) + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=TreeDataList).result) + + +class UserStatusView(APIView): + """【系统用户】修改用户状态""" + + @permAuth("*:*:*") + def put(self, request): + data: dict = request.data + userId = data.get("userId") + SystemUser.objects.filter(userId=userId).update(**data) + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class UserCreateView(APIView): + """【系统用户】新增接口""" + + @permAuth("*:*:*") + def post(self, request): + data: dict = request.data + username = data.get("username") + password = data.get('password', "") + + userId = Sf.generate() + + # 判断用户名是否重复 + userExist = SystemUser.objects.filter(username=username, delFlag=SystemDelEnum.p0.value) + if userExist: + return JsonResponse(ResultJson(ret=ResultCode.USER_ERROR).result) + + # 处理角色用户关系 + roleIds = data.pop("roleIds", []) + for roleId in roleIds: + SystemUserRole.objects.create(**dict(roleId=roleId, userId=userId)) + + # 用户表插入数据 + user_info = request.headers.user_info + username = user_info.get('user', {}).get('username') + data["userId"] = userId + data["createBy"] = username + data["password"] = HashCipher.md5(config.ENCRYPT_STRING + password) + SystemUser.objects.create(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + @permAuth("*:*:*") + def put(self, request): + """【系统用户】修改信息""" + # 处理角色用户关系 + data: dict = request.data + + userId = data.get('userId') + roleIds = data.pop("roleIds", []) + + # 删除以前的角色人员关系,在增加新的关系 + SystemUserRole.objects.filter(userId=userId).delete() + for roleId in roleIds: + SystemUserRole.objects.create(**dict(roleId=roleId, userId=userId)) + + SystemUser.objects.filter(userId=userId).update(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + @permAuth("*:*:*") + def get(self, request): + """【系统用户】获取现有的角色列表""" + res = Dict() + roleData = SystemRole.objects.filter(status=SystemStatusEnum.p0.value, delFlag=SystemDelEnum.p0.value, roleAdmin=False) + res.roles = SystemRoleSerializer(instance=roleData, many=True).data + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=res).result) + + +class UserDetailView(APIView): + @permAuth("system:user:query") + def get(self, request, userId: str): + """【系统用户】获取用户信息""" + res = Dict() + + # 找到用户绑定的角色id + userData = SystemUser.objects.get(userId=userId) + + userRoleData = SystemUserRole.objects.filter(userId=userId) + roleIds = [item.roleId for item in userRoleData] + roleData = SystemRole.objects.filter(status=SystemStatusEnum.p0.value, roleAdmin=False, delFlag=SystemDelEnum.p0.value) + + # 组装数据 + res.user = SystemUserSerializer(instance=userData).data + res.roleIds = roleIds + res.roles = SystemRoleSerializer(instance=roleData, many=True).data + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=res).result) + + @permAuth("system:user:remove") + def delete(self, request, userId: str): + """【系统用户】获取删除用户信息""" + + # 分割路径的userId,变为list + userIds = userId.split(',') + SystemUser.objects.filter(userId__in=userIds).update(delFlag=SystemDelEnum.p1.value) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class UserProfileView(APIView): + + def get(self, request): + """【个人中心】获取信息""" + user_info = request.headers.user_info + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=user_info).result) + + def put(self, request): + """【个人中心】修改""" + data: dict = request.data + user_info = request.headers.user_info + userId = user_info.get('user', {}).get('userId') + SystemUser.objects.filter(userId=userId).update(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class UserProfileAvatarView(APIView): + + def post(self, request): + """【个人中心】修改头像""" + avatar = request.Files.get("avatarfile") + user_info = request.headers.user_info + userId = user_info.get('user', {}).get('userId') + + # TODO: 上传头像文件流,生成一个url,更新用户信息的头像字段(没有obs, 功能未作) + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=user_info).result) + + +class UserResetPwdView(APIView): + @permAuth("*:*:*") + def put(self, request): + """【系统用户】重置密码/ 需要管理员权限""" + data: dict = request.data + password = data.get('password') + userId = data.get('userId') + + # 修改密码 + password_md5 = HashCipher.md5(config.ENCRYPT_STRING + password) + + SystemUser.objects.filter(userId=userId).update(password=password_md5) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class UserUpdatePwdView(APIView): + def put(self, request): + """【系统用户】更新密码""" + oldPassword = request.GET.get('oldPassword') + newPassword = request.GET.get('newPassword') + + # 判断旧密码是否正确 + user_info = request.headers.user_info + userId = user_info.get('user', {}).get('userId', "") + + # 对密码进行加密 + old_encrypt_password = HashCipher.md5(config.ENCRYPT_STRING + str(oldPassword)) + new_encrypt_password = HashCipher.md5(config.ENCRYPT_STRING + str(newPassword)) + + userData = SystemUser.objects.filter(password=old_encrypt_password, userId=userId) + + if not userData: + return JsonResponse(ResultJson(ret=ResultCode.PASSWORD_ERROR).result) + else: + SystemUser.objects.filter(userId=userId).update(password=new_encrypt_password) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class AuthRoleView(APIView): + + def get(self, request, userId: str): + """【系统用户】查询角色映射关系""" + # 查询用户信息 + userData = SystemUser.objects.get(userId=userId) + + # 查询用户角色映射关系 + userRoleList = SystemUserRole.objects.filter(userId=userId) + + # 查询角色信息 + roleIds = [item.roleId for item in userRoleList] + roleData = SystemRole.objects.filter(roleId__in=roleIds) + + # 序列化 + userData = SystemUserSerializer(instance=userData).data + roleData = SystemRoleSerializer(instance=roleData, many=True).data + + # 组装返回数据 + resData = dict(user=userData, roles=roleData) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=resData).result) + + def put(self, request): + """【系统用户】修改角色映射关系""" + userId = request.GET.get("userId") + roleIds = request.GET.get("roleIds") + roleIds = roleIds.split(",") + + # 删除以前的角色人员关系,在增加新的关系 + SystemUserRole.objects.filter(userId=userId).delete() + for roleId in roleIds: + SystemUserRole.objects.create(**dict(roleId=roleId, userId=userId)) + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=None).result) + + +class MenuDetailView(APIView): + @permAuth("system:menu:query") + def get(self, request, menuId: str): + """【系统用户】查询""" + menuData = SystemMenu.objects.get(menuId=menuId) + menuData = SystemMenuSerializer(instance=menuData).data + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=menuData).result) + + @permAuth("system:menu:remove") + def delete(self, request, menuId: str): + """【系统用户】删除""" + + # 删除目录信息 + SystemMenu.objects.filter(menuId=menuId).delete() + + # 删除角色目录映射 + SystemRoleMenu.objects.filter(menuId=menuId).delete() + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class MenuListView(APIView): + + @permAuth("system:menu:list") + def get(self, request): + """【系统目录】列表""" + menuName: str = request.GET.get('menuName') + status: str = request.GET.get('status') + + q = Q() + q.connector = 'AND' + + if menuName: + q.children.append(('menuName', menuName)) + + if status: + q.children.append(('status', status)) + + q.children.append(('visible', SystemDelEnum.p0.value)) + + # 查询数据列表 + menuData = SystemMenu.objects.filter(q).order_by('orderNum') + menuData = SystemMenuSerializer(instance=menuData, many=True).data + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=menuData).result) + + +class MenuCreateView(APIView): + + @permAuth("system:menu:add") + def post(self, request): + """【系统目录】新增""" + data: dict = request.data + parentId = data.get("parentId") + menuName = data.get("menuName") + # 生成父级数据 + data["menuId"] = Sf.generate() + + menuExist = SystemMenu.objects.filter(parentId=parentId, menuName=menuName) + + if menuExist: + return JsonResponse(ResultJson(ret=ResultCode.MENU_ERROR).result) + + SystemMenu.objects.create(**data) + + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=data).result) + + @permAuth("system:menu:edit") + def put(self, request): + """【系统目录】修改""" + data: dict = request.data + menuId = data.get('menuId') + SystemMenu.objects.filter(menuId=menuId).update(**data) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS).result) + + +class MenuTreeSelectView(APIView): + """【系统目录】树选择""" + + @classmethod + def MenuFormat(cls, MenuData): + container = [] + for item in MenuData: + deptItem = {"id": item.get("menuId"), "parentId": item.get("parentId"), "label": item.get("menuName"), } + container.append(deptItem) + return container + + def get(self, request): + menuData = SystemMenu.objects.filter(status=SystemStatusEnum.p0.value) + menuData = SystemMenuSerializer(instance=menuData, many=True).data + + # 组装前端所需要的数据结构 + MenuList = self.MenuFormat(menuData) + + # 组装成树的结构 + TreeData = TreeBuilder(MenuList).build(parentKey="parentId", ownerKey="id", topParent="0") + TreeDataList = list(TreeData.values()) + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=TreeDataList).result) + + +class MenuRoleTreeSelectView(APIView): + """【系统目录】已经选择树选择器""" + + def get(self, request, roleId: str): + res = Dict() + + # 查询树的列表 + TreeDataListResponse = MenuTreeSelectView().get(request) + TreeDataList = response2json(TreeDataListResponse).get("data", []) + + # 查询选中数据的 + res.menus = TreeDataList + roleMenuData = SystemRoleMenu.objects.filter(roleId=roleId) + + res.checkedKeys = [item.menuId for item in roleMenuData] + return JsonResponse(ResultJson(ret=ResultCode.SUCCESS, data=res.to_dict()).result) diff --git a/admin-api/web/tests.py b/admin-api/web/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/admin-api/web/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/admin-api/web/urls.py b/admin-api/web/urls.py new file mode 100644 index 0000000..46883d8 --- /dev/null +++ b/admin-api/web/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from web import views as webView + +urlpatterns = [ + path('captchaImage', webView.CaptchaImageView.as_view(), name="获取验证码"), + path('login', webView.LoginView.as_view(), name="登录"), + path('logout', webView.LogoutView.as_view(), name="退出登录"), + path('getInfo', webView.GetInfoView.as_view(), name="获取登陆信息"), + path('getRouters', webView.GetRoutersView.as_view(), name="获取用户权限路由"), +] diff --git a/admin-api/web/views.py b/admin-api/web/views.py new file mode 100644 index 0000000..c1d2203 --- /dev/null +++ b/admin-api/web/views.py @@ -0,0 +1,199 @@ +import json +import uuid + +from addict import Dict +from django.http.response import JsonResponse +from django_redis import get_redis_connection +from rest_framework.views import APIView + +from config import config +from utils.myDataUtils import TreeBuilder +from utils.myEncrypt import HashCipher +from utils.myEnum import SystemDelEnum, SystemStatusEnum +from utils.myResFormat import ResultJson, ResultCode +from utils.myTimeFormat import MyTimeUtils +from web.captchaImage import CaptchaImage +from web.models import SystemUser, SystemUserRole, SystemRole, SystemRoleMenu, SystemMenu +from web.serializer import SystemUserSerializer, SystemMenuSerializer, SystemRoleSerializer + +RedisClient = get_redis_connection() + + +class CaptchaImageView(APIView): + + def get(self, request, *args, **kwargs): + """【系统用户】获取验证码""" + captcha = CaptchaImage() + + # 生成验证码图片和字符串 + captcha_string, image_base64 = captcha.generate(width=120, height=40) + + res = Dict() + uid = uuid.uuid4().hex + res.img = image_base64 + res.uuid = uid + res.captchaEnabled = True + + RedisClient.set(uid, captcha_string, ex=5 * 60) + + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=res.to_dict()).result) + + +class LoginView(APIView): + "登录" + + def post(self, request, *args, **kwargs): + + username = request.data.get("username", "") + password = request.data.get("password", "") + + # 如果有验证码的情况,校验方式 + uid = request.data.get("uuid", "") + code = request.data.get("code", "") + + # 密码加密 + password = HashCipher.md5(config.ENCRYPT_STRING + str(password)) + + if uid: + authCode = RedisClient.get(uid) + if not authCode: + return JsonResponse(ResultJson(ResultCode.AUTH_CODE_EXP).result) + else: + if str(authCode).strip() != str(code).strip(): + return JsonResponse(ResultJson(ResultCode.AUTH_CODE_ERROR).result) + + Users = SystemUser.objects.filter(username=username, password=password) + if not Users: + return JsonResponse(ResultJson(ResultCode.PASSWORD_ERROR).result) + + User = Users.first() + user_data = SystemUserSerializer(instance=User).data + + # 用户是否被删除 + if User.delFlag == SystemDelEnum.p1.value: + return JsonResponse(ResultJson(ResultCode.USER_NOT_EXIST).result) + + # 用户是否被禁用 + if User.status == SystemStatusEnum.p1.value: + return JsonResponse(ResultJson(ResultCode.USER_NOT_ALLOW).result) + + # 更新用户的登陆信息 + User.loginIp = request.META.get("REMOTE_ADDR", "") + User.loginDate = MyTimeUtils.TimeFormat() + User.save() + + # 获取角色信息 + token = uuid.uuid4().hex + userInfo = Dict() + + # 找到用户id和角色的映射 + UserRoleMap = SystemUserRole.objects.filter(userId=User.userId) + + RoleDataList = SystemRole.objects.filter(roleId__in=[roleItem.roleId for roleItem in UserRoleMap], delFlag=SystemDelEnum.p0.value, + status=SystemStatusEnum.p0.value) + + userInfo.user = user_data + userInfo.roles = [role.roleKey for role in RoleDataList] + user_data["role"] = SystemRoleSerializer(instance=RoleDataList, many=True).data + + if any([role.roleAdmin for role in RoleDataList]): + userInfo.permissions = ["*:*:*"] + else: + + roleIds = list(set([item.roleId for item in RoleDataList])) + + # 对目录权限进行去重 + RoleMenus = SystemRoleMenu.objects.filter(roleId__in=roleIds) + + menuIds = list(set([item.menuId for item in RoleMenus])) + + Menus = SystemMenu.objects.filter(menuId__in=menuIds, status=SystemStatusEnum.p0.value) + + userInfo.permissions = [item.perms for item in Menus] + + RedisClient.set(token, json.dumps(userInfo.to_dict()), ex=60 * 60) + + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=token).result) + + +class LogoutView(APIView): + "退出登录" + + def post(self, request, *args, **kwargs): + token = request.headers.user_info.get("token") + + # token不存在的情况 + if not token: + return JsonResponse(ResultJson(ResultCode.SUCCESS).result) + + RedisClient.delete(token) + return JsonResponse(ResultJson(ResultCode.SUCCESS).result) + + +class GetInfoView(APIView): + "获取登陆信息" + + def get(self, request, *args, **kwargs): + user_info = request.headers.user_info + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=user_info).result) + + +class GetRoutersView(APIView): + "获取用户权限路由" + + def routerFormat(self, MenuData): + # 目录数据组装前端的路由格式 + container = [] + for item in MenuData: + # 组装目录 + if item.get('menuType') == 'M': + + # 判断是否外链接 + if item.get('isFrame') == "0": + menuItem = {"id": item.get('menuId'), "parentId": item.get('parentId'), "component": "Layout", "hidden": bool(int(item.get('visible'))), + "path": item.get('path'), "name": item.get('path'), + "meta": {"icon": item.get('icon'), "link": item.get('path'), "noCache": bool(int(item.get('isCache'))), + "title": item.get('menuName'), } + + } + else: + menuItem = {"id": item.get('menuId'), "parentId": item.get('parentId'), "component": "Layout", "hidden": bool(int(item.get('visible'))), + "path": "/" + item.get('path'), "name": str(item.get('path')).capitalize(), "redirect": "noRedirect", + "meta": {"icon": item.get('icon'), "link": "", "noCache": bool(int(item.get('isCache'))), "title": item.get('menuName'), }} + container.append(menuItem) + + # 处理组件形式 + elif item.get('menuType') == 'C': + menuItem = {"id": item.get('menuId'), "parentId": item.get('parentId'), "component": item.get('component'), + "hidden": bool(int(item.get('visible'))), "path": item.get('path'), "name": str(item.get('path')).capitalize(), + "redirect": "noRedirect", + "meta": {"icon": item.get('icon'), "link": "", "noCache": bool(int(item.get('isCache'))), "title": item.get('menuName'), }} + container.append(menuItem) + + # 基础数据组装后,组装成树结构 + treeData = TreeBuilder(container).build(parentKey="parentId", ownerKey="id", topParent="0") + return list(treeData.values()) if treeData else [] + + def get(self, request, *args, **kwargs): + + user_info = request.headers.user_info + + # 获取用户的角色信息 + roleData = user_info.get("user", {}).get("role", []) + roleAdminList = [roleItem.get("roleAdmin") for roleItem in roleData] + + if any(roleAdminList): + Menus = SystemMenu.objects.all() + else: + roleIds = list(set([item.get("roleId") for item in roleData])) + + # 对目录权限进行去重 + RoleMenus = SystemRoleMenu.objects.filter(roleId__in=roleIds) + + menuIds = list(set([item.menuId for item in RoleMenus])) + + Menus = SystemMenu.objects.filter(menuId__in=menuIds, status=SystemStatusEnum.p0.value) + + MenuData = SystemMenuSerializer(instance=Menus, many=True).data + routerInfo = self.routerFormat(MenuData) + return JsonResponse(ResultJson(ResultCode.SUCCESS, data=routerInfo).result) diff --git a/admin-ui/.env.development b/admin-ui/.env.development new file mode 100644 index 0000000..98713c4 --- /dev/null +++ b/admin-ui/.env.development @@ -0,0 +1,9 @@ +# 页面标题 +VITE_APP_TITLE = 若依后台管理系统 + +# 开发环境配置 +VITE_APP_ENV = 'development' + +# 若依管理系统/开发环境 +VITE_APP_BASE_API = '/dev-api' + diff --git a/admin-ui/.env.production b/admin-ui/.env.production new file mode 100644 index 0000000..394212d --- /dev/null +++ b/admin-ui/.env.production @@ -0,0 +1,11 @@ +# 页面标题 +VITE_APP_TITLE = '若依管理系统' + +# 生产环境配置 +VITE_APP_ENV = 'production' + +# 若依管理系统/生产环境 +VITE_APP_BASE_API = 'http://124.71.212.219:8090/api' + +# 是否在打包时开启压缩,支持 gzip 和 brotli +VITE_BUILD_COMPRESS = gzip \ No newline at end of file diff --git a/admin-ui/.env.staging b/admin-ui/.env.staging new file mode 100644 index 0000000..12a8601 --- /dev/null +++ b/admin-ui/.env.staging @@ -0,0 +1,11 @@ +# 页面标题 +VITE_APP_TITLE = 若依后台管理 + +# 生产环境配置 +VITE_APP_ENV = 'staging' + +# 若依管理系统/生产环境 +VITE_APP_BASE_API = '/stage-api' + +# 是否在打包时开启压缩,支持 gzip 和 brotli +VITE_BUILD_COMPRESS = gzip \ No newline at end of file diff --git a/admin-ui/.gitignore b/admin-ui/.gitignore new file mode 100644 index 0000000..78a752d --- /dev/null +++ b/admin-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/admin-ui/Dockerfile b/admin-ui/Dockerfile new file mode 100644 index 0000000..5cc144e --- /dev/null +++ b/admin-ui/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:latest +WORKDIR /app +COPY ./dist /usr/share/nginx/html +EXPOSE 80 \ No newline at end of file diff --git a/admin-ui/LICENSE b/admin-ui/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/admin-ui/build.sh b/admin-ui/build.sh new file mode 100644 index 0000000..cae0d55 --- /dev/null +++ b/admin-ui/build.sh @@ -0,0 +1,4 @@ +git pull +yarn run build:prod +docker-compose build +docker-compose up -d \ No newline at end of file diff --git a/admin-ui/docker-compose.yaml b/admin-ui/docker-compose.yaml new file mode 100644 index 0000000..2941fba --- /dev/null +++ b/admin-ui/docker-compose.yaml @@ -0,0 +1,18 @@ +version: '3.0' + +services: + + django-vue-ui-std: + + build: + context: . + dockerfile: Dockerfile + + image: django-vue-ui-image-std + + container_name: django-vue-ui-container-std + + ports: + - "8101:80" + + restart: always \ No newline at end of file diff --git a/admin-ui/html/ie.html b/admin-ui/html/ie.html new file mode 100644 index 0000000..052ffcd --- /dev/null +++ b/admin-ui/html/ie.html @@ -0,0 +1,46 @@ + + + + + + 请升级您的浏览器 + + + + + + +

    请升级您的浏览器,以便我们更好的为您提供服务!

    +

    您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。

    +
    +

    请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束

    +

    自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明

    +
    +

    您可以选择更先进的浏览器

    +

    推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。

    + +
    + + \ No newline at end of file diff --git a/admin-ui/index.html b/admin-ui/index.html new file mode 100644 index 0000000..d755a92 --- /dev/null +++ b/admin-ui/index.html @@ -0,0 +1,216 @@ + + + + + + + + + + 后台管理系统 + + + + + +
    +
    +
    +
    +
    +
    系统加载中,请稍后.......
    +
    +
    + + + + \ No newline at end of file diff --git a/admin-ui/package.json b/admin-ui/package.json new file mode 100644 index 0000000..ad83ed1 --- /dev/null +++ b/admin-ui/package.json @@ -0,0 +1,45 @@ +{ + "name": "ruoyi", + "version": "3.8.7", + "description": "若依管理系统", + "author": "若依", + "license": "MIT", + "type": "module", + "scripts": { + "dev": "vite", + "build:prod": "vite build --mode production", + "build:stage": "vite build --mode staging", + "preview": "vite preview" + }, + "repository": { + "type": "git", + "url": "https://gitee.com/y_project/RuoYi-Vue.git" + }, + "dependencies": { + "@element-plus/icons-vue": "2.3.1", + "@vueup/vue-quill": "1.2.0", + "@vueuse/core": "10.6.1", + "axios": "0.27.2", + "echarts": "5.4.3", + "element-plus": "2.4.3", + "file-saver": "2.0.5", + "fuse.js": "6.6.2", + "js-cookie": "3.0.5", + "jsencrypt": "3.3.2", + "nprogress": "0.2.0", + "pinia": "2.1.7", + "vue": "3.3.9", + "vue-cropper": "1.1.1", + "vue-router": "4.2.5" + }, + "devDependencies": { + "@vitejs/plugin-vue": "4.5.0", + "@vue/compiler-sfc": "3.3.9", + "sass": "1.69.5", + "unplugin-auto-import": "0.17.1", + "vite": "5.0.4", + "vite-plugin-compression": "0.5.1", + "vite-plugin-svg-icons": "2.0.1", + "unplugin-vue-setup-extend-plus": "1.0.0" + } +} diff --git a/admin-ui/public/favicon.ico b/admin-ui/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e26376026420542212ed58d90d0ed34f554fa4ae GIT binary patch literal 5663 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 + + + + diff --git a/admin-ui/src/api/login.js b/admin-ui/src/api/login.js new file mode 100644 index 0000000..f5825a1 --- /dev/null +++ b/admin-ui/src/api/login.js @@ -0,0 +1,51 @@ +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, code, uuid) { + const data = { + username, + password, + code, + uuid + } + return request({ + url: '/login', + + method: 'post', + data: data + }) +} + +// 注册方法 +export function register(data) { + return request({ + url: '/register', + method: 'post', + data: data + }) +} + +// 获取用户详细信息 +export function getInfo() { + return request({ + url: '/getInfo', + method: 'get' + }) +} + +// 退出方法 +export function logout() { + return request({ + url: '/logout', + method: 'post' + }) +} + +// 获取验证码 +export function getCodeImg() { + return request({ + url: '/captchaImage', + method: 'get', + timeout: 20000 + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/menu.js b/admin-ui/src/api/menu.js new file mode 100644 index 0000000..faef101 --- /dev/null +++ b/admin-ui/src/api/menu.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获取路由 +export const getRouters = () => { + return request({ + url: '/getRouters', + method: 'get' + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/monitor/cache.js b/admin-ui/src/api/monitor/cache.js new file mode 100644 index 0000000..72c5f6a --- /dev/null +++ b/admin-ui/src/api/monitor/cache.js @@ -0,0 +1,57 @@ +import request from '@/utils/request' + +// 查询缓存详细 +export function getCache() { + return request({ + url: '/monitor/cache', + method: 'get' + }) +} + +// 查询缓存名称列表 +export function listCacheName() { + return request({ + url: '/monitor/cache/getNames', + method: 'get' + }) +} + +// 查询缓存键名列表 +export function listCacheKey(cacheName) { + return request({ + url: '/monitor/cache/getKeys/' + cacheName, + method: 'get' + }) +} + +// 查询缓存内容 +export function getCacheValue(cacheName, cacheKey) { + return request({ + url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, + method: 'get' + }) +} + +// 清理指定名称缓存 +export function clearCacheName(cacheName) { + return request({ + url: '/monitor/cache/clearCacheName/' + cacheName, + method: 'delete' + }) +} + +// 清理指定键名缓存 +export function clearCacheKey(cacheKey) { + return request({ + url: '/monitor/cache/clearCacheKey/' + cacheKey, + method: 'delete' + }) +} + +// 清理全部缓存 +export function clearCacheAll() { + return request({ + url: '/monitor/cache/clearCacheAll', + method: 'delete' + }) +} diff --git a/admin-ui/src/api/monitor/job.js b/admin-ui/src/api/monitor/job.js new file mode 100644 index 0000000..3815569 --- /dev/null +++ b/admin-ui/src/api/monitor/job.js @@ -0,0 +1,71 @@ +import request from '@/utils/request' + +// 查询定时任务调度列表 +export function listJob(query) { + return request({ + url: '/monitor/job/list', + method: 'get', + params: query + }) +} + +// 查询定时任务调度详细 +export function getJob(jobId) { + return request({ + url: '/monitor/job/' + jobId, + method: 'get' + }) +} + +// 新增定时任务调度 +export function addJob(data) { + return request({ + url: '/monitor/job', + method: 'post', + data: data + }) +} + +// 修改定时任务调度 +export function updateJob(data) { + return request({ + url: '/monitor/job', + method: 'put', + data: data + }) +} + +// 删除定时任务调度 +export function delJob(jobId) { + return request({ + url: '/monitor/job/' + jobId, + method: 'delete' + }) +} + +// 任务状态修改 +export function changeJobStatus(jobId, status) { + const data = { + jobId, + status + } + return request({ + url: '/monitor/job/changeStatus', + method: 'put', + data: data + }) +} + + +// 定时任务立即执行一次 +export function runJob(jobId, jobGroup) { + const data = { + jobId, + jobGroup + } + return request({ + url: '/monitor/job/run', + method: 'put', + data: data + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/monitor/jobLog.js b/admin-ui/src/api/monitor/jobLog.js new file mode 100644 index 0000000..6e0be61 --- /dev/null +++ b/admin-ui/src/api/monitor/jobLog.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 查询调度日志列表 +export function listJobLog(query) { + return request({ + url: '/monitor/jobLog/list', + method: 'get', + params: query + }) +} + +// 删除调度日志 +export function delJobLog(jobLogId) { + return request({ + url: '/monitor/jobLog/' + jobLogId, + method: 'delete' + }) +} + +// 清空调度日志 +export function cleanJobLog() { + return request({ + url: '/monitor/jobLog/clean', + method: 'delete' + }) +} diff --git a/admin-ui/src/api/monitor/logininfor.js b/admin-ui/src/api/monitor/logininfor.js new file mode 100644 index 0000000..4d112b7 --- /dev/null +++ b/admin-ui/src/api/monitor/logininfor.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' + +// 查询登录日志列表 +export function list(query) { + return request({ + url: '/monitor/logininfor/list', + method: 'get', + params: query + }) +} + +// 删除登录日志 +export function delLogininfor(infoId) { + return request({ + url: '/monitor/logininfor/' + infoId, + method: 'delete' + }) +} + +// 解锁用户登录状态 +export function unlockLogininfor(userName) { + return request({ + url: '/monitor/logininfor/unlock/' + userName, + method: 'get' + }) +} + +// 清空登录日志 +export function cleanLogininfor() { + return request({ + url: '/monitor/logininfor/clean', + method: 'delete' + }) +} diff --git a/admin-ui/src/api/monitor/online.js b/admin-ui/src/api/monitor/online.js new file mode 100644 index 0000000..bd22137 --- /dev/null +++ b/admin-ui/src/api/monitor/online.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 查询在线用户列表 +export function list(query) { + return request({ + url: '/monitor/online/list', + method: 'get', + params: query + }) +} + +// 强退用户 +export function forceLogout(tokenId) { + return request({ + url: '/monitor/online/' + tokenId, + method: 'delete' + }) +} diff --git a/admin-ui/src/api/monitor/operlog.js b/admin-ui/src/api/monitor/operlog.js new file mode 100644 index 0000000..a04bca8 --- /dev/null +++ b/admin-ui/src/api/monitor/operlog.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 查询操作日志列表 +export function list(query) { + return request({ + url: '/monitor/operlog/list', + method: 'get', + params: query + }) +} + +// 删除操作日志 +export function delOperlog(operId) { + return request({ + url: '/monitor/operlog/' + operId, + method: 'delete' + }) +} + +// 清空操作日志 +export function cleanOperlog() { + return request({ + url: '/monitor/operlog/clean', + method: 'delete' + }) +} diff --git a/admin-ui/src/api/monitor/server.js b/admin-ui/src/api/monitor/server.js new file mode 100644 index 0000000..e1f9ca2 --- /dev/null +++ b/admin-ui/src/api/monitor/server.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获取服务信息 +export function getServer() { + return request({ + url: '/monitor/server', + method: 'get' + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/system/config.js b/admin-ui/src/api/system/config.js new file mode 100644 index 0000000..a404d82 --- /dev/null +++ b/admin-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/admin-ui/src/api/system/dept.js b/admin-ui/src/api/system/dept.js new file mode 100644 index 0000000..fc943cd --- /dev/null +++ b/admin-ui/src/api/system/dept.js @@ -0,0 +1,52 @@ +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 delDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/system/dict/data.js b/admin-ui/src/api/system/dict/data.js new file mode 100644 index 0000000..6c9eb79 --- /dev/null +++ b/admin-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/admin-ui/src/api/system/dict/type.js b/admin-ui/src/api/system/dict/type.js new file mode 100644 index 0000000..a0254ba --- /dev/null +++ b/admin-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' + }) +} diff --git a/admin-ui/src/api/system/menu.js b/admin-ui/src/api/system/menu.js new file mode 100644 index 0000000..f6415c6 --- /dev/null +++ b/admin-ui/src/api/system/menu.js @@ -0,0 +1,60 @@ +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 delMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/system/notice.js b/admin-ui/src/api/system/notice.js new file mode 100644 index 0000000..c274ea5 --- /dev/null +++ b/admin-ui/src/api/system/notice.js @@ -0,0 +1,44 @@ +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' + }) +} \ No newline at end of file diff --git a/admin-ui/src/api/system/post.js b/admin-ui/src/api/system/post.js new file mode 100644 index 0000000..1a8e9ca --- /dev/null +++ b/admin-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/admin-ui/src/api/system/role.js b/admin-ui/src/api/system/role.js new file mode 100644 index 0000000..f13e6f4 --- /dev/null +++ b/admin-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/admin-ui/src/api/system/user.js b/admin-ui/src/api/system/user.js new file mode 100644 index 0000000..147343e --- /dev/null +++ b/admin-ui/src/api/system/user.js @@ -0,0 +1,135 @@ +import request from '@/utils/request' +import { parseStrEmpty } from "@/utils/ruoyi"; + +// 查询用户列表 +export function listUser(query) { + return request({ + url: '/system/user/list', + method: 'get', + params: query + }) +} + +// 查询用户详细 +export function getUser(userId) { + return request({ + url: '/system/user/' + parseStrEmpty(userId), + method: 'get' + }) +} + +// 新增用户 +export function addUser(data) { + return request({ + url: '/system/user/', + method: 'post', + data: data + }) +} + +// 修改用户 +export function updateUser(data) { + return request({ + url: '/system/user/', + method: 'put', + data: data + }) +} + +// 删除用户 +export function delUser(userId) { + return request({ + url: '/system/user/' + userId, + method: 'delete' + }) +} + +// 用户密码重置 +export function resetUserPwd(userId, password) { + const data = { + userId, + password + } + return request({ + url: '/system/user/resetPwd', + method: 'put', + data: data + }) +} + +// 用户状态修改 +export function changeUserStatus(userId, status) { + const data = { + userId, + status + } + return request({ + url: '/system/user/changeStatus', + method: 'put', + data: data + }) +} + +// 查询用户个人信息 +export function getUserProfile() { + return request({ + url: '/system/user/profile', + method: 'get' + }) +} + +// 修改用户个人信息 +export function updateUserProfile(data) { + return request({ + url: '/system/user/profile', + method: 'put', + data: data + }) +} + +// 用户密码重置 +export function updateUserPwd(oldPassword, newPassword) { + const data = { + oldPassword, + newPassword + } + return request({ + url: '/system/user/profile/updatePwd', + method: 'put', + params: data + }) +} + +// 用户头像上传 +export function uploadAvatar(data) { + return request({ + url: '/system/user/profile/avatar', + method: 'post', + data: data + }) +} + +// 查询授权角色 +export function getAuthRole(userId) { + return request({ + url: '/system/user/authRole/' + userId, + method: 'get' + }) +} + +// 保存授权角色 +export function updateAuthRole(data) { + return request({ + url: '/system/user/authRole', + method: 'put', + params: data + }) +} + +// 查询部门下拉树结构 +export function deptTreeSelect() { + return request({ + url: '/system/user/deptTree', + method: 'get' + }) +} diff --git a/admin-ui/src/api/tool/gen.js b/admin-ui/src/api/tool/gen.js new file mode 100644 index 0000000..4506927 --- /dev/null +++ b/admin-ui/src/api/tool/gen.js @@ -0,0 +1,76 @@ +import request from '@/utils/request' + +// 查询生成表数据 +export function listTable(query) { + return request({ + url: '/tool/gen/list', + method: 'get', + params: query + }) +} +// 查询db数据库列表 +export function listDbTable(query) { + return request({ + url: '/tool/gen/db/list', + method: 'get', + params: query + }) +} + +// 查询表详细信息 +export function getGenTable(tableId) { + return request({ + url: '/tool/gen/' + tableId, + method: 'get' + }) +} + +// 修改代码生成信息 +export function updateGenTable(data) { + return request({ + url: '/tool/gen', + method: 'put', + data: data + }) +} + +// 导入表 +export function importTable(data) { + return request({ + url: '/tool/gen/importTable', + method: 'post', + params: data + }) +} + +// 预览生成代码 +export function previewTable(tableId) { + return request({ + url: '/tool/gen/preview/' + tableId, + method: 'get' + }) +} + +// 删除表数据 +export function delTable(tableId) { + return request({ + url: '/tool/gen/' + tableId, + method: 'delete' + }) +} + +// 生成代码(自定义路径) +export function genCode(tableName) { + return request({ + url: '/tool/gen/genCode/' + tableName, + method: 'get' + }) +} + +// 同步数据库 +export function synchDb(tableName) { + return request({ + url: '/tool/gen/synchDb/' + tableName, + method: 'get' + }) +} diff --git a/admin-ui/src/assets/icons/svg/404.svg b/admin-ui/src/assets/icons/svg/404.svg new file mode 100644 index 0000000..6df5019 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/bug.svg b/admin-ui/src/assets/icons/svg/bug.svg new file mode 100644 index 0000000..05a150d --- /dev/null +++ b/admin-ui/src/assets/icons/svg/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/build.svg b/admin-ui/src/assets/icons/svg/build.svg new file mode 100644 index 0000000..97c4688 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/build.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/button.svg b/admin-ui/src/assets/icons/svg/button.svg new file mode 100644 index 0000000..904fddc --- /dev/null +++ b/admin-ui/src/assets/icons/svg/button.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/cascader.svg b/admin-ui/src/assets/icons/svg/cascader.svg new file mode 100644 index 0000000..e256024 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/cascader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/chart.svg b/admin-ui/src/assets/icons/svg/chart.svg new file mode 100644 index 0000000..27728fb --- /dev/null +++ b/admin-ui/src/assets/icons/svg/chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/checkbox.svg b/admin-ui/src/assets/icons/svg/checkbox.svg new file mode 100644 index 0000000..013fd3a --- /dev/null +++ b/admin-ui/src/assets/icons/svg/checkbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/clipboard.svg b/admin-ui/src/assets/icons/svg/clipboard.svg new file mode 100644 index 0000000..90923ff --- /dev/null +++ b/admin-ui/src/assets/icons/svg/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/code.svg b/admin-ui/src/assets/icons/svg/code.svg new file mode 100644 index 0000000..5f9c5ab --- /dev/null +++ b/admin-ui/src/assets/icons/svg/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/color.svg b/admin-ui/src/assets/icons/svg/color.svg new file mode 100644 index 0000000..44a81aa --- /dev/null +++ b/admin-ui/src/assets/icons/svg/color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/component.svg b/admin-ui/src/assets/icons/svg/component.svg new file mode 100644 index 0000000..29c3458 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/component.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/dashboard.svg b/admin-ui/src/assets/icons/svg/dashboard.svg new file mode 100644 index 0000000..5317d37 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/date-range.svg b/admin-ui/src/assets/icons/svg/date-range.svg new file mode 100644 index 0000000..fda571e --- /dev/null +++ b/admin-ui/src/assets/icons/svg/date-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/date.svg b/admin-ui/src/assets/icons/svg/date.svg new file mode 100644 index 0000000..52dc73e --- /dev/null +++ b/admin-ui/src/assets/icons/svg/date.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/dict.svg b/admin-ui/src/assets/icons/svg/dict.svg new file mode 100644 index 0000000..4849377 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/dict.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/documentation.svg b/admin-ui/src/assets/icons/svg/documentation.svg new file mode 100644 index 0000000..7043122 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/documentation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/download.svg b/admin-ui/src/assets/icons/svg/download.svg new file mode 100644 index 0000000..c896951 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/drag.svg b/admin-ui/src/assets/icons/svg/drag.svg new file mode 100644 index 0000000..4185d3c --- /dev/null +++ b/admin-ui/src/assets/icons/svg/drag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/druid.svg b/admin-ui/src/assets/icons/svg/druid.svg new file mode 100644 index 0000000..a2b4b4e --- /dev/null +++ b/admin-ui/src/assets/icons/svg/druid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/edit.svg b/admin-ui/src/assets/icons/svg/edit.svg new file mode 100644 index 0000000..d26101f --- /dev/null +++ b/admin-ui/src/assets/icons/svg/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/education.svg b/admin-ui/src/assets/icons/svg/education.svg new file mode 100644 index 0000000..7bfb01d --- /dev/null +++ b/admin-ui/src/assets/icons/svg/education.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/email.svg b/admin-ui/src/assets/icons/svg/email.svg new file mode 100644 index 0000000..74d25e2 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/example.svg b/admin-ui/src/assets/icons/svg/example.svg new file mode 100644 index 0000000..46f42b5 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/excel.svg b/admin-ui/src/assets/icons/svg/excel.svg new file mode 100644 index 0000000..74d97b8 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/excel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/exit-fullscreen.svg b/admin-ui/src/assets/icons/svg/exit-fullscreen.svg new file mode 100644 index 0000000..485c128 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/eye-open.svg b/admin-ui/src/assets/icons/svg/eye-open.svg new file mode 100644 index 0000000..88dcc98 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/eye.svg b/admin-ui/src/assets/icons/svg/eye.svg new file mode 100644 index 0000000..16ed2d8 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/form.svg b/admin-ui/src/assets/icons/svg/form.svg new file mode 100644 index 0000000..dcbaa18 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/fullscreen.svg b/admin-ui/src/assets/icons/svg/fullscreen.svg new file mode 100644 index 0000000..0e86b6f --- /dev/null +++ b/admin-ui/src/assets/icons/svg/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/github.svg b/admin-ui/src/assets/icons/svg/github.svg new file mode 100644 index 0000000..db0a0d4 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/guide.svg b/admin-ui/src/assets/icons/svg/guide.svg new file mode 100644 index 0000000..b271001 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/icon.svg b/admin-ui/src/assets/icons/svg/icon.svg new file mode 100644 index 0000000..82be8ee --- /dev/null +++ b/admin-ui/src/assets/icons/svg/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/input.svg b/admin-ui/src/assets/icons/svg/input.svg new file mode 100644 index 0000000..ab91381 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/input.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/international.svg b/admin-ui/src/assets/icons/svg/international.svg new file mode 100644 index 0000000..e9b56ee --- /dev/null +++ b/admin-ui/src/assets/icons/svg/international.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/job.svg b/admin-ui/src/assets/icons/svg/job.svg new file mode 100644 index 0000000..2a93a25 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/job.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/language.svg b/admin-ui/src/assets/icons/svg/language.svg new file mode 100644 index 0000000..0082b57 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/link.svg b/admin-ui/src/assets/icons/svg/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/admin-ui/src/assets/icons/svg/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/list.svg b/admin-ui/src/assets/icons/svg/list.svg new file mode 100644 index 0000000..20259ed --- /dev/null +++ b/admin-ui/src/assets/icons/svg/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/lock.svg b/admin-ui/src/assets/icons/svg/lock.svg new file mode 100644 index 0000000..74fee54 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/log.svg b/admin-ui/src/assets/icons/svg/log.svg new file mode 100644 index 0000000..d879d33 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/logininfor.svg b/admin-ui/src/assets/icons/svg/logininfor.svg new file mode 100644 index 0000000..267f844 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/logininfor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/message.svg b/admin-ui/src/assets/icons/svg/message.svg new file mode 100644 index 0000000..14ca817 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/message.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/money.svg b/admin-ui/src/assets/icons/svg/money.svg new file mode 100644 index 0000000..c1580de --- /dev/null +++ b/admin-ui/src/assets/icons/svg/money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/monitor.svg b/admin-ui/src/assets/icons/svg/monitor.svg new file mode 100644 index 0000000..bc308cb --- /dev/null +++ b/admin-ui/src/assets/icons/svg/monitor.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/nested.svg b/admin-ui/src/assets/icons/svg/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/number.svg b/admin-ui/src/assets/icons/svg/number.svg new file mode 100644 index 0000000..ad5ce9a --- /dev/null +++ b/admin-ui/src/assets/icons/svg/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/online.svg b/admin-ui/src/assets/icons/svg/online.svg new file mode 100644 index 0000000..330a202 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/online.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/password.svg b/admin-ui/src/assets/icons/svg/password.svg new file mode 100644 index 0000000..6c64def --- /dev/null +++ b/admin-ui/src/assets/icons/svg/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/pdf.svg b/admin-ui/src/assets/icons/svg/pdf.svg new file mode 100644 index 0000000..957aa0c --- /dev/null +++ b/admin-ui/src/assets/icons/svg/pdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/people.svg b/admin-ui/src/assets/icons/svg/people.svg new file mode 100644 index 0000000..2bd54ae --- /dev/null +++ b/admin-ui/src/assets/icons/svg/people.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/peoples.svg b/admin-ui/src/assets/icons/svg/peoples.svg new file mode 100644 index 0000000..aab852e --- /dev/null +++ b/admin-ui/src/assets/icons/svg/peoples.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/phone.svg b/admin-ui/src/assets/icons/svg/phone.svg new file mode 100644 index 0000000..ab8e8c4 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/post.svg b/admin-ui/src/assets/icons/svg/post.svg new file mode 100644 index 0000000..2922c61 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/post.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/qq.svg b/admin-ui/src/assets/icons/svg/qq.svg new file mode 100644 index 0000000..ee13d4e --- /dev/null +++ b/admin-ui/src/assets/icons/svg/qq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/question.svg b/admin-ui/src/assets/icons/svg/question.svg new file mode 100644 index 0000000..cf75bd4 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/radio.svg b/admin-ui/src/assets/icons/svg/radio.svg new file mode 100644 index 0000000..0cde345 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/rate.svg b/admin-ui/src/assets/icons/svg/rate.svg new file mode 100644 index 0000000..aa3b14d --- /dev/null +++ b/admin-ui/src/assets/icons/svg/rate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/redis-list.svg b/admin-ui/src/assets/icons/svg/redis-list.svg new file mode 100644 index 0000000..98a15b2 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/redis-list.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/redis.svg b/admin-ui/src/assets/icons/svg/redis.svg new file mode 100644 index 0000000..2f1d62d --- /dev/null +++ b/admin-ui/src/assets/icons/svg/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/row.svg b/admin-ui/src/assets/icons/svg/row.svg new file mode 100644 index 0000000..0780992 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/row.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/search.svg b/admin-ui/src/assets/icons/svg/search.svg new file mode 100644 index 0000000..84233dd --- /dev/null +++ b/admin-ui/src/assets/icons/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/select.svg b/admin-ui/src/assets/icons/svg/select.svg new file mode 100644 index 0000000..d628382 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/server.svg b/admin-ui/src/assets/icons/svg/server.svg new file mode 100644 index 0000000..eb287e3 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/shopping.svg b/admin-ui/src/assets/icons/svg/shopping.svg new file mode 100644 index 0000000..87513e7 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/shopping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/size.svg b/admin-ui/src/assets/icons/svg/size.svg new file mode 100644 index 0000000..ddb25b8 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/size.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/skill.svg b/admin-ui/src/assets/icons/svg/skill.svg new file mode 100644 index 0000000..a3b7312 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/skill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/slider.svg b/admin-ui/src/assets/icons/svg/slider.svg new file mode 100644 index 0000000..fbe4f39 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/slider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/star.svg b/admin-ui/src/assets/icons/svg/star.svg new file mode 100644 index 0000000..6cf86e6 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/swagger.svg b/admin-ui/src/assets/icons/svg/swagger.svg new file mode 100644 index 0000000..05d4e7b --- /dev/null +++ b/admin-ui/src/assets/icons/svg/swagger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/switch.svg b/admin-ui/src/assets/icons/svg/switch.svg new file mode 100644 index 0000000..0ba61e3 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/switch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/system.svg b/admin-ui/src/assets/icons/svg/system.svg new file mode 100644 index 0000000..5992593 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/system.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/tab.svg b/admin-ui/src/assets/icons/svg/tab.svg new file mode 100644 index 0000000..b4b48e4 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/table.svg b/admin-ui/src/assets/icons/svg/table.svg new file mode 100644 index 0000000..0e3dc9d --- /dev/null +++ b/admin-ui/src/assets/icons/svg/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/textarea.svg b/admin-ui/src/assets/icons/svg/textarea.svg new file mode 100644 index 0000000..2709f29 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/textarea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/theme.svg b/admin-ui/src/assets/icons/svg/theme.svg new file mode 100644 index 0000000..5982a2f --- /dev/null +++ b/admin-ui/src/assets/icons/svg/theme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/time-range.svg b/admin-ui/src/assets/icons/svg/time-range.svg new file mode 100644 index 0000000..13c1202 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/time-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/time.svg b/admin-ui/src/assets/icons/svg/time.svg new file mode 100644 index 0000000..b376e32 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/tool.svg b/admin-ui/src/assets/icons/svg/tool.svg new file mode 100644 index 0000000..48e0e35 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/tree-table.svg b/admin-ui/src/assets/icons/svg/tree-table.svg new file mode 100644 index 0000000..8aafdb8 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/tree-table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/tree.svg b/admin-ui/src/assets/icons/svg/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/admin-ui/src/assets/icons/svg/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/upload.svg b/admin-ui/src/assets/icons/svg/upload.svg new file mode 100644 index 0000000..bae49c0 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/user.svg b/admin-ui/src/assets/icons/svg/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/validCode.svg b/admin-ui/src/assets/icons/svg/validCode.svg new file mode 100644 index 0000000..cfb1021 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/validCode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/wechat.svg b/admin-ui/src/assets/icons/svg/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/icons/svg/zip.svg b/admin-ui/src/assets/icons/svg/zip.svg new file mode 100644 index 0000000..f806fc4 --- /dev/null +++ b/admin-ui/src/assets/icons/svg/zip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/src/assets/images/dark.svg b/admin-ui/src/assets/images/dark.svg new file mode 100644 index 0000000..f646bd7 --- /dev/null +++ b/admin-ui/src/assets/images/dark.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/admin-ui/src/assets/images/light.svg b/admin-ui/src/assets/images/light.svg new file mode 100644 index 0000000..ab7cc08 --- /dev/null +++ b/admin-ui/src/assets/images/light.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/admin-ui/src/assets/styles/btn.scss b/admin-ui/src/assets/styles/btn.scss new file mode 100644 index 0000000..3590d8d --- /dev/null +++ b/admin-ui/src/assets/styles/btn.scss @@ -0,0 +1,99 @@ +@import './variables.module.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/admin-ui/src/assets/styles/element-ui.scss b/admin-ui/src/assets/styles/element-ui.scss new file mode 100644 index 0000000..0f175f2 --- /dev/null +++ b/admin-ui/src/assets/styles/element-ui.scss @@ -0,0 +1,96 @@ +// 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; +} + +.el-dropdown .el-dropdown-link{ + color: var(--el-color-primary) !important; +} \ No newline at end of file diff --git a/admin-ui/src/assets/styles/index.scss b/admin-ui/src/assets/styles/index.scss new file mode 100644 index 0000000..2b8dca5 --- /dev/null +++ b/admin-ui/src/assets/styles/index.scss @@ -0,0 +1,184 @@ +@import './variables.module.scss'; +@import './mixin.scss'; +@import './transition.scss'; +@import './element-ui.scss'; +@import './sidebar.scss'; +@import './btn.scss'; +@import './ruoyi.scss'; + +body { + height: 100%; + margin: 0; + -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; +} + +.pagination-container { + margin-top: 30px; +} + +.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/admin-ui/src/assets/styles/mixin.scss b/admin-ui/src/assets/styles/mixin.scss new file mode 100644 index 0000000..06fa061 --- /dev/null +++ b/admin-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/admin-ui/src/assets/styles/ruoyi.scss b/admin-ui/src/assets/styles/ruoyi.scss new file mode 100644 index 0000000..155fdb7 --- /dev/null +++ b/admin-ui/src/assets/styles/ruoyi.scss @@ -0,0 +1,281 @@ + /** + * 通用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-form .el-form-item__label { + font-weight: 700; +} +.el-dialog:not(.is-fullscreen) { + margin-top: 6vh !important; +} + +.el-dialog.scrollbar .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 !important; + color: #515a6e; + height: 40px !important; + 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 { + position: relative; + height: 25px; + margin-bottom: 10px; + margin-top: 15px; + padding: 10px 20px !important; +} + +.el-dialog .pagination-container { + position: static !important; +} + +/* tree border */ +.tree-border { + margin-top: 5px; + border: 1px solid #e5e6e7; + background: #FFFFFF none; + border-radius:4px; + width: 100%; +} + +.pagination-container .el-pagination { + right: 0; + position: absolute; +} + +@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--small { + padding-left: 0; + padding-right: 0; + width: inherit; +} + +/** 表格更多操作下拉样式 */ +.el-table .el-dropdown-link { + cursor: pointer; + color: #409EFF; + margin-left: 10px; +} + +.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 !important; + min-height: 40px; +} + +.el-card__body { + padding: 15px 20px 20px 20px !important; +} + +.card-box { + padding-right: 15px; + padding-left: 15px; + 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; +} + +/* 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: absolute; + top: 50%; + transform: translate(50%, -50%); + width: 200px; + height: 200px; + border-radius: 50%; + box-shadow: 0 0 4px #ccc; + overflow: hidden; +} + +/* 拖拽列样式 */ +.sortable-ghost{ + opacity: .8; + color: #fff!important; + background: #42b983!important; +} + +/* 表格右侧工具栏样式 */ +.top-right-btn { + margin-left: auto; +} diff --git a/admin-ui/src/assets/styles/sidebar.scss b/admin-ui/src/assets/styles/sidebar.scss new file mode 100644 index 0000000..8b3c472 --- /dev/null +++ b/admin-ui/src/assets/styles/sidebar.scss @@ -0,0 +1,238 @@ +#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: 2px 0 6px rgba(0,21,41,.35); + + // 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: 16px; + } + + .el-menu { + border: none; + height: 100%; + width: 100% !important; + } + + .el-menu-item, .menu-title { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + .el-menu-item .el-menu-tooltip__trigger { + display: inline-block !important; + } + + // menu hover + .sub-menu-title-noDropdown, + .el-sub-menu__title { + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .is-active > .el-sub-menu__title { + color: $base-menu-color-active !important; + } + + & .nest-menu .el-sub-menu>.el-sub-menu__title, + & .el-sub-menu .el-menu-item { + min-width: $base-sidebar-width !important; + + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title, + & .theme-dark .el-sub-menu .el-menu-item { + background-color: $base-sub-menu-background !important; + + &:hover { + background-color: $base-sub-menu-hover !important; + } + } + } + + .hideSidebar { + .sidebar-container { + width: 54px !important; + } + + .main-container { + margin-left: 54px; + } + + .sub-menu-title-noDropdown { + padding: 0 !important; + position: relative; + + .el-tooltip { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + } + } + + .el-sub-menu { + overflow: hidden; + + &>.el-sub-menu__title { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + + } + } + + .el-menu--collapse { + .el-sub-menu { + &>.el-sub-menu__title { + &>span { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + &>i { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + } + } + } + } + + .el-menu--collapse .el-menu .el-sub-menu { + 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-sub-menu>.el-sub-menu__title, + .el-menu-item { + &:hover { + // you can use $sub-menuHover + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + // the scroll bar appears when the sub-menu 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/admin-ui/src/assets/styles/transition.scss b/admin-ui/src/assets/styles/transition.scss new file mode 100644 index 0000000..073f8c6 --- /dev/null +++ b/admin-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/admin-ui/src/assets/styles/variables.module.scss b/admin-ui/src/assets/styles/variables.module.scss new file mode 100644 index 0000000..3dbfaa7 --- /dev/null +++ b/admin-ui/src/assets/styles/variables.module.scss @@ -0,0 +1,65 @@ +// 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: #f4f4f5; +$base-menu-background: #304156; +$base-logo-title-color: #ffffff; + +$base-menu-light-color: rgba(0, 0, 0, 0.7); +$base-menu-light-background: #ffffff; +$base-logo-light-title-color: #001529; + +$base-sub-menu-background: #1f2d3d; +$base-sub-menu-hover: #001528; + +// 自定义暗色菜单风格 +/** +$base-menu-color:hsla(0,0%,100%,.65); +$base-menu-color-active:#fff; +$base-menu-background:#001529; +$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:#000c17; +$base-sub-menu-hover:#001528; +*/ + +$--color-primary: #409EFF; +$--color-success: #67C23A; +$--color-warning: #E6A23C; +$--color-danger: #F56C6C; +$--color-info: #909399; + +$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; + primaryColor: $--color-primary; + successColor: $--color-success; + dangerColor: $--color-danger; + infoColor: $--color-info; + warningColor: $--color-warning; +} diff --git a/admin-ui/src/components/Breadcrumb/index.vue b/admin-ui/src/components/Breadcrumb/index.vue new file mode 100644 index 0000000..489cba1 --- /dev/null +++ b/admin-ui/src/components/Breadcrumb/index.vue @@ -0,0 +1,66 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/day.vue b/admin-ui/src/components/Crontab/day.vue new file mode 100644 index 0000000..25c4f79 --- /dev/null +++ b/admin-ui/src/components/Crontab/day.vue @@ -0,0 +1,174 @@ + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/hour.vue b/admin-ui/src/components/Crontab/hour.vue new file mode 100644 index 0000000..9f052ad --- /dev/null +++ b/admin-ui/src/components/Crontab/hour.vue @@ -0,0 +1,127 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/index.vue b/admin-ui/src/components/Crontab/index.vue new file mode 100644 index 0000000..910c9b3 --- /dev/null +++ b/admin-ui/src/components/Crontab/index.vue @@ -0,0 +1,310 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/min.vue b/admin-ui/src/components/Crontab/min.vue new file mode 100644 index 0000000..5d80cd2 --- /dev/null +++ b/admin-ui/src/components/Crontab/min.vue @@ -0,0 +1,126 @@ + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/month.vue b/admin-ui/src/components/Crontab/month.vue new file mode 100644 index 0000000..657d3f2 --- /dev/null +++ b/admin-ui/src/components/Crontab/month.vue @@ -0,0 +1,141 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/result.vue b/admin-ui/src/components/Crontab/result.vue new file mode 100644 index 0000000..5a812ee --- /dev/null +++ b/admin-ui/src/components/Crontab/result.vue @@ -0,0 +1,540 @@ + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/second.vue b/admin-ui/src/components/Crontab/second.vue new file mode 100644 index 0000000..a7e5798 --- /dev/null +++ b/admin-ui/src/components/Crontab/second.vue @@ -0,0 +1,128 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/week.vue b/admin-ui/src/components/Crontab/week.vue new file mode 100644 index 0000000..105a3be --- /dev/null +++ b/admin-ui/src/components/Crontab/week.vue @@ -0,0 +1,197 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Crontab/year.vue b/admin-ui/src/components/Crontab/year.vue new file mode 100644 index 0000000..b26bdae --- /dev/null +++ b/admin-ui/src/components/Crontab/year.vue @@ -0,0 +1,149 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/DictTag/index.vue b/admin-ui/src/components/DictTag/index.vue new file mode 100644 index 0000000..7d0888c --- /dev/null +++ b/admin-ui/src/components/DictTag/index.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/admin-ui/src/components/Editor/index.vue b/admin-ui/src/components/Editor/index.vue new file mode 100644 index 0000000..0a696f2 --- /dev/null +++ b/admin-ui/src/components/Editor/index.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/admin-ui/src/components/FileUpload/index.vue b/admin-ui/src/components/FileUpload/index.vue new file mode 100644 index 0000000..2af9672 --- /dev/null +++ b/admin-ui/src/components/FileUpload/index.vue @@ -0,0 +1,207 @@ + + + + + diff --git a/admin-ui/src/components/Hamburger/index.vue b/admin-ui/src/components/Hamburger/index.vue new file mode 100644 index 0000000..18c201e --- /dev/null +++ b/admin-ui/src/components/Hamburger/index.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/admin-ui/src/components/HeaderSearch/index.vue b/admin-ui/src/components/HeaderSearch/index.vue new file mode 100644 index 0000000..6ef6d2c --- /dev/null +++ b/admin-ui/src/components/HeaderSearch/index.vue @@ -0,0 +1,187 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/IconSelect/index.vue b/admin-ui/src/components/IconSelect/index.vue new file mode 100644 index 0000000..517a4af --- /dev/null +++ b/admin-ui/src/components/IconSelect/index.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/IconSelect/requireIcons.js b/admin-ui/src/components/IconSelect/requireIcons.js new file mode 100644 index 0000000..ac22fd7 --- /dev/null +++ b/admin-ui/src/components/IconSelect/requireIcons.js @@ -0,0 +1,8 @@ +let icons = [] +const modules = import.meta.glob('./../../assets/icons/svg/*.svg'); +for (const path in modules) { + const p = path.split('assets/icons/svg/')[1].split('.svg')[0]; + icons.push(p); +} + +export default icons \ No newline at end of file diff --git a/admin-ui/src/components/ImagePreview/index.vue b/admin-ui/src/components/ImagePreview/index.vue new file mode 100644 index 0000000..7e3d2b6 --- /dev/null +++ b/admin-ui/src/components/ImagePreview/index.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/admin-ui/src/components/ImageUpload/index.vue b/admin-ui/src/components/ImageUpload/index.vue new file mode 100644 index 0000000..55dafb8 --- /dev/null +++ b/admin-ui/src/components/ImageUpload/index.vue @@ -0,0 +1,213 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/Pagination/index.vue b/admin-ui/src/components/Pagination/index.vue new file mode 100644 index 0000000..38de953 --- /dev/null +++ b/admin-ui/src/components/Pagination/index.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/ParentView/index.vue b/admin-ui/src/components/ParentView/index.vue new file mode 100644 index 0000000..7bf6148 --- /dev/null +++ b/admin-ui/src/components/ParentView/index.vue @@ -0,0 +1,3 @@ + diff --git a/admin-ui/src/components/RightToolbar/index.vue b/admin-ui/src/components/RightToolbar/index.vue new file mode 100644 index 0000000..5a53dd4 --- /dev/null +++ b/admin-ui/src/components/RightToolbar/index.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/admin-ui/src/components/SvgIcon/index.vue b/admin-ui/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..8c101f6 --- /dev/null +++ b/admin-ui/src/components/SvgIcon/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/admin-ui/src/components/SvgIcon/svgicon.js b/admin-ui/src/components/SvgIcon/svgicon.js new file mode 100644 index 0000000..4431719 --- /dev/null +++ b/admin-ui/src/components/SvgIcon/svgicon.js @@ -0,0 +1,10 @@ +import * as components from '@element-plus/icons-vue' + +export default { + install: (app) => { + for (const key in components) { + const componentConfig = components[key]; + app.component(componentConfig.name, componentConfig); + } + }, +}; diff --git a/admin-ui/src/components/TopNav/index.vue b/admin-ui/src/components/TopNav/index.vue new file mode 100644 index 0000000..52b40ea --- /dev/null +++ b/admin-ui/src/components/TopNav/index.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/admin-ui/src/components/TreeSelect/index.vue b/admin-ui/src/components/TreeSelect/index.vue new file mode 100644 index 0000000..4ff0e76 --- /dev/null +++ b/admin-ui/src/components/TreeSelect/index.vue @@ -0,0 +1,156 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/components/iFrame/index.vue b/admin-ui/src/components/iFrame/index.vue new file mode 100644 index 0000000..091b1a2 --- /dev/null +++ b/admin-ui/src/components/iFrame/index.vue @@ -0,0 +1,31 @@ + + + diff --git a/admin-ui/src/layout/components/Navbar.vue b/admin-ui/src/layout/components/Navbar.vue new file mode 100644 index 0000000..3f11f67 --- /dev/null +++ b/admin-ui/src/layout/components/Navbar.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/admin-ui/src/layout/components/Settings/index.vue b/admin-ui/src/layout/components/Settings/index.vue new file mode 100644 index 0000000..d0a0e88 --- /dev/null +++ b/admin-ui/src/layout/components/Settings/index.vue @@ -0,0 +1,205 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/layout/components/Sidebar/Link.vue b/admin-ui/src/layout/components/Sidebar/Link.vue new file mode 100644 index 0000000..8011431 --- /dev/null +++ b/admin-ui/src/layout/components/Sidebar/Link.vue @@ -0,0 +1,40 @@ + + + diff --git a/admin-ui/src/layout/components/Sidebar/Logo.vue b/admin-ui/src/layout/components/Sidebar/Logo.vue new file mode 100644 index 0000000..67582d0 --- /dev/null +++ b/admin-ui/src/layout/components/Sidebar/Logo.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/layout/components/Sidebar/SidebarItem.vue b/admin-ui/src/layout/components/Sidebar/SidebarItem.vue new file mode 100644 index 0000000..3a85e7e --- /dev/null +++ b/admin-ui/src/layout/components/Sidebar/SidebarItem.vue @@ -0,0 +1,102 @@ + + + diff --git a/admin-ui/src/layout/components/Sidebar/index.vue b/admin-ui/src/layout/components/Sidebar/index.vue new file mode 100644 index 0000000..9b14dfc --- /dev/null +++ b/admin-ui/src/layout/components/Sidebar/index.vue @@ -0,0 +1,54 @@ + + + diff --git a/admin-ui/src/layout/components/TagsView/ScrollPane.vue b/admin-ui/src/layout/components/TagsView/ScrollPane.vue new file mode 100644 index 0000000..516b5d2 --- /dev/null +++ b/admin-ui/src/layout/components/TagsView/ScrollPane.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/layout/components/TagsView/index.vue b/admin-ui/src/layout/components/TagsView/index.vue new file mode 100644 index 0000000..c1b7e3f --- /dev/null +++ b/admin-ui/src/layout/components/TagsView/index.vue @@ -0,0 +1,338 @@ + + + + + + + \ No newline at end of file diff --git a/admin-ui/src/layout/components/index.js b/admin-ui/src/layout/components/index.js new file mode 100644 index 0000000..fd57731 --- /dev/null +++ b/admin-ui/src/layout/components/index.js @@ -0,0 +1,4 @@ +export { default as AppMain } from './AppMain' +export { default as Navbar } from './Navbar' +export { default as Settings } from './Settings' +export { default as TagsView } from './TagsView/index.vue' diff --git a/admin-ui/src/layout/index.vue b/admin-ui/src/layout/index.vue new file mode 100644 index 0000000..3ddb165 --- /dev/null +++ b/admin-ui/src/layout/index.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/main.js b/admin-ui/src/main.js new file mode 100644 index 0000000..04b6801 --- /dev/null +++ b/admin-ui/src/main.js @@ -0,0 +1,84 @@ +import { createApp } from 'vue' + +import Cookies from 'js-cookie' + +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import locale from 'element-plus/es/locale/lang/zh-cn' + +import '@/assets/styles/index.scss' // global 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' + +// svg图标 +import 'virtual:svg-icons-register' +import SvgIcon from '@/components/SvgIcon' +import elementIcons from '@/components/SvgIcon/svgicon' + +import './permission' // permission control + +import { useDict } from '@/utils/dict' +import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } 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 TreeSelect from '@/components/TreeSelect' +// 字典标签组件 +import DictTag from '@/components/DictTag' + +const app = createApp(App) + +// 全局方法挂载 +app.config.globalProperties.useDict = useDict +app.config.globalProperties.download = download +app.config.globalProperties.parseTime = parseTime +app.config.globalProperties.resetForm = resetForm +app.config.globalProperties.handleTree = handleTree +app.config.globalProperties.addDateRange = addDateRange +app.config.globalProperties.selectDictLabel = selectDictLabel +app.config.globalProperties.selectDictLabels = selectDictLabels + +// 全局组件挂载 +app.component('DictTag', DictTag) +app.component('Pagination', Pagination) +app.component('TreeSelect', TreeSelect) +app.component('FileUpload', FileUpload) +app.component('ImageUpload', ImageUpload) +app.component('ImagePreview', ImagePreview) +app.component('RightToolbar', RightToolbar) +app.component('Editor', Editor) + +app.use(router) +app.use(store) +app.use(plugins) +app.use(elementIcons) +app.component('svg-icon', SvgIcon) + +directive(app) + +// 使用element-plus 并且设置全局的大小 +app.use(ElementPlus, { + locale: locale, + // 支持 large、default、small + size: Cookies.get('size') || 'default' +}) + +app.mount('#app') diff --git a/admin-ui/src/permission.js b/admin-ui/src/permission.js new file mode 100644 index 0000000..e7390f1 --- /dev/null +++ b/admin-ui/src/permission.js @@ -0,0 +1,79 @@ +import router from "./router"; +import { ElMessage } from "element-plus"; +import NProgress from "nprogress"; +import "nprogress/nprogress.css"; +import { getToken } from "@/utils/auth"; +import { isHttp } from "@/utils/validate"; +import { isRelogin } from "@/utils/request"; +import useUserStore from "@/store/modules/user"; +import useSettingsStore from "@/store/modules/settings"; +import usePermissionStore from "@/store/modules/permission"; + +NProgress.configure({ showSpinner: false }); + +const whiteList = ["/login", "/register"]; + +router.beforeEach((to, from, next) => { + NProgress.start(); + if (getToken()) { + to.meta.title && useSettingsStore().setTitle(to.meta.title); + /* has token*/ + if (to.path === "/login") { + next({ path: "/" }); + NProgress.done(); + } else if (whiteList.indexOf(to.path) !== -1) { + next(); + } else { + if (useUserStore().roles.length === 0) { + isRelogin.show = true; + // 判断当前用户是否已拉取完user_info信息 + useUserStore() + .getInfo() + .then(() => { + isRelogin.show = false; + usePermissionStore() + .generateRoutes() + .then((accessRoutes) => { + // 根据roles权限生成可访问的路由表 + accessRoutes.forEach((route) => { + if (!isHttp(route.path)) { + router.addRoute(route); // 动态添加可访问路由表 + } + }); + + if (to.meta.noCache) { + // 如果目标路由不需要缓存,强制重新加载 + const { path, query } = to; + window.location.href = `/${path}?${query}`; + } else { + next({ ...to, replace: true }); // hack方法 确保addRoutes已完成 + } + }); + }) + .catch((err) => { + useUserStore() + .logOut() + .then(() => { + ElMessage.error(err); + next({ path: "/" }); + }); + }); + } else { + next(); + } + } + } else { + // 没有token + if (whiteList.indexOf(to.path) !== -1) { + // 在免登录白名单,直接进入 + next(); + } else { + next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页 + NProgress.done(); + } + } +}); + +router.afterEach(() => { + NProgress.done(); +}); diff --git a/admin-ui/src/plugins/auth.js b/admin-ui/src/plugins/auth.js new file mode 100644 index 0000000..5e8c28d --- /dev/null +++ b/admin-ui/src/plugins/auth.js @@ -0,0 +1,60 @@ +import useUserStore from '@/store/modules/user' + +function authPermission(permission) { + const all_permission = "*:*:*"; + const permissions = useUserStore().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 = useUserStore().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/admin-ui/src/plugins/cache.js b/admin-ui/src/plugins/cache.js new file mode 100644 index 0000000..6b5c00b --- /dev/null +++ b/admin-ui/src/plugins/cache.js @@ -0,0 +1,77 @@ +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) + } + }, + 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) + } + }, + remove (key) { + localStorage.removeItem(key); + } +} + +export default { + /** + * 会话级缓存 + */ + session: sessionCache, + /** + * 本地缓存 + */ + local: localCache +} diff --git a/admin-ui/src/plugins/download.js b/admin-ui/src/plugins/download.js new file mode 100644 index 0000000..1a89efd --- /dev/null +++ b/admin-ui/src/plugins/download.js @@ -0,0 +1,79 @@ +import axios from 'axios' +import { ElLoading, ElMessage } from 'element-plus' +import { saveAs } from 'file-saver' +import { getToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { blobValidate } from '@/utils/ruoyi' + +const baseURL = import.meta.env.VITE_APP_BASE_API +let downloadLoadingInstance; + +export default { + name(name, isDelete = true) { + var url = baseURL + "/common/download?fileName=" + encodeURIComponent(name) + "&delete=" + isDelete + 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]) + this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) + } else { + this.printErrMsg(res.data); + } + }) + }, + resource(resource) { + var url = baseURL + "/common/download/resource?resource=" + encodeURIComponent(resource); + 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]) + this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) + } else { + this.printErrMsg(res.data); + } + }) + }, + zip(url, name) { + var url = baseURL + url + downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", 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) + ElMessage.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'] + ElMessage.error(errMsg); + } +} + diff --git a/admin-ui/src/plugins/index.js b/admin-ui/src/plugins/index.js new file mode 100644 index 0000000..47d1b41 --- /dev/null +++ b/admin-ui/src/plugins/index.js @@ -0,0 +1,18 @@ +import tab from './tab' +import auth from './auth' +import cache from './cache' +import modal from './modal' +import download from './download' + +export default function installPlugins(app){ + // 页签操作 + app.config.globalProperties.$tab = tab + // 认证对象 + app.config.globalProperties.$auth = auth + // 缓存对象 + app.config.globalProperties.$cache = cache + // 模态框对象 + app.config.globalProperties.$modal = modal + // 下载文件 + app.config.globalProperties.$download = download +} diff --git a/admin-ui/src/plugins/modal.js b/admin-ui/src/plugins/modal.js new file mode 100644 index 0000000..b59e14d --- /dev/null +++ b/admin-ui/src/plugins/modal.js @@ -0,0 +1,82 @@ +import { ElMessage, ElMessageBox, ElNotification, ElLoading } from 'element-plus' + +let loadingInstance; + +export default { + // 消息提示 + msg(content) { + ElMessage.info(content) + }, + // 错误消息 + msgError(content) { + ElMessage.error(content) + }, + // 成功消息 + msgSuccess(content) { + ElMessage.success(content) + }, + // 警告消息 + msgWarning(content) { + ElMessage.warning(content) + }, + // 弹出提示 + alert(content) { + ElMessageBox.alert(content, "系统提示") + }, + // 错误提示 + alertError(content) { + ElMessageBox.alert(content, "系统提示", { type: 'error' }) + }, + // 成功提示 + alertSuccess(content) { + ElMessageBox.alert(content, "系统提示", { type: 'success' }) + }, + // 警告提示 + alertWarning(content) { + ElMessageBox.alert(content, "系统提示", { type: 'warning' }) + }, + // 通知提示 + notify(content) { + ElNotification.info(content) + }, + // 错误通知 + notifyError(content) { + ElNotification.error(content); + }, + // 成功通知 + notifySuccess(content) { + ElNotification.success(content) + }, + // 警告通知 + notifyWarning(content) { + ElNotification.warning(content) + }, + // 确认窗体 + confirm(content) { + return ElMessageBox.confirm(content, "系统提示", { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: "warning", + }) + }, + // 提交内容 + prompt(content) { + return ElMessageBox.prompt(content, "系统提示", { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: "warning", + }) + }, + // 打开遮罩层 + loading(content) { + loadingInstance = ElLoading.service({ + lock: true, + text: content, + background: "rgba(0, 0, 0, 0.7)", + }) + }, + // 关闭遮罩层 + closeLoading() { + loadingInstance.close(); + } +} diff --git a/admin-ui/src/plugins/tab.js b/admin-ui/src/plugins/tab.js new file mode 100644 index 0000000..7b51cf5 --- /dev/null +++ b/admin-ui/src/plugins/tab.js @@ -0,0 +1,69 @@ +import useTagsViewStore from '@/store/modules/tagsView' +import router from '@/router' + +export default { + // 刷新当前tab页签 + refreshPage(obj) { + const { path, query, matched } = router.currentRoute.value; + 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 useTagsViewStore().delCachedView(obj).then(() => { + const { path, query } = obj + router.replace({ + path: '/redirect' + path, + query: query + }) + }) + }, + // 关闭当前tab页签,打开新页签 + closeOpenPage(obj) { + useTagsViewStore().delView(router.currentRoute.value); + if (obj !== undefined) { + return router.push(obj); + } + }, + // 关闭指定tab页签 + closePage(obj) { + if (obj === undefined) { + return useTagsViewStore().delView(router.currentRoute.value).then(({ visitedViews }) => { + const latestView = visitedViews.slice(-1)[0] + if (latestView) { + return router.push(latestView.fullPath) + } + return router.push('/'); + }); + } + return useTagsViewStore().delView(obj); + }, + // 关闭所有tab页签 + closeAllPage() { + return useTagsViewStore().delAllViews(); + }, + // 关闭左侧tab页签 + closeLeftPage(obj) { + return useTagsViewStore().delLeftTags(obj || router.currentRoute.value); + }, + // 关闭右侧tab页签 + closeRightPage(obj) { + return useTagsViewStore().delRightTags(obj || router.currentRoute.value); + }, + // 关闭其他tab页签 + closeOtherPage(obj) { + return useTagsViewStore().delOthersViews(obj || router.currentRoute.value); + }, + // 打开tab页签 + openPage(url) { + return router.push(url); + }, + // 修改tab页签 + updatePage(obj) { + return useTagsViewStore().updateVisitedView(obj); + } +} diff --git a/admin-ui/src/router/index.js b/admin-ui/src/router/index.js new file mode 100644 index 0000000..fda14cd --- /dev/null +++ b/admin-ui/src/router/index.js @@ -0,0 +1,134 @@ +import { createWebHashHistory, createRouter } from 'vue-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' // 设定路由的名字,一定要填写不然使用时会出现各种问题 + * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 + * roles: ['admin', 'common'] // 访问路由的角色权限 + * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 + * meta : { + noCache: true // 如果设置为true,则不会被 缓存(默认 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/index.vue') + } + ] + }, + { + path: '/login', + component: () => import('@/views/login'), + hidden: true + }, + { + path: '/register', + component: () => import('@/views/register'), + hidden: true + }, + { + path: "/:pathMatch(.*)*", + 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: '/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' } + } + ] + }, + +] + +const router = createRouter({ + history: createWebHashHistory(), + routes: constantRoutes, + scrollBehavior(to, from, savedPosition) { + if (savedPosition) { + return savedPosition + } else { + return { top: 0 } + } + }, +}); + +export default router; diff --git a/admin-ui/src/settings.js b/admin-ui/src/settings.js new file mode 100644 index 0000000..08a0108 --- /dev/null +++ b/admin-ui/src/settings.js @@ -0,0 +1,47 @@ +export default { + /** + * 网页标题 + */ + title: import.meta.env.VITE_APP_TITLE, + /** + * 侧边栏主题 深色主题theme-dark,浅色主题theme-light + */ + sideTheme: 'theme-dark', + /** + * 是否系统布局配置 + */ + showSettings: true, + + /** + * 是否显示顶部导航 + */ + topNav: false, + + /** + * 是否显示 tagsView + */ + tagsView: true, + + /** + * 是否固定头部 + */ + fixedHeader: false, + + /** + * 是否显示logo + */ + sidebarLogo: true, + + /** + * 是否显示动态标题 + */ + dynamicTitle: false, + + /** + * @type {string | array} 'production' | ['production', 'development'] + * @description Need show err logs component. + * The default is only used in the production env + * If you want to also use it in dev, you can pass ['production', 'development'] + */ + errorLog: 'production' +} diff --git a/admin-ui/src/store/index.js b/admin-ui/src/store/index.js new file mode 100644 index 0000000..f10f389 --- /dev/null +++ b/admin-ui/src/store/index.js @@ -0,0 +1,3 @@ +const store = createPinia() + +export default store \ No newline at end of file diff --git a/admin-ui/src/store/modules/app.js b/admin-ui/src/store/modules/app.js new file mode 100644 index 0000000..0b57159 --- /dev/null +++ b/admin-ui/src/store/modules/app.js @@ -0,0 +1,46 @@ +import Cookies from 'js-cookie' + +const useAppStore = defineStore( + 'app', + { + state: () => ({ + sidebar: { + opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, + withoutAnimation: false, + hide: false + }, + device: 'desktop', + size: Cookies.get('size') || 'default' + }), + actions: { + toggleSideBar(withoutAnimation) { + if (this.sidebar.hide) { + return false; + } + this.sidebar.opened = !this.sidebar.opened + this.sidebar.withoutAnimation = withoutAnimation + if (this.sidebar.opened) { + Cookies.set('sidebarStatus', 1) + } else { + Cookies.set('sidebarStatus', 0) + } + }, + closeSideBar({ withoutAnimation }) { + Cookies.set('sidebarStatus', 0) + this.sidebar.opened = false + this.sidebar.withoutAnimation = withoutAnimation + }, + toggleDevice(device) { + this.device = device + }, + setSize(size) { + this.size = size; + Cookies.set('size', size) + }, + toggleSideBarHide(status) { + this.sidebar.hide = status + } + } + }) + +export default useAppStore diff --git a/admin-ui/src/store/modules/dict.js b/admin-ui/src/store/modules/dict.js new file mode 100644 index 0000000..27fc308 --- /dev/null +++ b/admin-ui/src/store/modules/dict.js @@ -0,0 +1,57 @@ +const useDictStore = defineStore( + 'dict', + { + state: () => ({ + dict: new Array() + }), + actions: { + // 获取字典 + getDict(_key) { + if (_key == null && _key == "") { + return null; + } + try { + for (let i = 0; i < this.dict.length; i++) { + if (this.dict[i].key == _key) { + return this.dict[i].value; + } + } + } catch (e) { + return null; + } + }, + // 设置字典 + setDict(_key, value) { + if (_key !== null && _key !== "") { + this.dict.push({ + key: _key, + value: value + }); + } + }, + // 删除字典 + removeDict(_key) { + var bln = false; + try { + for (let i = 0; i < this.dict.length; i++) { + if (this.dict[i].key == _key) { + this.dict.splice(i, 1); + return true; + } + } + } catch (e) { + bln = false; + } + return bln; + }, + // 清空字典 + cleanDict() { + this.dict = new Array(); + }, + // 初始字典 + initDict() { + } + } + }) + +export default useDictStore diff --git a/admin-ui/src/store/modules/permission.js b/admin-ui/src/store/modules/permission.js new file mode 100644 index 0000000..958fe63 --- /dev/null +++ b/admin-ui/src/store/modules/permission.js @@ -0,0 +1,142 @@ +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' + +// 匹配views里面所有的.vue文件 +const modules = import.meta.glob('./../../views/**/*.vue') + +const usePermissionStore = defineStore( + 'permission', + { + state: () => ({ + routes: [], + addRoutes: [], + defaultRoutes: [], + topbarRouters: [], + sidebarRouters: [] + }), + actions: { + setRoutes(routes) { + this.addRoutes = routes + this.routes = constantRoutes.concat(routes) + }, + setDefaultRoutes(routes) { + this.defaultRoutes = constantRoutes.concat(routes) + }, + setTopbarRoutes(routes) { + this.topbarRouters = routes + }, + setSidebarRouters(routes) { + this.sidebarRouters = routes + }, + generateRoutes(roles) { + return new Promise(resolve => { + // 向后端请求路由数据 + getRouters().then(res => { + const sdata = JSON.parse(JSON.stringify(res.data)) + const rdata = JSON.parse(JSON.stringify(res.data)) + const defaultData = JSON.parse(JSON.stringify(res.data)) + const sidebarRoutes = filterAsyncRouter(sdata) + const rewriteRoutes = filterAsyncRouter(rdata, false, true) + const defaultRoutes = filterAsyncRouter(defaultData) + const asyncRoutes = filterDynamicRoutes(dynamicRoutes) + asyncRoutes.forEach(route => { router.addRoute(route) }) + this.setRoutes(rewriteRoutes) + this.setSidebarRouters(constantRoutes.concat(sidebarRoutes)) + this.setDefaultRoutes(sidebarRoutes) + this.setTopbarRoutes(defaultRoutes) + 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, index) => { + if (el.children && el.children.length) { + if (el.component === 'ParentView' && !lastRouter) { + el.children.forEach(c => { + c.path = el.path + '/' + c.path + if (c.children && c.children.length) { + children = children.concat(filterChildren(c.children, c)) + return + } + children.push(c) + }) + return + } + } + if (lastRouter) { + el.path = lastRouter.path + '/' + el.path + if (el.children && el.children.length) { + children = children.concat(filterChildren(el.children, el)) + return + } + } + children = children.concat(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) => { + let res; + for (const path in modules) { + const dir = path.split('views/')[1].split('.vue')[0]; + if (dir === view) { + res = () => modules[path](); + } + } + return res; +} + +export default usePermissionStore diff --git a/admin-ui/src/store/modules/settings.js b/admin-ui/src/store/modules/settings.js new file mode 100644 index 0000000..22b7336 --- /dev/null +++ b/admin-ui/src/store/modules/settings.js @@ -0,0 +1,38 @@ +import defaultSettings from '@/settings' +import { useDynamicTitle } from '@/utils/dynamicTitle' + +const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings + +const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' + +const useSettingsStore = defineStore( + 'settings', + { + state: () => ({ + title: '', + theme: storageSetting.theme || '#409EFF', + sideTheme: storageSetting.sideTheme || sideTheme, + showSettings: showSettings, + topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, + tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, + fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, + sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, + dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle + }), + actions: { + // 修改布局设置 + changeSetting(data) { + const { key, value } = data + if (this.hasOwnProperty(key)) { + this[key] = value + } + }, + // 设置网页标题 + setTitle(title) { + this.title = title + useDynamicTitle(); + } + } + }) + +export default useSettingsStore diff --git a/admin-ui/src/store/modules/tagsView.js b/admin-ui/src/store/modules/tagsView.js new file mode 100644 index 0000000..9d07f33 --- /dev/null +++ b/admin-ui/src/store/modules/tagsView.js @@ -0,0 +1,182 @@ +const useTagsViewStore = defineStore( + 'tags-view', + { + state: () => ({ + visitedViews: [], + cachedViews: [], + iframeViews: [] + }), + actions: { + addView(view) { + this.addVisitedView(view) + this.addCachedView(view) + }, + addIframeView(view) { + if (this.iframeViews.some(v => v.path === view.path)) return + this.iframeViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + }, + addVisitedView(view) { + if (this.visitedViews.some(v => v.path === view.path)) return + this.visitedViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + }, + addCachedView(view) { + if (this.cachedViews.includes(view.name)) return + if (!view.meta.noCache) { + this.cachedViews.push(view.name) + } + }, + delView(view) { + return new Promise(resolve => { + this.delVisitedView(view) + this.delCachedView(view) + resolve({ + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] + }) + }) + }, + delVisitedView(view) { + return new Promise(resolve => { + for (const [i, v] of this.visitedViews.entries()) { + if (v.path === view.path) { + this.visitedViews.splice(i, 1) + break + } + } + this.iframeViews = this.iframeViews.filter(item => item.path !== view.path) + resolve([...this.visitedViews]) + }) + }, + delIframeView(view) { + return new Promise(resolve => { + this.iframeViews = this.iframeViews.filter(item => item.path !== view.path) + resolve([...this.iframeViews]) + }) + }, + delCachedView(view) { + return new Promise(resolve => { + const index = this.cachedViews.indexOf(view.name) + index > -1 && this.cachedViews.splice(index, 1) + resolve([...this.cachedViews]) + }) + }, + delOthersViews(view) { + return new Promise(resolve => { + this.delOthersVisitedViews(view) + this.delOthersCachedViews(view) + resolve({ + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] + }) + }) + }, + delOthersVisitedViews(view) { + return new Promise(resolve => { + this.visitedViews = this.visitedViews.filter(v => { + return v.meta.affix || v.path === view.path + }) + this.iframeViews = this.iframeViews.filter(item => item.path === view.path) + resolve([...this.visitedViews]) + }) + }, + delOthersCachedViews(view) { + return new Promise(resolve => { + const index = this.cachedViews.indexOf(view.name) + if (index > -1) { + this.cachedViews = this.cachedViews.slice(index, index + 1) + } else { + this.cachedViews = [] + } + resolve([...this.cachedViews]) + }) + }, + delAllViews(view) { + return new Promise(resolve => { + this.delAllVisitedViews(view) + this.delAllCachedViews(view) + resolve({ + visitedViews: [...this.visitedViews], + cachedViews: [...this.cachedViews] + }) + }) + }, + delAllVisitedViews(view) { + return new Promise(resolve => { + const affixTags = this.visitedViews.filter(tag => tag.meta.affix) + this.visitedViews = affixTags + this.iframeViews = [] + resolve([...this.visitedViews]) + }) + }, + delAllCachedViews(view) { + return new Promise(resolve => { + this.cachedViews = [] + resolve([...this.cachedViews]) + }) + }, + updateVisitedView(view) { + for (let v of this.visitedViews) { + if (v.path === view.path) { + v = Object.assign(v, view) + break + } + } + }, + delRightTags(view) { + return new Promise(resolve => { + const index = this.visitedViews.findIndex(v => v.path === view.path) + if (index === -1) { + return + } + this.visitedViews = this.visitedViews.filter((item, idx) => { + if (idx <= index || (item.meta && item.meta.affix)) { + return true + } + const i = this.cachedViews.indexOf(item.name) + if (i > -1) { + this.cachedViews.splice(i, 1) + } + if(item.meta.link) { + const fi = this.iframeViews.findIndex(v => v.path === item.path) + this.iframeViews.splice(fi, 1) + } + return false + }) + resolve([...this.visitedViews]) + }) + }, + delLeftTags(view) { + return new Promise(resolve => { + const index = this.visitedViews.findIndex(v => v.path === view.path) + if (index === -1) { + return + } + this.visitedViews = this.visitedViews.filter((item, idx) => { + if (idx >= index || (item.meta && item.meta.affix)) { + return true + } + const i = this.cachedViews.indexOf(item.name) + if (i > -1) { + this.cachedViews.splice(i, 1) + } + if(item.meta.link) { + const fi = this.iframeViews.findIndex(v => v.path === item.path) + this.iframeViews.splice(fi, 1) + } + return false + }) + resolve([...this.visitedViews]) + }) + } + } + }) + +export default useTagsViewStore diff --git a/admin-ui/src/store/modules/user.js b/admin-ui/src/store/modules/user.js new file mode 100644 index 0000000..5c26f4e --- /dev/null +++ b/admin-ui/src/store/modules/user.js @@ -0,0 +1,72 @@ +import { login, logout, getInfo } from '@/api/login' +import { getToken, setToken, removeToken } from '@/utils/auth' +import defAva from '@/assets/images/profile.jpg' + +const useUserStore = defineStore( + 'user', + { + state: () => ({ + token: getToken(), + id: '', + name: '', + avatar: '', + roles: [], + permissions: [] + }), + actions: { + // 登录 + login(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 => { + setToken(res.data) + this.token = res.data + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + // 获取用户信息 + getInfo() { + return new Promise((resolve, reject) => { + getInfo().then(res => { + const user = res.data.user + const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar; + + if (res.data.roles && res.data.roles.length > 0) { // 验证返回的roles是否是一个非空数组 + this.roles = res.data.roles + this.permissions = res.data.permissions + } else { + this.roles = ['ROLE_DEFAULT'] + } + this.id = user.userId + this.name = user.userName + this.avatar = avatar + resolve(res) + }).catch(error => { + reject(error) + }) + }) + }, + // 退出系统 + logOut() { + return new Promise((resolve, reject) => { + logout(this.token).then(() => { + this.token = '' + this.roles = [] + this.permissions = [] + removeToken() + resolve() + }).catch(error => { + reject(error) + }) + }) + } + } + }) + +export default useUserStore diff --git a/admin-ui/src/utils/auth.js b/admin-ui/src/utils/auth.js new file mode 100644 index 0000000..08a43d6 --- /dev/null +++ b/admin-ui/src/utils/auth.js @@ -0,0 +1,15 @@ +import Cookies from 'js-cookie' + +const TokenKey = 'Admin-Token' + +export function getToken() { + return Cookies.get(TokenKey) +} + +export function setToken(token) { + return Cookies.set(TokenKey, token) +} + +export function removeToken() { + return Cookies.remove(TokenKey) +} diff --git a/admin-ui/src/utils/dict.js b/admin-ui/src/utils/dict.js new file mode 100644 index 0000000..9648f14 --- /dev/null +++ b/admin-ui/src/utils/dict.js @@ -0,0 +1,24 @@ +import useDictStore from '@/store/modules/dict' +import { getDicts } from '@/api/system/dict/data' + +/** + * 获取字典数据 + */ +export function useDict(...args) { + const res = ref({}); + return (() => { + args.forEach((dictType, index) => { + res.value[dictType] = []; + const dicts = useDictStore().getDict(dictType); + if (dicts) { + res.value[dictType] = dicts; + } else { + getDicts(dictType).then(resp => { + res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })) + useDictStore().setDict(dictType, res.value[dictType]); + }) + } + }) + return toRefs(res.value); + })() +} \ No newline at end of file diff --git a/admin-ui/src/utils/dynamicTitle.js b/admin-ui/src/utils/dynamicTitle.js new file mode 100644 index 0000000..64404b2 --- /dev/null +++ b/admin-ui/src/utils/dynamicTitle.js @@ -0,0 +1,15 @@ +import store from '@/store' +import defaultSettings from '@/settings' +import useSettingsStore from '@/store/modules/settings' + +/** + * 动态修改标题 + */ +export function useDynamicTitle() { + const settingsStore = useSettingsStore(); + if (settingsStore.dynamicTitle) { + document.title = settingsStore.title + ' - ' + defaultSettings.title; + } else { + document.title = defaultSettings.title; + } +} \ No newline at end of file diff --git a/admin-ui/src/utils/errorCode.js b/admin-ui/src/utils/errorCode.js new file mode 100644 index 0000000..d2111ee --- /dev/null +++ b/admin-ui/src/utils/errorCode.js @@ -0,0 +1,6 @@ +export default { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + 'default': '系统未知错误,请反馈给管理员' +} diff --git a/admin-ui/src/utils/index.js b/admin-ui/src/utils/index.js new file mode 100644 index 0000000..4e65504 --- /dev/null +++ b/admin-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/admin-ui/src/utils/jsencrypt.js b/admin-ui/src/utils/jsencrypt.js new file mode 100644 index 0000000..78d9523 --- /dev/null +++ b/admin-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/admin-ui/src/utils/permission.js b/admin-ui/src/utils/permission.js new file mode 100644 index 0000000..93fee87 --- /dev/null +++ b/admin-ui/src/utils/permission.js @@ -0,0 +1,51 @@ +import useUserStore from '@/store/modules/user' + +/** + * 字符权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkPermi(value) { + if (value && value instanceof Array && value.length > 0) { + const permissions = useUserStore().permissions + const permissionDatas = value + const all_permission = "*:*:*"; + + const hasPermission = permissions.some(permission => { + return all_permission === permission || permissionDatas.includes(permission) + }) + + if (!hasPermission) { + return false + } + return true + } 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 = useUserStore().roles + const permissionRoles = value + const super_admin = "admin"; + + const hasRole = roles.some(role => { + return super_admin === role || permissionRoles.includes(role) + }) + + if (!hasRole) { + return false + } + return true + } else { + console.error(`need roles! Like checkRole="['admin','editor']"`) + return false + } +} \ No newline at end of file diff --git a/admin-ui/src/utils/request.js b/admin-ui/src/utils/request.js new file mode 100644 index 0000000..3bdd541 --- /dev/null +++ b/admin-ui/src/utils/request.js @@ -0,0 +1,152 @@ +import axios from 'axios' +import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus' +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' +import useUserStore from '@/store/modules/user' +import router from '@/router' + +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: import.meta.env.VITE_APP_BASE_API, + // 超时 + timeout: 10000 +}) + +// request拦截器 +service.interceptors.request.use(config => { + + // 是否需要防止数据重复提交 + const isRepeatSubmit = (config.headers || {}).repeatSubmit === false + if (getToken()) { + config.headers['Authorization'] = 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; // 请求时间 + const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交 + 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; + ElMessageBox.confirm('登录状态已过期!', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { + isRelogin.show = false; + useUserStore().logOut().then(() => { + router.push({path:"/login"}); + }) + }).catch(() => { + isRelogin.show = false; + }); + } + return Promise.reject('登陆已过期,请重新登录') + } else if (code === 500) { + ElMessage({ message: msg, type: 'error' }) + return Promise.reject(new Error(msg)) + } else if (code === 601) { + ElMessage({ message: msg, type: 'warning' }) + return Promise.reject(new Error(msg)) + } else if (code !== 200) { + ElNotification.error({ title: msg }) + return Promise.reject('error') + } else { + return Promise.resolve(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.substr(message.length - 3) + "异常"; + } + ElMessage({ message: message, type: 'error', duration: 5 * 1000 }) + return Promise.reject(error) + } +) + +// 通用下载方法 +export function download(url, params, filename, config) { + downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", 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'] + ElMessage.error(errMsg); + } + downloadLoadingInstance.close(); + }).catch((r) => { + console.error(r) + ElMessage.error('下载文件出现错误,请联系管理员!') + downloadLoadingInstance.close(); + }) +} + +export default service diff --git a/admin-ui/src/utils/ruoyi.js b/admin-ui/src/utils/ruoyi.js new file mode 100644 index 0000000..4efca08 --- /dev/null +++ b/admin-ui/src/utils/ruoyi.js @@ -0,0 +1,246 @@ + + +/** + * 通用js方法封装处理 + * Copyright (c) 2019 ruoyi + */ + +// 日期格式化 +export function parseTime(time, pattern) { + if (arguments.length === 0 || !time) { + return null + } + const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } else if (typeof time === 'string') { + time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), ''); + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} + +// 表单重置 +export function resetForm(refName) { + if (this.$refs[refName]) { + this.$refs[refName].resetFields(); + } +} + +// 添加日期范围 +export function addDateRange(params, dateRange, propName) { + let search = params; + search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}; + dateRange = Array.isArray(dateRange) ? dateRange : []; + if (typeof (propName) === 'undefined') { + search.params['beginTime'] = dateRange[0]; + search.params['endTime'] = dateRange[1]; + } else { + search.params['begin' + propName] = dateRange[0]; + search.params['end' + propName] = dateRange[1]; + } + return search; +} + +// 回显数据字典 +export function selectDictLabel(datas, value) { + if (value === undefined) { + return ""; + } + var actions = []; + Object.keys(datas).some((key) => { + if (datas[key].value == ('' + value)) { + actions.push(datas[key].label); + return true; + } + }) + if (actions.length === 0) { + actions.push(value); + } + return actions.join(''); +} + +// 回显数据字典(字符串数组) +export function selectDictLabels(datas, value, separator) { + if (value === undefined || value.length ===0) { + return ""; + } + if (Array.isArray(value)) { + value = value.join(","); + } + var actions = []; + var currentSeparator = undefined === separator ? "," : separator; + var temp = value.split(currentSeparator); + Object.keys(value.split(currentSeparator)).some((val) => { + var match = false; + Object.keys(datas).some((key) => { + if (datas[key].value == ('' + temp[val])) { + actions.push(datas[key].label + currentSeparator); + match = true; + } + }) + if (!match) { + actions.push(temp[val] + currentSeparator); + } + }) + return actions.join('').substring(0, actions.join('').length - 1); +} + +// 字符串格式化(%s ) +export function sprintf(str) { + var args = arguments, flag = true, i = 1; + str = str.replace(/%s/g, function () { + var arg = args[i++]; + if (typeof arg === 'undefined') { + flag = false; + return ''; + } + return arg; + }); + return flag ? str : ''; +} + +// 转换字符串,undefined,null等转化为"" +export function parseStrEmpty(str) { + if (!str || str == "undefined" || str == "null") { + return ""; + } + return str; +} + +// 数据合并 +export function mergeRecursive(source, target) { + for (var p in target) { + try { + if (target[p].constructor == Object) { + source[p] = mergeRecursive(source[p], target[p]); + } else { + source[p] = target[p]; + } + } catch (e) { + source[p] = target[p]; + } + } + return source; +}; + +/** + * 构造树型结构数据 + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + */ +export function handleTree(data, id, parentId, children) { + let config = { + id: id || 'id', + parentId: parentId || 'parentId', + childrenList: children || 'children' + }; + + var childrenListMap = {}; + var nodeIds = {}; + var tree = []; + + for (let d of data) { + let parentId = d[config.parentId]; + if (childrenListMap[parentId] == null) { + childrenListMap[parentId] = []; + } + nodeIds[d[config.id]] = d; + childrenListMap[parentId].push(d); + } + + for (let d of data) { + let parentId = d[config.parentId]; + if (nodeIds[parentId] == null) { + tree.push(d); + } + } + + for (let t of tree) { + adaptToChildrenList(t); + } + + function adaptToChildrenList(o) { + if (childrenListMap[o[config.id]] !== null) { + o[config.childrenList] = childrenListMap[o[config.id]]; + } + if (o[config.childrenList]) { + for (let c of o[config.childrenList]) { + adaptToChildrenList(c); + } + } + } + return tree; +} + +/** +* 参数处理 +* @param {*} params 参数 +*/ +export function tansParams(params) { + let result = '' + for (const propName of Object.keys(params)) { + const value = params[propName]; + var part = encodeURIComponent(propName) + "="; + if (value !== null && value !== "" && typeof (value) !== "undefined") { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { + let params = propName + '[' + key + ']'; + var subPart = encodeURIComponent(params) + "="; + result += subPart + encodeURIComponent(value[key]) + "&"; + } + } + } else { + result += part + encodeURIComponent(value) + "&"; + } + } + } + return result +} + + +// 返回项目路径 +export function getNormalPath(p) { + if (p.length === 0 || !p || p == 'undefined') { + return p + }; + let res = p.replace('//', '/') + if (res[res.length - 1] === '/') { + return res.slice(0, res.length - 1) + } + return res; +} + +// 验证是否为blob格式 +export function blobValidate(data) { + return data.type !== 'application/json' +} diff --git a/admin-ui/src/utils/scroll-to.js b/admin-ui/src/utils/scroll-to.js new file mode 100644 index 0000000..c5d8e04 --- /dev/null +++ b/admin-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/admin-ui/src/utils/theme.js b/admin-ui/src/utils/theme.js new file mode 100644 index 0000000..f4badc6 --- /dev/null +++ b/admin-ui/src/utils/theme.js @@ -0,0 +1,49 @@ +// 处理主题样式 +export function handleThemeStyle(theme) { + document.documentElement.style.setProperty('--el-color-primary', theme) + for (let i = 1; i <= 9; i++) { + document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`) + } + for (let i = 1; i <= 9; i++) { + document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`) + } +} + +// hex颜色转rgb颜色 +export function hexToRgb(str) { + str = str.replace('#', '') + let hexs = str.match(/../g) + for (let i = 0; i < 3; i++) { + hexs[i] = parseInt(hexs[i], 16) + } + return hexs +} + +// rgb颜色转Hex颜色 +export function rgbToHex(r, g, b) { + let hexs = [r.toString(16), g.toString(16), b.toString(16)] + for (let i = 0; i < 3; i++) { + if (hexs[i].length == 1) { + hexs[i] = `0${hexs[i]}` + } + } + return `#${hexs.join('')}` +} + +// 变浅颜色值 +export function getLightColor(color, level) { + let rgb = hexToRgb(color) + for (let i = 0; i < 3; i++) { + rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]) + } + return rgbToHex(rgb[0], rgb[1], rgb[2]) +} + +// 变深颜色值 +export function getDarkColor(color, level) { + let rgb = hexToRgb(color) + for (let i = 0; i < 3; i++) { + rgb[i] = Math.floor(rgb[i] * (1 - level)) + } + return rgbToHex(rgb[0], rgb[1], rgb[2]) +} diff --git a/admin-ui/src/utils/validate.js b/admin-ui/src/utils/validate.js new file mode 100644 index 0000000..702add4 --- /dev/null +++ b/admin-ui/src/utils/validate.js @@ -0,0 +1,93 @@ +/** + * 判断url是否是http或https + * @param {string} path + * @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) { + if (typeof str === 'string' || str instanceof String) { + return true + } + return false +} + +/** + * @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/admin-ui/src/views/error/401.vue b/admin-ui/src/views/error/401.vue new file mode 100644 index 0000000..1ba3792 --- /dev/null +++ b/admin-ui/src/views/error/401.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/admin-ui/src/views/error/404.vue b/admin-ui/src/views/error/404.vue new file mode 100644 index 0000000..f205303 --- /dev/null +++ b/admin-ui/src/views/error/404.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/admin-ui/src/views/index.vue b/admin-ui/src/views/index.vue new file mode 100644 index 0000000..a98948c --- /dev/null +++ b/admin-ui/src/views/index.vue @@ -0,0 +1,23 @@ + + + + + + diff --git a/admin-ui/src/views/login.vue b/admin-ui/src/views/login.vue new file mode 100644 index 0000000..df9fc9c --- /dev/null +++ b/admin-ui/src/views/login.vue @@ -0,0 +1,228 @@ + + + + + diff --git a/admin-ui/src/views/redirect/index.vue b/admin-ui/src/views/redirect/index.vue new file mode 100644 index 0000000..a469960 --- /dev/null +++ b/admin-ui/src/views/redirect/index.vue @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/admin-ui/src/views/register.vue b/admin-ui/src/views/register.vue new file mode 100644 index 0000000..d9e3bc2 --- /dev/null +++ b/admin-ui/src/views/register.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/admin-ui/src/views/system/dept/index.vue b/admin-ui/src/views/system/dept/index.vue new file mode 100644 index 0000000..eb101e7 --- /dev/null +++ b/admin-ui/src/views/system/dept/index.vue @@ -0,0 +1,381 @@ + + + diff --git a/admin-ui/src/views/system/menu/index.vue b/admin-ui/src/views/system/menu/index.vue new file mode 100644 index 0000000..2eff120 --- /dev/null +++ b/admin-ui/src/views/system/menu/index.vue @@ -0,0 +1,462 @@ + + + diff --git a/admin-ui/src/views/system/role/authUser.vue b/admin-ui/src/views/system/role/authUser.vue new file mode 100644 index 0000000..98337d7 --- /dev/null +++ b/admin-ui/src/views/system/role/authUser.vue @@ -0,0 +1,171 @@ + + + + diff --git a/admin-ui/src/views/system/role/index.vue b/admin-ui/src/views/system/role/index.vue new file mode 100644 index 0000000..83ad99e --- /dev/null +++ b/admin-ui/src/views/system/role/index.vue @@ -0,0 +1,630 @@ + + + diff --git a/admin-ui/src/views/system/role/selectUser.vue b/admin-ui/src/views/system/role/selectUser.vue new file mode 100644 index 0000000..d77aefe --- /dev/null +++ b/admin-ui/src/views/system/role/selectUser.vue @@ -0,0 +1,138 @@ + + + diff --git a/admin-ui/src/views/system/user/authRole.vue b/admin-ui/src/views/system/user/authRole.vue new file mode 100644 index 0000000..8188ecb --- /dev/null +++ b/admin-ui/src/views/system/user/authRole.vue @@ -0,0 +1,112 @@ + + + diff --git a/admin-ui/src/views/system/user/index.vue b/admin-ui/src/views/system/user/index.vue new file mode 100644 index 0000000..25f6018 --- /dev/null +++ b/admin-ui/src/views/system/user/index.vue @@ -0,0 +1,482 @@ + + + diff --git a/admin-ui/src/views/system/user/profile/index.vue b/admin-ui/src/views/system/user/profile/index.vue new file mode 100644 index 0000000..6c03ff7 --- /dev/null +++ b/admin-ui/src/views/system/user/profile/index.vue @@ -0,0 +1,80 @@ + + + diff --git a/admin-ui/src/views/system/user/profile/resetPwd.vue b/admin-ui/src/views/system/user/profile/resetPwd.vue new file mode 100644 index 0000000..dec2d79 --- /dev/null +++ b/admin-ui/src/views/system/user/profile/resetPwd.vue @@ -0,0 +1,57 @@ + + + diff --git a/admin-ui/src/views/system/user/profile/userAvatar.vue b/admin-ui/src/views/system/user/profile/userAvatar.vue new file mode 100644 index 0000000..3b39636 --- /dev/null +++ b/admin-ui/src/views/system/user/profile/userAvatar.vue @@ -0,0 +1,171 @@ + + + + + \ No newline at end of file diff --git a/admin-ui/src/views/system/user/profile/userInfo.vue b/admin-ui/src/views/system/user/profile/userInfo.vue new file mode 100644 index 0000000..47cd36c --- /dev/null +++ b/admin-ui/src/views/system/user/profile/userInfo.vue @@ -0,0 +1,62 @@ + + + diff --git a/admin-ui/vite.config.js b/admin-ui/vite.config.js new file mode 100644 index 0000000..3c75f68 --- /dev/null +++ b/admin-ui/vite.config.js @@ -0,0 +1,64 @@ +import { defineConfig, loadEnv } from 'vite' +import path from 'path' +import createVitePlugins from './vite/plugins' + +// https://vitejs.dev/config/ +export default defineConfig(({ mode, command }) => { + const env = loadEnv(mode, process.cwd()) + const { VITE_APP_ENV } = env + return { + // 部署生产环境和开发环境下的URL。 + // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上 + // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 + base: VITE_APP_ENV === 'production' ? '/' : '/', + plugins: createVitePlugins(env, command === 'build'), + resolve: { + // https://cn.vitejs.dev/config/#resolve-alias + alias: { + // 设置路径 + '~': path.resolve(__dirname, './'), + // 设置别名 + '@': path.resolve(__dirname, './src') + }, + // https://cn.vitejs.dev/config/#resolve-extensions + extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] + }, + // vite 相关配置 + server: { + port: 80, + host: true, + open: true, + proxy: { + '/dev-api': { + // target: 'https://vue.ruoyi.vip/prod-api/', + target: 'http://124.71.212.219:8090/api', + changeOrigin: true, + rewrite: (p) => p.replace(/^\/dev-api/, ''), + bypass(req, res, options) { + const proxyURL = options.target + options.rewrite(req.url); + console.log('proxyURL', proxyURL); + req.headers['x-req-proxyURL'] = proxyURL; // 设置未生效 + res.setHeader('x-req-proxyURL', proxyURL); // 设置响应头可以看到 + }, + } + } + }, + //fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file + css: { + postcss: { + plugins: [ + { + postcssPlugin: 'internal:charset-removal', + AtRule: { + charset: (atRule) => { + if (atRule.name === 'charset') { + atRule.remove(); + } + } + } + } + ] + } + } + } +}) diff --git a/admin-ui/vite/plugins/auto-import.js b/admin-ui/vite/plugins/auto-import.js new file mode 100644 index 0000000..a5d3576 --- /dev/null +++ b/admin-ui/vite/plugins/auto-import.js @@ -0,0 +1,12 @@ +import autoImport from 'unplugin-auto-import/vite' + +export default function createAutoImport() { + return autoImport({ + imports: [ + 'vue', + 'vue-router', + 'pinia' + ], + dts: false + }) +} diff --git a/admin-ui/vite/plugins/compression.js b/admin-ui/vite/plugins/compression.js new file mode 100644 index 0000000..e90aaec --- /dev/null +++ b/admin-ui/vite/plugins/compression.js @@ -0,0 +1,28 @@ +import compression from 'vite-plugin-compression' + +export default function createCompression(env) { + const { VITE_BUILD_COMPRESS } = env + const plugin = [] + if (VITE_BUILD_COMPRESS) { + const compressList = VITE_BUILD_COMPRESS.split(',') + if (compressList.includes('gzip')) { + // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 + plugin.push( + compression({ + ext: '.gz', + deleteOriginFile: false + }) + ) + } + if (compressList.includes('brotli')) { + plugin.push( + compression({ + ext: '.br', + algorithm: 'brotliCompress', + deleteOriginFile: false + }) + ) + } + } + return plugin +} diff --git a/admin-ui/vite/plugins/index.js b/admin-ui/vite/plugins/index.js new file mode 100644 index 0000000..10e17c3 --- /dev/null +++ b/admin-ui/vite/plugins/index.js @@ -0,0 +1,15 @@ +import vue from '@vitejs/plugin-vue' + +import createAutoImport from './auto-import' +import createSvgIcon from './svg-icon' +import createCompression from './compression' +import createSetupExtend from './setup-extend' + +export default function createVitePlugins(viteEnv, isBuild = false) { + const vitePlugins = [vue()] + vitePlugins.push(createAutoImport()) + vitePlugins.push(createSetupExtend()) + vitePlugins.push(createSvgIcon(isBuild)) + isBuild && vitePlugins.push(...createCompression(viteEnv)) + return vitePlugins +} diff --git a/admin-ui/vite/plugins/setup-extend.js b/admin-ui/vite/plugins/setup-extend.js new file mode 100644 index 0000000..ed8342e --- /dev/null +++ b/admin-ui/vite/plugins/setup-extend.js @@ -0,0 +1,5 @@ +import setupExtend from 'unplugin-vue-setup-extend-plus/vite' + +export default function createSetupExtend() { + return setupExtend({}) +} diff --git a/admin-ui/vite/plugins/svg-icon.js b/admin-ui/vite/plugins/svg-icon.js new file mode 100644 index 0000000..30a4140 --- /dev/null +++ b/admin-ui/vite/plugins/svg-icon.js @@ -0,0 +1,10 @@ +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' +import path from 'path' + +export default function createSvgIcon(isBuild) { + return createSvgIconsPlugin({ + iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')], + symbolId: 'icon-[dir]-[name]', + svgoOptions: isBuild + }) +}