From 488206779f4c29afb5a26a7952a2228cf33f1be9 Mon Sep 17 00:00:00 2001
From: alex_q <914269@qq.com>
Date: Fri, 12 Jun 2026 17:24:25 +0800
Subject: [PATCH] Initial commit
---
.editorconfig | 15 +
.env.development | 17 +
.env.production | 8 +
.eslintrc-auto-import.json | 316 +++
.gitignore | 20 +
.husky/commit-msg | 1 +
.husky/pre-commit | 1 +
.prettierignore | 12 +
.prettierrc.yaml | 41 +
.stylelintignore | 11 +
.stylelintrc.cjs | 38 +
.vscode/extensions.json | 11 +
.vscode/settings.json | 81 +
.vscode/vue3.0.code-snippets | 23 +
.vscode/vue3.2.code-snippets | 17 +
.vscode/vue3.3.code-snippets | 21 +
CHANGELOG.md | 386 +++
README.en-US.md | 222 ++
README.md | 221 ++
commitlint.config.cjs | 93 +
eslint.config.ts | 176 ++
index.html | 90 +
mock/auth.mock.ts | 44 +
mock/base.ts | 7 +
mock/dept.mock.ts | 153 ++
mock/dict.mock.ts | 312 +++
mock/log.mock.ts | 207 ++
mock/menu.mock.ts | 2082 +++++++++++++++++
mock/notice.mock.ts | 416 ++++
mock/role.mock.ts | 334 +++
mock/user.mock.ts | 251 ++
package.json | 128 +
public/favicon.ico | Bin 0 -> 3439 bytes
.../710b7a81cbe748f28bfa10c44382fd67.jpg | Bin 0 -> 20291 bytes
.../332f8fa543dc4f7f8262e05aae95a110.jpg | Bin 0 -> 19961 bytes
.../4d806fda9d0f48c289028aef9c7e7e57.jpg | Bin 0 -> 20291 bytes
.../de041f1795904b6c8a4e97ffb3072fb4.jpg | Bin 0 -> 19961 bytes
public/files/default.gif | Bin 0 -> 6334 bytes
src/App.vue | 32 +
src/api/auth.api.ts | 86 +
src/api/codegen.api.ts | 191 ++
src/api/file.api.ts | 83 +
src/api/rnb/index.ts | 254 ++
src/api/system/config.api.ts | 95 +
src/api/system/dept.api.ts | 130 +
src/api/system/dict.api.ts | 310 +++
src/api/system/log.api.ts | 121 +
src/api/system/menu.api.ts | 209 ++
src/api/system/notice.api.ts | 199 ++
src/api/system/role.api.ts | 138 ++
src/api/system/user.api.ts | 384 +++
src/assets/icons/api.svg | 1 +
src/assets/icons/backtop.svg | 1 +
src/assets/icons/bilibili.svg | 1 +
src/assets/icons/browser.svg | 1 +
src/assets/icons/captcha.svg | 1 +
src/assets/icons/cascader.svg | 1 +
src/assets/icons/client.svg | 1 +
src/assets/icons/close.svg | 1 +
src/assets/icons/close_all.svg | 1 +
src/assets/icons/close_left.svg | 1 +
src/assets/icons/close_other.svg | 1 +
src/assets/icons/close_right.svg | 1 +
src/assets/icons/cnblogs.svg | 1 +
src/assets/icons/code.svg | 1 +
src/assets/icons/collapse.svg | 1 +
src/assets/icons/csdn.svg | 6 +
src/assets/icons/dict.svg | 1 +
src/assets/icons/document.svg | 1 +
src/assets/icons/down.svg | 1 +
src/assets/icons/download.svg | 1 +
src/assets/icons/enter.svg | 1 +
src/assets/icons/esc.svg | 1 +
src/assets/icons/file.svg | 1 +
src/assets/icons/fullscreen-exit.svg | 1 +
src/assets/icons/fullscreen.svg | 1 +
src/assets/icons/gitcode.svg | 1 +
src/assets/icons/gitee.svg | 1 +
src/assets/icons/github.svg | 1 +
src/assets/icons/homepage.svg | 1 +
src/assets/icons/java.svg | 1 +
src/assets/icons/juejin.svg | 1 +
src/assets/icons/language.svg | 1 +
src/assets/icons/menu.svg | 1 +
src/assets/icons/message.svg | 1 +
src/assets/icons/monitor.svg | 1 +
src/assets/icons/project.svg | 1 +
src/assets/icons/qq.svg | 1 +
src/assets/icons/refresh.svg | 1 +
src/assets/icons/role.svg | 1 +
src/assets/icons/search.svg | 1 +
src/assets/icons/setting.svg | 1 +
src/assets/icons/size.svg | 1 +
src/assets/icons/system.svg | 1 +
src/assets/icons/table.svg | 1 +
src/assets/icons/todo.svg | 1 +
src/assets/icons/tree.svg | 1 +
src/assets/icons/typescript.svg | 1 +
src/assets/icons/up.svg | 1 +
src/assets/icons/user.svg | 1 +
src/assets/icons/visitor.svg | 1 +
src/assets/icons/vue.svg | 1 +
src/assets/icons/wechat.svg | 1 +
src/assets/icons/xml.svg | 1 +
src/assets/images/401.svg | 398 ++++
src/assets/images/404.svg | 340 +++
src/assets/images/login-bg.svg | 71 +
src/assets/logo.png | Bin 0 -> 38468 bytes
src/components/AppLink/index.vue | 38 +
src/components/Breadcrumb/index.vue | 85 +
src/components/CURD/PageContent.vue | 934 ++++++++
src/components/CURD/PageModal.vue | 271 +++
src/components/CURD/PageSearch.vue | 161 ++
src/components/CURD/types.ts | 223 ++
src/components/CURD/usePage.ts | 105 +
src/components/CommonWrapper/index.vue | 21 +
src/components/CopyButton/index.vue | 62 +
src/components/DarkModeSwitch/index.vue | 39 +
src/components/Dict/DictLabel.vue | 66 +
src/components/Dict/index.vue | 123 +
src/components/ECharts/index.vue | 81 +
src/components/Fullscreen/index.vue | 11 +
src/components/GithubCorner/index.vue | 62 +
src/components/Hamburger/index.vue | 63 +
src/components/IconSelect/index.vue | 207 ++
src/components/InputTag/index.vue | 73 +
src/components/LangSelect/index.vue | 49 +
src/components/MenuSearch/index.vue | 521 +++++
src/components/NoticeDropdown/index.vue | 215 ++
src/components/Pagination/index.vue | 91 +
src/components/SizeSelect/index.vue | 42 +
src/components/TableSelect/index.vue | 357 +++
src/components/TextScroll/index.vue | 412 ++++
src/components/Upload/FileUpload.vue | 310 +++
src/components/Upload/MultiImageUpload.vue | 215 ++
src/components/Upload/SingleImageUpload.vue | 201 ++
src/components/WangEditor/index.vue | 87 +
src/directive/index.ts | 9 +
src/directive/permission/index.ts | 64 +
src/enums/api/result.enum.ts | 23 +
src/enums/codegen/form.enum.ts | 15 +
src/enums/codegen/query.enum.ts | 37 +
src/enums/index.ts | 11 +
src/enums/settings/device.enum.ts | 14 +
src/enums/settings/layout.enum.ts | 53 +
src/enums/settings/locale.enum.ts | 14 +
src/enums/settings/theme.enum.ts | 32 +
src/enums/system/menu.enum.ts | 7 +
src/hooks/index.ts | 7 +
src/hooks/websocket/core/useStomp.ts | 312 +++
src/hooks/websocket/index.ts | 11 +
src/hooks/websocket/services/useDictSync.ts | 197 ++
.../websocket/services/useOnlineCount.ts | 180 ++
src/lang/index.ts | 31 +
src/lang/package/en.ts | 80 +
src/lang/package/zh-cn.ts | 80 +
src/layout/components/AppMain/index.vue | 36 +
.../NavBar/components/NavbarRight.vue | 127 +
src/layout/components/NavBar/index.vue | 40 +
.../Settings/components/LayoutSelect.vue | 140 ++
src/layout/components/Settings/index.vue | 193 ++
.../Sidebar/components/SidebarLogo.vue | 53 +
.../Sidebar/components/SidebarMenu.vue | 132 ++
.../Sidebar/components/SidebarMenuItem.vue | 201 ++
.../components/SidebarMenuItemTitle.vue | 53 +
.../Sidebar/components/SidebarMixTopMenu.vue | 111 +
src/layout/components/Sidebar/index.vue | 45 +
src/layout/components/TagsView/index.vue | 540 +++++
src/layout/index.vue | 306 +++
src/main.ts | 21 +
src/plugins/icons.ts | 9 +
src/plugins/index.ts | 31 +
src/plugins/permission.ts | 88 +
src/router/index.ts | 73 +
src/settings.ts | 37 +
src/store/index.ts | 17 +
src/store/modules/app.store.ts | 145 ++
src/store/modules/dict.store.ts | 72 +
src/store/modules/permission.store.ts | 111 +
src/store/modules/settings.store.ts | 97 +
src/store/modules/tags-view.store.ts | 257 ++
src/store/modules/user.store.ts | 122 +
src/styles/dark/css-vars.css | 7 +
src/styles/index.scss | 64 +
src/styles/reset.scss | 77 +
src/styles/variables.module.scss | 11 +
src/styles/variables.scss | 69 +
src/types/auto-imports.d.ts | 991 ++++++++
src/types/components.d.ts | 100 +
src/types/env.d.ts | 33 +
src/types/global.d.ts | 109 +
src/types/router.d.ts | 54 +
src/types/shims-vue.d.ts | 5 +
src/types/socket.d.ts | 6 +
src/types/websocket.ts | 15 +
src/utils/auth.ts | 27 +
src/utils/i18n.ts | 12 +
src/utils/index.ts | 58 +
src/utils/nprogress.ts | 18 +
src/utils/request.ts | 105 +
src/utils/theme.ts | 106 +
src/views/codegen/index.vue | 866 +++++++
src/views/dashboard/index.vue | 420 ++++
src/views/demo/api/apifox.vue | 27 +
src/views/demo/curd/config/add.ts | 137 ++
src/views/demo/curd/config/content.ts | 137 ++
src/views/demo/curd/config/edit.ts | 127 +
src/views/demo/curd/config/options.ts | 31 +
src/views/demo/curd/config/search.ts | 63 +
src/views/demo/curd/config2/add.ts | 55 +
src/views/demo/curd/config2/content.ts | 136 ++
src/views/demo/curd/config2/edit.ts | 105 +
src/views/demo/curd/config2/search.ts | 152 ++
src/views/demo/curd/index.vue | 213 ++
src/views/demo/dict-sync.vue | 308 +++
src/views/demo/dictionary.vue | 48 +
src/views/demo/drag.vue | 123 +
src/views/demo/icon-selector.vue | 21 +
src/views/demo/icons.vue | 129 +
src/views/demo/internal-doc.vue | 25 +
.../children/children/level3-1.vue | 5 +
.../children/children/level3-2.vue | 5 +
.../demo/multi-level/children/level2.vue | 7 +
src/views/demo/multi-level/level1.vue | 16 +
src/views/demo/route-param.vue | 16 +
src/views/demo/signature.vue | 185 ++
src/views/demo/table-select/config/select.ts | 121 +
src/views/demo/table-select/index.vue | 54 +
src/views/demo/text-scroll.vue | 30 +
src/views/demo/upload.vue | 40 +
src/views/demo/wang-editor.vue | 24 +
src/views/demo/websocket.vue | 246 ++
src/views/error/401.vue | 25 +
src/views/error/404.vue | 59 +
src/views/login/components/Login.vue | 220 ++
src/views/login/components/Register.vue | 203 ++
src/views/login/components/ResetPwd.vue | 57 +
src/views/login/index.vue | 85 +
src/views/profile/index.vue | 591 +++++
src/views/redirect/index.vue | 15 +
src/views/rnb/accounts.vue | 633 +++++
src/views/rnb/amount/amoRanges.vue | 167 ++
src/views/rnb/amount/amoReports.vue | 152 ++
src/views/rnb/amount/amoUsers.vue | 165 ++
src/views/rnb/extends.vue | 372 +++
src/views/rnb/oplogs.vue | 222 ++
src/views/rnb/software/softwareList.vue | 308 +++
src/views/system/config/index.vue | 293 +++
src/views/system/dept/index.vue | 320 +++
src/views/system/dict/dict-item.vue | 289 +++
src/views/system/dict/index.vue | 300 +++
src/views/system/log/index.vue | 118 +
src/views/system/menu/index.vue | 547 +++++
.../system/notice/components/MyNotice.vue | 204 ++
src/views/system/notice/index.vue | 472 ++++
src/views/system/role/index.vue | 474 ++++
src/views/system/user/components/DeptTree.vue | 70 +
.../system/user/components/UserImport.vue | 199 ++
src/views/system/user/index.vue | 491 ++++
tsconfig.json | 35 +
uno.config.ts | 83 +
vite.config.ts | 234 ++
262 files changed, 31355 insertions(+)
create mode 100644 .editorconfig
create mode 100644 .env.development
create mode 100644 .env.production
create mode 100644 .eslintrc-auto-import.json
create mode 100644 .gitignore
create mode 100644 .husky/commit-msg
create mode 100644 .husky/pre-commit
create mode 100644 .prettierignore
create mode 100644 .prettierrc.yaml
create mode 100644 .stylelintignore
create mode 100644 .stylelintrc.cjs
create mode 100644 .vscode/extensions.json
create mode 100644 .vscode/settings.json
create mode 100644 .vscode/vue3.0.code-snippets
create mode 100644 .vscode/vue3.2.code-snippets
create mode 100644 .vscode/vue3.3.code-snippets
create mode 100644 CHANGELOG.md
create mode 100644 README.en-US.md
create mode 100644 README.md
create mode 100644 commitlint.config.cjs
create mode 100644 eslint.config.ts
create mode 100644 index.html
create mode 100644 mock/auth.mock.ts
create mode 100644 mock/base.ts
create mode 100644 mock/dept.mock.ts
create mode 100644 mock/dict.mock.ts
create mode 100644 mock/log.mock.ts
create mode 100644 mock/menu.mock.ts
create mode 100644 mock/notice.mock.ts
create mode 100644 mock/role.mock.ts
create mode 100644 mock/user.mock.ts
create mode 100644 package.json
create mode 100644 public/favicon.ico
create mode 100644 public/files/20250716/710b7a81cbe748f28bfa10c44382fd67.jpg
create mode 100644 public/files/20250717/332f8fa543dc4f7f8262e05aae95a110.jpg
create mode 100644 public/files/20250717/4d806fda9d0f48c289028aef9c7e7e57.jpg
create mode 100644 public/files/20250717/de041f1795904b6c8a4e97ffb3072fb4.jpg
create mode 100644 public/files/default.gif
create mode 100644 src/App.vue
create mode 100644 src/api/auth.api.ts
create mode 100644 src/api/codegen.api.ts
create mode 100644 src/api/file.api.ts
create mode 100644 src/api/rnb/index.ts
create mode 100644 src/api/system/config.api.ts
create mode 100644 src/api/system/dept.api.ts
create mode 100644 src/api/system/dict.api.ts
create mode 100644 src/api/system/log.api.ts
create mode 100644 src/api/system/menu.api.ts
create mode 100644 src/api/system/notice.api.ts
create mode 100644 src/api/system/role.api.ts
create mode 100644 src/api/system/user.api.ts
create mode 100644 src/assets/icons/api.svg
create mode 100644 src/assets/icons/backtop.svg
create mode 100644 src/assets/icons/bilibili.svg
create mode 100644 src/assets/icons/browser.svg
create mode 100644 src/assets/icons/captcha.svg
create mode 100644 src/assets/icons/cascader.svg
create mode 100644 src/assets/icons/client.svg
create mode 100644 src/assets/icons/close.svg
create mode 100644 src/assets/icons/close_all.svg
create mode 100644 src/assets/icons/close_left.svg
create mode 100644 src/assets/icons/close_other.svg
create mode 100644 src/assets/icons/close_right.svg
create mode 100644 src/assets/icons/cnblogs.svg
create mode 100644 src/assets/icons/code.svg
create mode 100644 src/assets/icons/collapse.svg
create mode 100644 src/assets/icons/csdn.svg
create mode 100644 src/assets/icons/dict.svg
create mode 100644 src/assets/icons/document.svg
create mode 100644 src/assets/icons/down.svg
create mode 100644 src/assets/icons/download.svg
create mode 100644 src/assets/icons/enter.svg
create mode 100644 src/assets/icons/esc.svg
create mode 100644 src/assets/icons/file.svg
create mode 100644 src/assets/icons/fullscreen-exit.svg
create mode 100644 src/assets/icons/fullscreen.svg
create mode 100644 src/assets/icons/gitcode.svg
create mode 100644 src/assets/icons/gitee.svg
create mode 100644 src/assets/icons/github.svg
create mode 100644 src/assets/icons/homepage.svg
create mode 100644 src/assets/icons/java.svg
create mode 100644 src/assets/icons/juejin.svg
create mode 100644 src/assets/icons/language.svg
create mode 100644 src/assets/icons/menu.svg
create mode 100644 src/assets/icons/message.svg
create mode 100644 src/assets/icons/monitor.svg
create mode 100644 src/assets/icons/project.svg
create mode 100644 src/assets/icons/qq.svg
create mode 100644 src/assets/icons/refresh.svg
create mode 100644 src/assets/icons/role.svg
create mode 100644 src/assets/icons/search.svg
create mode 100644 src/assets/icons/setting.svg
create mode 100644 src/assets/icons/size.svg
create mode 100644 src/assets/icons/system.svg
create mode 100644 src/assets/icons/table.svg
create mode 100644 src/assets/icons/todo.svg
create mode 100644 src/assets/icons/tree.svg
create mode 100644 src/assets/icons/typescript.svg
create mode 100644 src/assets/icons/up.svg
create mode 100644 src/assets/icons/user.svg
create mode 100644 src/assets/icons/visitor.svg
create mode 100644 src/assets/icons/vue.svg
create mode 100644 src/assets/icons/wechat.svg
create mode 100644 src/assets/icons/xml.svg
create mode 100644 src/assets/images/401.svg
create mode 100644 src/assets/images/404.svg
create mode 100644 src/assets/images/login-bg.svg
create mode 100644 src/assets/logo.png
create mode 100644 src/components/AppLink/index.vue
create mode 100644 src/components/Breadcrumb/index.vue
create mode 100644 src/components/CURD/PageContent.vue
create mode 100644 src/components/CURD/PageModal.vue
create mode 100644 src/components/CURD/PageSearch.vue
create mode 100644 src/components/CURD/types.ts
create mode 100644 src/components/CURD/usePage.ts
create mode 100644 src/components/CommonWrapper/index.vue
create mode 100644 src/components/CopyButton/index.vue
create mode 100644 src/components/DarkModeSwitch/index.vue
create mode 100644 src/components/Dict/DictLabel.vue
create mode 100644 src/components/Dict/index.vue
create mode 100644 src/components/ECharts/index.vue
create mode 100644 src/components/Fullscreen/index.vue
create mode 100644 src/components/GithubCorner/index.vue
create mode 100644 src/components/Hamburger/index.vue
create mode 100644 src/components/IconSelect/index.vue
create mode 100644 src/components/InputTag/index.vue
create mode 100644 src/components/LangSelect/index.vue
create mode 100644 src/components/MenuSearch/index.vue
create mode 100644 src/components/NoticeDropdown/index.vue
create mode 100644 src/components/Pagination/index.vue
create mode 100644 src/components/SizeSelect/index.vue
create mode 100644 src/components/TableSelect/index.vue
create mode 100644 src/components/TextScroll/index.vue
create mode 100644 src/components/Upload/FileUpload.vue
create mode 100644 src/components/Upload/MultiImageUpload.vue
create mode 100644 src/components/Upload/SingleImageUpload.vue
create mode 100644 src/components/WangEditor/index.vue
create mode 100644 src/directive/index.ts
create mode 100644 src/directive/permission/index.ts
create mode 100644 src/enums/api/result.enum.ts
create mode 100644 src/enums/codegen/form.enum.ts
create mode 100644 src/enums/codegen/query.enum.ts
create mode 100644 src/enums/index.ts
create mode 100644 src/enums/settings/device.enum.ts
create mode 100644 src/enums/settings/layout.enum.ts
create mode 100644 src/enums/settings/locale.enum.ts
create mode 100644 src/enums/settings/theme.enum.ts
create mode 100644 src/enums/system/menu.enum.ts
create mode 100644 src/hooks/index.ts
create mode 100644 src/hooks/websocket/core/useStomp.ts
create mode 100644 src/hooks/websocket/index.ts
create mode 100644 src/hooks/websocket/services/useDictSync.ts
create mode 100644 src/hooks/websocket/services/useOnlineCount.ts
create mode 100644 src/lang/index.ts
create mode 100644 src/lang/package/en.ts
create mode 100644 src/lang/package/zh-cn.ts
create mode 100644 src/layout/components/AppMain/index.vue
create mode 100644 src/layout/components/NavBar/components/NavbarRight.vue
create mode 100644 src/layout/components/NavBar/index.vue
create mode 100644 src/layout/components/Settings/components/LayoutSelect.vue
create mode 100644 src/layout/components/Settings/index.vue
create mode 100644 src/layout/components/Sidebar/components/SidebarLogo.vue
create mode 100644 src/layout/components/Sidebar/components/SidebarMenu.vue
create mode 100644 src/layout/components/Sidebar/components/SidebarMenuItem.vue
create mode 100644 src/layout/components/Sidebar/components/SidebarMenuItemTitle.vue
create mode 100644 src/layout/components/Sidebar/components/SidebarMixTopMenu.vue
create mode 100644 src/layout/components/Sidebar/index.vue
create mode 100644 src/layout/components/TagsView/index.vue
create mode 100644 src/layout/index.vue
create mode 100644 src/main.ts
create mode 100644 src/plugins/icons.ts
create mode 100644 src/plugins/index.ts
create mode 100644 src/plugins/permission.ts
create mode 100644 src/router/index.ts
create mode 100644 src/settings.ts
create mode 100644 src/store/index.ts
create mode 100644 src/store/modules/app.store.ts
create mode 100644 src/store/modules/dict.store.ts
create mode 100644 src/store/modules/permission.store.ts
create mode 100644 src/store/modules/settings.store.ts
create mode 100644 src/store/modules/tags-view.store.ts
create mode 100644 src/store/modules/user.store.ts
create mode 100644 src/styles/dark/css-vars.css
create mode 100644 src/styles/index.scss
create mode 100644 src/styles/reset.scss
create mode 100644 src/styles/variables.module.scss
create mode 100644 src/styles/variables.scss
create mode 100644 src/types/auto-imports.d.ts
create mode 100644 src/types/components.d.ts
create mode 100644 src/types/env.d.ts
create mode 100644 src/types/global.d.ts
create mode 100644 src/types/router.d.ts
create mode 100644 src/types/shims-vue.d.ts
create mode 100644 src/types/socket.d.ts
create mode 100644 src/types/websocket.ts
create mode 100644 src/utils/auth.ts
create mode 100644 src/utils/i18n.ts
create mode 100644 src/utils/index.ts
create mode 100644 src/utils/nprogress.ts
create mode 100644 src/utils/request.ts
create mode 100644 src/utils/theme.ts
create mode 100644 src/views/codegen/index.vue
create mode 100644 src/views/dashboard/index.vue
create mode 100644 src/views/demo/api/apifox.vue
create mode 100644 src/views/demo/curd/config/add.ts
create mode 100644 src/views/demo/curd/config/content.ts
create mode 100644 src/views/demo/curd/config/edit.ts
create mode 100644 src/views/demo/curd/config/options.ts
create mode 100644 src/views/demo/curd/config/search.ts
create mode 100644 src/views/demo/curd/config2/add.ts
create mode 100644 src/views/demo/curd/config2/content.ts
create mode 100644 src/views/demo/curd/config2/edit.ts
create mode 100644 src/views/demo/curd/config2/search.ts
create mode 100644 src/views/demo/curd/index.vue
create mode 100644 src/views/demo/dict-sync.vue
create mode 100644 src/views/demo/dictionary.vue
create mode 100644 src/views/demo/drag.vue
create mode 100644 src/views/demo/icon-selector.vue
create mode 100644 src/views/demo/icons.vue
create mode 100644 src/views/demo/internal-doc.vue
create mode 100644 src/views/demo/multi-level/children/children/level3-1.vue
create mode 100644 src/views/demo/multi-level/children/children/level3-2.vue
create mode 100644 src/views/demo/multi-level/children/level2.vue
create mode 100644 src/views/demo/multi-level/level1.vue
create mode 100644 src/views/demo/route-param.vue
create mode 100644 src/views/demo/signature.vue
create mode 100644 src/views/demo/table-select/config/select.ts
create mode 100644 src/views/demo/table-select/index.vue
create mode 100644 src/views/demo/text-scroll.vue
create mode 100644 src/views/demo/upload.vue
create mode 100644 src/views/demo/wang-editor.vue
create mode 100644 src/views/demo/websocket.vue
create mode 100644 src/views/error/401.vue
create mode 100644 src/views/error/404.vue
create mode 100644 src/views/login/components/Login.vue
create mode 100644 src/views/login/components/Register.vue
create mode 100644 src/views/login/components/ResetPwd.vue
create mode 100644 src/views/login/index.vue
create mode 100644 src/views/profile/index.vue
create mode 100644 src/views/redirect/index.vue
create mode 100644 src/views/rnb/accounts.vue
create mode 100644 src/views/rnb/amount/amoRanges.vue
create mode 100644 src/views/rnb/amount/amoReports.vue
create mode 100644 src/views/rnb/amount/amoUsers.vue
create mode 100644 src/views/rnb/extends.vue
create mode 100644 src/views/rnb/oplogs.vue
create mode 100644 src/views/rnb/software/softwareList.vue
create mode 100644 src/views/system/config/index.vue
create mode 100644 src/views/system/dept/index.vue
create mode 100644 src/views/system/dict/dict-item.vue
create mode 100644 src/views/system/dict/index.vue
create mode 100644 src/views/system/log/index.vue
create mode 100644 src/views/system/menu/index.vue
create mode 100644 src/views/system/notice/components/MyNotice.vue
create mode 100644 src/views/system/notice/index.vue
create mode 100644 src/views/system/role/index.vue
create mode 100644 src/views/system/user/components/DeptTree.vue
create mode 100644 src/views/system/user/components/UserImport.vue
create mode 100644 src/views/system/user/index.vue
create mode 100644 tsconfig.json
create mode 100644 uno.config.ts
create mode 100644 vite.config.ts
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..00ee2de
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+# http://editorconfig.org
+root = true
+
+# 表示所有文件适用
+[*]
+charset = utf-8 # 设置文件字符集为 utf-8
+end_of_line = lf # 控制换行类型(lf | cr | crlf)
+indent_style = space # 缩进风格(tab | space)
+indent_size = 2 # 缩进大小
+insert_final_newline = true # 始终在文件末尾插入一个新行
+
+# 表示仅 md 文件适用以下规则
+[*.md]
+max_line_length = off # 关闭最大行长度限制
+trim_trailing_whitespace = false # 关闭末尾空格修剪
diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..b87bd81
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,17 @@
+# 应用端口
+VITE_APP_PORT=3000
+
+# 代理前缀
+VITE_APP_BASE_API=/dev-api
+
+# 接口地址
+VITE_APP_API_URL=http://localhost:10800
+# VITE_APP_API_URL=http://23.236.66.46:88 # 线上环境
+
+# WebSocket 端点(不配置则关闭),线上 ws://api.youlai.tech/ws ,本地 ws://localhost:8989/ws
+VITE_APP_WS_ENDPOINT=
+
+# 启用 Mock 服务
+VITE_MOCK_DEV_SERVER=false
+
+VITE_BASE_FILE_URL=\files
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..61ed25f
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,8 @@
+# 代理前缀
+VITE_APP_BASE_API='/prod-api'
+
+
+# WebSocket端点(可选)
+#VITE_APP_WS_ENDPOINT=wss://api.youlai.tech/ws
+
+VITE_BASE_FILE_URL=/files
diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json
new file mode 100644
index 0000000..0e8546f
--- /dev/null
+++ b/.eslintrc-auto-import.json
@@ -0,0 +1,316 @@
+{
+ "globals": {
+ "Component": true,
+ "ComponentPublicInstance": true,
+ "ComputedRef": true,
+ "EffectScope": true,
+ "ElMessage": true,
+ "ElMessageBox": true,
+ "ElNotification": true,
+ "InjectionKey": true,
+ "PropType": true,
+ "Ref": true,
+ "VNode": true,
+ "asyncComputed": true,
+ "autoResetRef": true,
+ "computed": true,
+ "computedAsync": true,
+ "computedEager": true,
+ "computedInject": true,
+ "computedWithControl": true,
+ "controlledComputed": true,
+ "controlledRef": true,
+ "createApp": true,
+ "createEventHook": true,
+ "createGlobalState": true,
+ "createInjectionState": true,
+ "createReactiveFn": true,
+ "createReusableTemplate": true,
+ "createSharedComposable": true,
+ "createTemplatePromise": true,
+ "createUnrefFn": true,
+ "customRef": true,
+ "debouncedRef": true,
+ "debouncedWatch": true,
+ "defineAsyncComponent": true,
+ "defineComponent": true,
+ "eagerComputed": true,
+ "effectScope": true,
+ "extendRef": true,
+ "getCurrentInstance": true,
+ "getCurrentScope": true,
+ "h": true,
+ "ignorableWatch": true,
+ "inject": true,
+ "isDefined": true,
+ "isProxy": true,
+ "isReactive": true,
+ "isReadonly": true,
+ "isRef": true,
+ "makeDestructurable": true,
+ "markRaw": true,
+ "nextTick": true,
+ "onActivated": true,
+ "onBeforeMount": true,
+ "onBeforeUnmount": true,
+ "onBeforeUpdate": true,
+ "onClickOutside": true,
+ "onDeactivated": true,
+ "onErrorCaptured": true,
+ "onKeyStroke": true,
+ "onLongPress": true,
+ "onMounted": true,
+ "onRenderTracked": true,
+ "onRenderTriggered": true,
+ "onScopeDispose": true,
+ "onServerPrefetch": true,
+ "onStartTyping": true,
+ "onUnmounted": true,
+ "onUpdated": true,
+ "pausableWatch": true,
+ "provide": true,
+ "reactify": true,
+ "reactifyObject": true,
+ "reactive": true,
+ "reactiveComputed": true,
+ "reactiveOmit": true,
+ "reactivePick": true,
+ "readonly": true,
+ "ref": true,
+ "refAutoReset": true,
+ "refDebounced": true,
+ "refDefault": true,
+ "refThrottled": true,
+ "refWithControl": true,
+ "resolveComponent": true,
+ "resolveRef": true,
+ "resolveUnref": true,
+ "shallowReactive": true,
+ "shallowReadonly": true,
+ "shallowRef": true,
+ "syncRef": true,
+ "syncRefs": true,
+ "templateRef": true,
+ "throttledRef": true,
+ "throttledWatch": true,
+ "toRaw": true,
+ "toReactive": true,
+ "toRef": true,
+ "toRefs": true,
+ "toValue": true,
+ "triggerRef": true,
+ "tryOnBeforeMount": true,
+ "tryOnBeforeUnmount": true,
+ "tryOnMounted": true,
+ "tryOnScopeDispose": true,
+ "tryOnUnmounted": true,
+ "unref": true,
+ "unrefElement": true,
+ "until": true,
+ "useActiveElement": true,
+ "useAnimate": true,
+ "useArrayDifference": true,
+ "useArrayEvery": true,
+ "useArrayFilter": true,
+ "useArrayFind": true,
+ "useArrayFindIndex": true,
+ "useArrayFindLast": true,
+ "useArrayIncludes": true,
+ "useArrayJoin": true,
+ "useArrayMap": true,
+ "useArrayReduce": true,
+ "useArraySome": true,
+ "useArrayUnique": true,
+ "useAsyncQueue": true,
+ "useAsyncState": true,
+ "useAttrs": true,
+ "useBase64": true,
+ "useBattery": true,
+ "useBluetooth": true,
+ "useBreakpoints": true,
+ "useBroadcastChannel": true,
+ "useBrowserLocation": true,
+ "useCached": true,
+ "useClipboard": true,
+ "useCloned": true,
+ "useColorMode": true,
+ "useConfirmDialog": true,
+ "useCounter": true,
+ "useCssModule": true,
+ "useCssVar": true,
+ "useCssVars": true,
+ "useCurrentElement": true,
+ "useCycleList": true,
+ "useDark": true,
+ "useDateFormat": true,
+ "useDebounce": true,
+ "useDebounceFn": true,
+ "useDebouncedRefHistory": true,
+ "useDeviceMotion": true,
+ "useDeviceOrientation": true,
+ "useDevicePixelRatio": true,
+ "useDevicesList": true,
+ "useDisplayMedia": true,
+ "useDocumentVisibility": true,
+ "useDraggable": true,
+ "useDropZone": true,
+ "useElementBounding": true,
+ "useElementByPoint": true,
+ "useElementHover": true,
+ "useElementSize": true,
+ "useElementVisibility": true,
+ "useEventBus": true,
+ "useEventListener": true,
+ "useEventSource": true,
+ "useEyeDropper": true,
+ "useFavicon": true,
+ "useFetch": true,
+ "useFileDialog": true,
+ "useFileSystemAccess": true,
+ "useFocus": true,
+ "useFocusWithin": true,
+ "useFps": true,
+ "useFullscreen": true,
+ "useGamepad": true,
+ "useGeolocation": true,
+ "useIdle": true,
+ "useImage": true,
+ "useInfiniteScroll": true,
+ "useIntersectionObserver": true,
+ "useInterval": true,
+ "useIntervalFn": true,
+ "useKeyModifier": true,
+ "useLastChanged": true,
+ "useLocalStorage": true,
+ "useMagicKeys": true,
+ "useManualRefHistory": true,
+ "useMediaControls": true,
+ "useMediaQuery": true,
+ "useMemoize": true,
+ "useMemory": true,
+ "useMounted": true,
+ "useMouse": true,
+ "useMouseInElement": true,
+ "useMousePressed": true,
+ "useMutationObserver": true,
+ "useNavigatorLanguage": true,
+ "useNetwork": true,
+ "useNow": true,
+ "useObjectUrl": true,
+ "useOffsetPagination": true,
+ "useOnline": true,
+ "usePageLeave": true,
+ "useParallax": true,
+ "useParentElement": true,
+ "usePerformanceObserver": true,
+ "usePermission": true,
+ "usePointer": true,
+ "usePointerLock": true,
+ "usePointerSwipe": true,
+ "usePreferredColorScheme": true,
+ "usePreferredContrast": true,
+ "usePreferredDark": true,
+ "usePreferredLanguages": true,
+ "usePreferredReducedMotion": true,
+ "usePrevious": true,
+ "useRafFn": true,
+ "useRefHistory": true,
+ "useResizeObserver": true,
+ "useScreenOrientation": true,
+ "useScreenSafeArea": true,
+ "useScriptTag": true,
+ "useScroll": true,
+ "useScrollLock": true,
+ "useSessionStorage": true,
+ "useShare": true,
+ "useSlots": true,
+ "useSorted": true,
+ "useSpeechRecognition": true,
+ "useSpeechSynthesis": true,
+ "useStepper": true,
+ "useStorage": true,
+ "useStorageAsync": true,
+ "useStyleTag": true,
+ "useSupported": true,
+ "useSwipe": true,
+ "useTemplateRefsList": true,
+ "useTextDirection": true,
+ "useTextSelection": true,
+ "useTextareaAutosize": true,
+ "useThrottle": true,
+ "useThrottleFn": true,
+ "useThrottledRefHistory": true,
+ "useTimeAgo": true,
+ "useTimeout": true,
+ "useTimeoutFn": true,
+ "useTimeoutPoll": true,
+ "useTimestamp": true,
+ "useTitle": true,
+ "useToNumber": true,
+ "useToString": true,
+ "useToggle": true,
+ "useTransition": true,
+ "useUrlSearchParams": true,
+ "useUserMedia": true,
+ "useVModel": true,
+ "useVModels": true,
+ "useVibrate": true,
+ "useVirtualList": true,
+ "useWakeLock": true,
+ "useWebNotification": true,
+ "useWebSocket": true,
+ "useWebWorker": true,
+ "useWebWorkerFn": true,
+ "useWindowFocus": true,
+ "useWindowScroll": true,
+ "useWindowSize": true,
+ "watch": true,
+ "watchArray": true,
+ "watchAtMost": true,
+ "watchDebounced": true,
+ "watchDeep": true,
+ "watchEffect": true,
+ "watchIgnorable": true,
+ "watchImmediate": true,
+ "watchOnce": true,
+ "watchPausable": true,
+ "watchPostEffect": true,
+ "watchSyncEffect": true,
+ "watchThrottled": true,
+ "watchTriggerable": true,
+ "watchWithFilter": true,
+ "useRoute": true,
+ "useRouter": true,
+ "storeToRefs": true,
+ "whenever": true,
+ "DirectiveBinding": true,
+ "ExtractDefaultPropTypes": true,
+ "ExtractPropTypes": true,
+ "ExtractPublicPropTypes": true,
+ "MaybeRef": true,
+ "MaybeRefOrGetter": true,
+ "WritableComputedRef": true,
+ "acceptHMRUpdate": true,
+ "createPinia": true,
+ "defineStore": true,
+ "getActivePinia": true,
+ "injectLocal": true,
+ "mapActions": true,
+ "mapGetters": true,
+ "mapState": true,
+ "mapStores": true,
+ "mapWritableState": true,
+ "onBeforeRouteLeave": true,
+ "onBeforeRouteUpdate": true,
+ "onWatcherCleanup": true,
+ "provideLocal": true,
+ "setActivePinia": true,
+ "setMapStoreSuffix": true,
+ "useClipboardItems": true,
+ "useI18n": true,
+ "useId": true,
+ "useLink": true,
+ "useModel": true,
+ "useTemplateRef": true
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a6d77ca
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+node_modules
+.DS_Store
+dist
+dist-ssr
+*.local
+.history
+
+# Editor directories and files
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+stats.html
+pnpm-lock.yaml
+package-lock.json
+.stylelintcache
+.eslintcache
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000..fd2bf70
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1 @@
+npx --no-install commitlint --edit $1
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100644
index 0000000..b18d041
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1 @@
+npm run lint:lint-staged
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..44421a7
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,12 @@
+dist
+node_modules
+public
+.husky
+.vscode
+.idea
+*.sh
+*.md
+
+src/assets
+stats.html
+pnpm-lock.yaml
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 0000000..d9cf0c7
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,41 @@
+# 在单参数箭头函数中始终添加括号
+arrowParens: "always"
+# JSX 多行元素的闭合标签另起一行
+bracketSameLine: false
+# 对象字面量中的括号之间添加空格
+bracketSpacing: true
+# 自动格式化嵌入的代码(如 Markdown 和 HTML 内的代码)
+embeddedLanguageFormatting: "auto"
+# 忽略 HTML 空白敏感度,将空白视为非重要内容
+htmlWhitespaceSensitivity: "ignore"
+# 不插入 @prettier 的 pragma 注释
+insertPragma: false
+# 在 JSX 中使用双引号
+jsxSingleQuote: false
+# 每行代码的最大长度限制为 100 字符
+printWidth: 100
+# 在 Markdown 中保留原有的换行格式
+proseWrap: "preserve"
+# 仅在必要时添加对象属性的引号
+quoteProps: "as-needed"
+# 不要求文件开头插入 @prettier 的 pragma 注释
+requirePragma: false
+# 在语句末尾添加分号
+semi: true
+# 使用双引号而不是单引号
+singleQuote: false
+# 缩进使用 2 个空格
+tabWidth: 2
+# 在多行元素的末尾添加逗号(ES5 支持的对象、数组等)
+trailingComma: "es5"
+# 使用空格而不是制表符缩进
+useTabs: false
+# Vue 文件中的 ",
+ "",
+ "",
+ ""
+ ],
+ "description": "Vue3.0"
+ }
+}
diff --git a/.vscode/vue3.2.code-snippets b/.vscode/vue3.2.code-snippets
new file mode 100644
index 0000000..a083940
--- /dev/null
+++ b/.vscode/vue3.2.code-snippets
@@ -0,0 +1,17 @@
+{
+ "Vue3.2+快速生成模板": {
+ "scope": "vue",
+ "prefix": "Vue3.2+",
+ "body": [
+ "",
+ "",
+ "",
+ " ${1:test}
",
+ " ",
+ "",
+ "",
+ ""
+ ],
+ "description": "Vue3.2+"
+ }
+}
diff --git a/.vscode/vue3.3.code-snippets b/.vscode/vue3.3.code-snippets
new file mode 100644
index 0000000..705e04f
--- /dev/null
+++ b/.vscode/vue3.3.code-snippets
@@ -0,0 +1,21 @@
+{
+ "Vue3.3+defineOptions快速生成模板": {
+ "scope": "vue",
+ "prefix": "Vue3.3+",
+ "body": [
+ "",
+ "",
+ "",
+ " ${1:test}
",
+ " ",
+ "",
+ "",
+ ""
+ ],
+ "description": "Vue3.3+defineOptions快速生成模板"
+ }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..aef3f6d
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,386 @@
+
+# 2.11.5 (2024/6/18)
+
+## ✨ feat
+
+- 支持后端文件导入([#142](https://github.com/youlaitech/vue3-element-admin/pull/142)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+
+## 🐛 fix
+- vue-dev-tools 插件导致菜单路由切换卡死,暂时关闭 ([28349e](https://github.com/youlaitech/vue3-element-admin/commit/28349efe147afab36531ba148eaac3a448fe6c71)) [@haoxianrui](https://github.com/haoxianrui)
+
+
+
+# 2.11.4 (2024/6/16)
+
+## ✨ feat
+
+- 操作栏增加render配置参数([#138](https://github.com/youlaitech/vue3-element-admin/pull/140)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 左侧工具栏增加type配置参数([#141](https://github.com/youlaitech/vue3-element-admin/pull/141)) [@diamont1001](https://github.com/diamont1001)
+
+## ♻️ refactor
+- 更换权限分配弹窗类型为 drawer 并添加父子联动开关([2d9193](https://github.com/youlaitech/vue3-element-admin/commit/2d9193c47fd224f01f82b9c0b2bbeb5e7cb33584)) [@haoxianrui](https://github.com/haoxianrui)
+
+
+
+# 2.11.3 (2024/6/11)
+
+## ✨ feat
+
+- 支持默认工具栏的导入([#138](https://github.com/youlaitech/vue3-element-admin/pull/138)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 添加CURD导入示例([19e7bb](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+## ♻️ refactor
+- 修改导出全量数据选项文本([904fec](https://github.com/youlaitech/vue3-element-admin/commit/904fecad65217650482fcdbb10ffb7f3d27eb9ea)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+## 🐛 fix
+- 菜单列表未适配el-icon导致图标不显示问题修复([e72b68](https://github.com/youlaitech/vue3-element-admin/commit/e72b68337562b5a7ea24ad55bbe00023e1266b40)) [@haoxianrui](https://github.com/haoxianrui)
+
+# 2.11.2 (2024/6/8)
+
+## ✨ feat
+
+- 支持表格远程筛选([#131](https://github.com/youlaitech/vue3-element-admin/pull/131)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 支持标签输入框([#132](https://github.com/youlaitech/vue3-element-admin/pull/132)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 表单项支持tips配置([#133](https://github.com/youlaitech/vue3-element-admin/pull/133)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 前端导出支持全量数据([#134](https://github.com/youlaitech/vue3-element-admin/pull/134)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 支持选中数据导出([#135](https://github.com/youlaitech/vue3-element-admin/pull/135)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 表格默认工具栏的导出、搜索按钮增加权限点控制([883128](https://github.com/youlaitech/vue3-element-admin/commit/8831289b655f2cc086ecdababaa89f8d8a087c42)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 页签title支持动态设置([23876a](https://github.com/youlaitech/vue3-element-admin/commit/23876aa396143bf77cb5c86af8d6023d9ff6555a)) [@haoxianrui](https://github.com/haoxianrui)
+
+## ♻️ refactor
+- 默认工具栏支持自定义([#136](https://github.com/youlaitech/vue3-element-admin/pull/136)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 未配置全量导出接口时选项隐藏([eab91ef](https://github.com/youlaitech/vue3-element-admin/commit/eab91effd6a01d5a3d9257249c8d06aa252b3bf8)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+## 🐛 fix
+- 修复注销登出后redirect跳转路由参数丢失([5626017](https://github.com/youlaitech/vue3-element-admin/commit/562601736731afd20bb1a5140d856f6515720159)) [@haoxianrui](https://github.com/haoxianrui)
+
+# 2.11.1 (2024/6/6)
+
+## ✨ feat
+
+- 增加pagination、request、parseData配置参数([#119](https://github.com/youlaitech/vue3-element-admin/pull/119)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 增加返回顶部功能([#120](https://github.com/youlaitech/vue3-element-admin/pull/120)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 支持前端导出([#126](https://github.com/youlaitech/vue3-element-admin/pull/126)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+## ♻️ refactor
+- 重构布局样式(解决页面抖动问题)([#116](https://github.com/youlaitech/vue3-element-admin/pull/116)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 修改CURD示例编辑弹窗尺寸([#121](https://github.com/youlaitech/vue3-element-admin/pull/121)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 统一注册vue插件([#122](https://github.com/youlaitech/vue3-element-admin/pull/122)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 默认主题跟随系统([#128](https://github.com/youlaitech/vue3-element-admin/pull/128)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 增加"scss.lint.unknownAtRules": "ignore"代码,解决style中使用@apply提示unknow at rules@apply提示问题([Gitee#22](https://gitee.com/youlaiorg/vue3-element-admin/pulls/22)) [@zjsy521](https://gitee.com/zjsy521)
+
+## 🐛 fix
+- 修复左侧布局移动端菜单弹出样式 ([#117](https://github.com/youlaitech/vue3-element-admin/pull/117)) [@cshaptx4869](https://github.com/cshaptx4869)
+
+- 修复编辑后未清空id再新增菜单覆盖的问题([0e78eeb](https://github.com/youlaitech/vue3-element-admin/commit/0e78eeb75008fa8e9732b1b4e7d7a1ea345c7a1b)) [@haoxianrui](https://github.com/haoxianrui)
+- 修复水印层级问题([#123](https://github.com/youlaitech/vue3-element-admin/pull/123)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 修复混合布局样式问题([#124](https://github.com/youlaitech/vue3-element-admin/pull/124)) [@cshaptx4869](https://github.com/cshaptx4869)
+- 修复关闭弹窗时没有clearValidate问题([#125](https://github.com/youlaitech/vue3-element-admin/pull/125)) [@andm31](https://github.com/andm31)
+
+
+
+# 2.11.0 (2024/5/27)
+
+## ✨ feat
+- 菜单添加路由参数设置(author by [haoxianrui](https://github.com/haoxianrui))
+- 增加列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 增加列表选择组件使用示例(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 增加defaultToolbar配置参数(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 表单弹窗支持drawer模式(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 表单项增加computed和watchEffect配置(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 支持switch属性修改(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 表单项增加文本类型支持(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 列表列增加show配置项(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 支持搜索表单显隐控制(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 支持input属性修改(author by [cshaptx4869](https://github.com/cshaptx4869))
+- search配置新增函数能力拓展(author by [xiudaozhe](https://github.com/xiudaozhe))
+- 表格新增列设置控制(author by [haoxianrui](https://github.com/haoxianrui))
+- 搜索添加展开和收缩(author by [haoxianrui](https://github.com/haoxianrui))
+- watch函数增加配置项参数返回(author by [cshaptx4869](https://github.com/cshaptx4869))
+
+## ♻️ refactor
+- 重构图标选择组件(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 重构列表选择组件默认样式 (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 加强对话框表单组件和列表选择组件(author by [cshaptx4869](https://github.com/cshaptx4869))
+- routeMeta增加alwaysShow字段声明(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 分页组件增加溢出滚动效果(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修正登录表单的Ref类型(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 点击表格刷新按钮不重置页码(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 筛选列超出一定高度滚动(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 优化加强initFn函数,表单项增加initFn函数(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 重构watch、computed、watchEffect调用(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修改操作成功提示(author by [cshaptx4869](https://github.com/cshaptx4869))
+- PageSearch 改用card作为容器,样式改用unocss写法(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 优化首页 loading 动画效果author by [haoxianrui](https://github.com/haoxianrui))
+
+
+## 🐛 fix
+- 路由是否始终显示不限制只有顶级目录才有的配置,开放至菜单 (author by [haoxianrui](https://github.com/haoxianrui))
+- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui))
+- 发送用户重启密码功能,最少为6位字符(小于6位登陆时不允许的问题) (author by [dreamnyj](https://gitee.com/dreamnyj))
+- 修复系统设置面板滚动条问题(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修复表单插槽失效问题(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修改tagsview刷新丢失query问题(author by [xiudaozhe](https://github.com/xiudaozhe))
+
+## 📦️ build
+- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui))
+
+## ⚙️ ci
+- 规整脚本执行命令(author by [cshaptx4869](https://github.com/cshaptx4869))
+
+
+# 2.10.1 (2024/5/4)
+
+## ♻️ refactor
+- 抽离CURD的使用部分代码为Hooks实现(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修改CURD导入权限点标识名(author by [cshaptx4869](https://github.com/cshaptx4869))
+- cURD表单字段支持watch监听(author by [cshaptx4869](https://github.com/cshaptx4869))
+- cURD表单input支持number修饰(author by [cshaptx4869](https://github.com/cshaptx4869))
+- cURD表单组件支持checkbox多选框(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 优化axios响应数据TS类型提示(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修改CURD表单组件自定义类型的attrs传值(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 同步重置密码按钮权限标识重命名(author by [haoxianrui](https://github.com/haoxianrui))
+- 重构API为静态方法实现模块化管理,并将types.ts重命名为model.ts用于存放接口模型定义(author by [haoxianrui](https://github.com/haoxianrui))
+
+
+## 🐛 fix
+- sockjs-client 报错 global is not defined 导致开发环境无法打开 WebSocket 页面问题修复 (author by [haoxianrui](https://github.com/haoxianrui))
+- 主题颜色设置覆盖暗黑模式下el-table行激活的背景色问题修复 (author by [haoxianrui](https://github.com/haoxianrui))
+- 修复因API接口调整而影响的调用页面的问题 (author by [haoxianrui](https://github.com/haoxianrui))
+
+## 📦️ build
+- 升级 NPM 包版本至最新 (author by [haoxianrui](https://github.com/haoxianrui))
+
+
+# 2.10.0 (2024/4/26)
+## ✨ feat
+- 封装增删改查组件(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 集成 vite-plugin-vue-devtools 插件(author by [Tricker39](https://github.com/Tricker39))
+- 增加CURD配置化实现(author by [cshaptx4869](https://github.com/cshaptx4869))
+
+
+# 2.9.3 (2024/04/14)
+## ✨ feat
+- 增加vue文件代码片段(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 菜单 hover 背景色添加值全局SCSS变量进行控制(author by [haoxianrui](https://github.com/haoxianrui))
+
+## ♻️ refactor
+- 加强基础国际化(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 增加语言和布局大小枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 增加侧边栏状态枚举类型(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 使用布局枚举替换字面量(author by [haoxianrui](https://github.com/haoxianrui))
+- 控制台使用静态数据循环渲染(author by [april](mailto:april@zen-game.cn))
+- 本地缓存的 token 变量重命名(author by [haoxianrui](https://github.com/haoxianrui))
+- 完善 Vite 环境变量类型声明(author by [haoxianrui](https://github.com/haoxianrui))
+
+## 🐛 fix
+- 修复构建时提示iconComponent.name可能为undefined的报错 (author by [wangji1042](https://github.com/wangji1042))
+- 修复浏览器密码自动填充时可能存在的报错 (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修复eslint报错(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 移动端下点击左侧菜单节点后关闭侧边栏(author by [haoxianrui](https://github.com/haoxianrui))
+- 添加 size 类型断言修复类型报错(author by [haoxianrui](https://github.com/haoxianrui))
+
+## 📦️ build
+- husky9.x版本适配 (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 升级 npm 包版本至最新(author by [haoxianrui](https://github.com/haoxianrui))
+
+# 2.9.2 (2024/03/05)
+## ✨ feat
+- vscode开发扩展推荐(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 完善基础增删改查Mock接口(author by [haoxianrui](https://github.com/haoxianrui))
+
+## ♻️ refactor
+- 修改login密码框功能实现(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 弱化页面进入动画效果(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 取消推荐TypeScript Vue Plugin (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 网站加载动画替换 (author by [haoxianrui](https://github.com/haoxianrui))
+- 优化主题和主题色监听,避免多个页面重复初始化 (author by [haoxianrui](https://github.com/haoxianrui))
+
+## 🐛 fix
+- AppMain 高度在非固定头部不正确导致出现滚动条问题修复 (author by [haoxianrui](https://github.com/haoxianrui))
+- 修复混合模式开启固定Head时的样式问题 (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 设置面板统一字体大小 (author by [cshaptx4869](https://github.com/cshaptx4869))
+
+## 📦️build
+- 通过env配置控制mock服务 (author by [cshaptx4869](https://github.com/cshaptx4869))
+- 升级依赖包至最新版本 (author by [haoxianrui](https://github.com/haoxianrui))
+- 定义vite全局常量替换项目标题和版本 (author by [cshaptx4869](https://github.com/cshaptx4869))
+
+# 2.9.1 (2024/02/28)
+## ♻️ refactor
+- 项目配置按钮移入navbar(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 优化user数据定义(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 统一设置栏的 SVG 图标风格
+
+## 🐛 fix
+- 规整一些开发依赖(author by [cshaptx4869](https://github.com/cshaptx4869))
+- 修复登录页主题切换问题 (author by [cshaptx4869](https://github.com/cshaptx4869))
+
+## 🚀 pref
+
+- 压缩图片资源 (author by [cshaptx4869](https://github.com/cshaptx4869))
+
+
+# 2.9.0 (2024/02/25)
+
+## ✨ feat
+- 引入 animate.css 动画库
+- 新增水印和配置
+- 动态路由菜单支持 element plus 的图标
+
+## ♻️ refactor
+- Layout 布局重构和相关问题修复
+- sass 使用 @use 替代 @import 引入外部文件指令
+
+## 🐛 fix
+- 修复管理页面部分弹窗无法打开问题
+- 主题颜色设置按钮 hover 等未变化问题修复
+
+
+# 2.8.1 (2024/01/10)
+
+## ✨ feat
+- 替换 Mock 解决方案 vite-plugin-mock 为 vite-plugin-mock-dev-server 适配 Vite5
+
+# 2.8.0 (2023/12/27)
+
+## ⬆️ chore
+- 升级 Vite4 至 Vite5
+
+# 2.7.1 (2023/12/12)
+
+## ♻️ refactor
+- 将打包后的文件进行分类 (author by [ityangzhiwen](https://gitee.com/ityangzhiwen))
+
+# 2.7.0 (2023/11/19)
+
+## ♻️ refactor
+- 代码重构优化
+- 修改自动导入组件类型声明文件路径
+- 完善 typescript 类型
+
+## 🐛 fix
+- 修复管理页面部分弹窗无法打开问题
+
+
+# 2.7.0 (2023/11/19)
+
+## ♻️ refactor
+- 代码重构
+- 修改自动导入组件类型声明文件路径
+- 完善 typescript 类型
+
+## 🐛 fix
+- 修复管理页面部分弹窗无法打开问题
+
+
+# 2.6.3 (2023/10/22)
+
+## ✨ feat
+- 菜单管理新增目录只有一级子路由是否始终显示(alwaysShow)和路由页面是否缓存(keepAlive)的配置
+- 接口文档新增 swagger、knife4j
+- 引入和支持 tsx
+
+## ♻️ refactor
+- 代码瘦身,整理并删除未使用的 svg
+- 控制台样式优化
+
+## 🐛 fix
+- 菜单栏折叠和展开的图标暗黑模式显示问题修复
+
+
+# 2.6.2 (2023/10/11)
+
+## 🐛 fix
+- 主题设置未持久化问题
+- UnoCSS 插件无智能提示
+
+## ♻️ refactor
+- WebSocket 演示样式和代码优化
+- 用户管理代码重构
+
+# 2.6.1 (2023/9/4)
+
+## 🐛 fix
+- 导航顶部模式、混合模式样式在固定 Header 出现的样式问题修复
+- 固定 Header 没有持久化问题修复
+- 字典回显兼容 String 和 Number 类型
+
+# 2.6.0 (2023/8/24)💥💥💥
+
+## ✨ feat
+- 导航顶部模式、混合模式支持(author by [april-tong](https://april-tong.com/))
+- 平台文档(内嵌)(author by [april-tong](https://april-tong.com/))
+
+# 2.5.0 (2023/8/8)
+
+## ✨ feat
+- 新增 Mock(author by [ygcaicn](https://github.com/ygcaicn))
+- 图标 DEMO(author by [ygcaicn](https://github.com/ygcaicn))
+
+## 🐛 fix
+- 字典支持 Number 类型
+
+# 2.4.1 (2023/7/20)
+
+## ✨ feat
+- 整合 vite-plugin-compression 插件打包优化(3.66MB → 1.58MB) (author by [april-tong](https://april-tong.com/))
+- 字典组件封装(author by [haoxr](https://juejin.cn/user/4187394044331261/posts))
+
+## 🐛 fix
+- 分页组件hidden无效
+- 签名无法保存至后端
+- Git 提交 stylelint 校验部分机器报错
+
+# 2.4.0 (2023/6/17)
+
+## ✨ feat
+- 新增组件标签输入框(author by [april-tong](https://april-tong.com/))
+- 新增组件签名(author by [april-tong](https://april-tong.com/))
+- 新增组件表格(author by [april-tong](https://april-tong.com/))
+- Echarts 图表添加下载功能 author by [april-tong](https://april-tong.com/))
+
+## ♻️ refactor
+- 限制包管理器为 pnpm 和 node 版本16+
+- 自定义组件自动导入配置
+- 搜索框样式写法优化
+
+## 🐛 fix
+- 用户导入的部门回显成数字问题修复
+
+## ⬆️ chore
+- element-plus 版本升级 2.3.5 → 2.3.6
+
+# 2.3.1 (2023/5/21)
+
+## 🔄 refactor
+- 组件示例文件名称优化
+
+# 2.2.2 (2023/5/11)
+
+## ✨ feat
+- 组件封装示例添加源码地址
+- 角色、菜单、部门、字段按钮添加权限控制
+
+
+# 2.3.0 (2023/5/12)
+
+## ⬆️ chore
+- vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md))
+- vite 版本升级 4.3.1 → 4.3.5
+
+## ♻️ refactor
+- 使用 vue 3.3 版本新特性 `defineOptions` 在 `setup` 定义组件名称,移除重复的 `script` 标签
+
+# 2.2.2 (2023/5/11)
+
+## ✨ feat
+- 用户新增提交添加 `vueUse` 的 `useDebounceFn` 函数实现按钮防抖节流
+
+
+# 2.2.1 (2023/4/25)
+
+## 🐛 fix
+- 图标选择器组件使用 `onClickOutside` 未排除下拉弹出框元素导致无法输入搜索。
+
diff --git a/README.en-US.md b/README.en-US.md
new file mode 100644
index 0000000..0a92b17
--- /dev/null
+++ b/README.en-US.md
@@ -0,0 +1,222 @@
+
+
+
vue3-element-admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Introduction
+
+[vue3-element-admin](https://gitcode.com/youlai/vue3-element-admin) is a minimalist enterprise-level backend management frontend template built with Vue3, Vite, TypeScript, and Element-Plus. It comes with complementary Java backend [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) and Node backend [youlai-nest](https://gitee.com/youlaiorg/youlai-nest). A simplified version [vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) and a JavaScript version [vue3-element-admin-js](https://gitee.com/youlaiorg/vue3-element-admin) are also available for developers to quickly start development.
+
+
+## Project Features
+
+- **Simple and Easy-to-use**: Upgraded version of [vue-element-admin](https://gitee.com/panjiachen/vue-element-admin) for Vue3, with minimal encapsulation and easy to get started.
+- **Data Interaction**: Support for `Mock` data and [online API documentation](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5), with accompanying [Java](https://gitee.com/youlaiorg/youlai-boot) and [Node](https://gitee.com/youlaiorg/youlai-nest) backend source code.
+
+- **System Functions**: Provides user management, role management, menu management, department management, dictionary management, and other functional modules.
+- **Permission Management**: Supports dynamic routing, button permissions, role permissions, and data permissions.
+
+- **Infrastructure**: Provides internationalization, multiple layouts, dark mode, full screen, watermark, API documentation, and code generator functionality.
+- **Continuous Updates**: Project is continuously updated with real-time updates of tools and dependencies.
+
+
+## Project Screenshots
+
+🖥️ **Dashboard**
+
+
+
+⚡**API Documentation**
+
+
+
+📲 **Mobile Version**
+
+
+
+## Project Source Code
+
+| Project | Gitee | Github | GitCode|
+| ---- | ----| ---- | ---- |
+| vue3-element-admin ✅| [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | [vue3-element-admin](https://github.com/youlaitech/vue3-element-admin) | [vue3-element-admin](https://gitcode.com/youlai/vue3-element-admin) |
+| vue3-element-admin JS Version| [vue3-element-admin-js](https://gitee.com/youlaiorg/vue3-element-admin-js) | [vue3-element-admin-js](https://github.com/youlaitech/vue3-element-admin-js) | [vue3-element-admin-js](https://gitcode.com/youlai/vue3-element-admin-js) |
+| vue3-element-admin Lite Version | [vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) | [vue3-element-template](https://github.com/youlaitech/vue3-element-template) |[vue3-element-template](https://gitcode.com/youlai/vue3-element-template)|
+| vue-uniapp-admin Mobile Version | [vue-uniapp-admin](https://gitee.com/youlaiorg/vue-uniapp-admin) | [vue-uniapp-admin](https://github.com/youlaitech/vue-uniapp-admin) |[vue-uniapp-admin](https://gitcode.com/youlai/vue-uniapp-admin)|
+| Java Backend | [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) | [youlai-boot](https://github.com/haoxianrui/youlai-boot.git) |[youlai-boot](https://gitcode.com/youlai/youlai-boot.git)|
+| Node Backend | [youlai-nest](https://gitee.com/youlaiorg/youlai-nest) | [youlai-nest](https://github.com/haoxianrui/youlai-nest.git) |[youlai-nest](https://gitcode.com/youlai/youlai-nest.git)|
+
+
+
+## Development Guide
+
+| Name | Link |
+|---------------|--------------------|
+| Video Tutorial | [https://www.bilibili.com/video/BV1eFUuYyEFj](https://www.bilibili.com/video/BV1eFUuYyEFj) |
+| Project Setup | [Building a Backend Management System from Scratch with Vue3, Vite, TypeScript, and Element-Plus](https://blog.csdn.net/u013737132/article/details/130191394) |
+| Official Documentation | [https://www.youlai.tech/vue3-element-admin/](https://www.youlai.tech/vue3-element-admin/) |
+| Code Standards | [ESLint V9 + Prettier + Stylelint + EditorConfig for Standardized and Unified Frontend Code Style](https://youlai.blog.csdn.net/article/details/145608723) |
+| Commit Standards | [Husky + Lint-staged + Commitlint + Commitizen + cz-git for Git Commit Standards](https://youlai.blog.csdn.net/article/details/145615236) |
+| API Documentation | [https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5) |
+
+
+
+## Project Setup
+
+
+- **Environment Preparation**
+
+| Environment Type | Name |
+|----------------|-----------------------------|
+| **Development Tool** | [Visual Studio Code](https://code.visualstudio.com/Download) |
+| **Runtime Environment** | Node 18 + (Recommended [22.9.0](https://npmmirror.com/mirrors/node/v22.9.0/)) |
+> ⚠️ Note: Node.js version 20.6.0 has compatibility issues, please don't use it
+
+
+- **Quick Start**
+
+```bash
+# Clone repository
+git clone https://gitee.com/youlaiorg/vue3-element-admin.git
+
+# Change directory
+cd vue3-element-admin
+
+# Install pnpm
+npm install pnpm -g
+
+# Set mirror source (optional)
+pnpm config set registry https://registry.npmmirror.com
+
+# Install dependencies
+pnpm install
+
+# Start development server
+pnpm run dev
+```
+
+
+## Project Deployment
+
+After executing the `pnpm run build` command, the project will be bundled and a `dist` directory will be generated. Next, upload the files from the `dist` directory to the `/usr/share/nginx/html` directory on your server and configure Nginx for reverse proxy.
+
+```bash
+pnpm run build
+```
+
+Here is an example Nginx configuration:
+
+```nginx
+server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ }
+
+ # Reverse proxy configuration
+ location /prod-api/ {
+ # Please replace api.youlai.tech with your backend API address, and keep the trailing slash /
+ proxy_pass http://api.youlai.tech/;
+ }
+}
+```
+
+For more detailed information, please refer to this article: [Nginx Installation and Configuration](https://blog.csdn.net/u013737132/article/details/145667694).
+
+## Local Mock
+
+The project supports both online and local Mock interfaces. By default, it uses online interfaces. To switch to Mock interfaces, modify the `VITE_MOCK_DEV_SERVER` value in the `.env.development` file to `true`.
+
+## Backend API
+
+> If you have a basic understanding of Java development, follow these steps to convert online API to local backend API and create an enterprise-level full-stack development environment to help you on your full-stack journey.
+
+1. Get the backend source code based on `Java` and `SpringBoot` from [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git).
+2. Follow the instructions in the backend project's README.md to [set up and run locally](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C).
+3. Modify the value of `VITE_APP_API_URL` in the `.env.development` file, changing it from https://api.youlai.tech to http://localhost:8989.
+
+
+## Notes
+
+- **Auto import plugin is disabled by default**
+
+ Component type declarations have been automatically generated for the template project. If you add and use new components, follow the instructions in the screenshot to enable automatic generation. After automatic generation is complete, remember to set it back to `false` to avoid conflicts.
+
+ 
+
+- **Blank page when accessing the project**
+
+ Try upgrading your browser, as older browser engines may not support certain new JavaScript syntax, such as optional chaining operator `?.`.
+
+- **Project synchronization with repository updates**
+
+ After synchronizing the project with repository updates, it is recommended to run `pnpm install` to update dependencies before starting.
+
+- **Red highlight on project components, functions, and imports**
+
+ Restart VSCode to try again.
+
+- **Other issues**
+
+ If you have any other issues or suggestions, please open an [ISSUE](https://gitee.com/youlaiorg/vue3-element-admin/issues/new).
+
+
+## Commit Conventions
+
+Execute `pnpm run commit` to invoke interactive git commit and complete the information input and selection according to the prompts.
+
+
+
+
+## Project Statistics
+
+
+
+
+Thanks to all the contributors!
+
+[](https://github.com/youlaitech/vue3-element-admin/graphs/contributors)
+
+
+## Special Thanks
+
+- Thanks to the [GitCode](https://gitcode.com/) official [G-Star](https://gitcode.com/g-star) certification
+ 
+
+## Community
+
+① Follow the "Youlai Tech" WeChat Official Account, click the **Group Chat** menu to get the QR code (this measure is taken to prevent ads from entering the group, thanks for your understanding and support).
+
+② Directly add WeChat **`haoxianrui`** with a note indicating "Frontend/Backend/Full Stack".
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..70cf5dc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,221 @@
+
+
+
vue3-element-admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 项目简介
+
+[vue3-element-admin](https://gitcode.com/youlai/vue3-element-admin) 基于 Vue3、Vite、TypeScript 和 Element-Plus 搭建的极简开箱即用企业级后台管理前端模板。 配套 Java 后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) 和 Node 后端 [youlai-nest](https://gitee.com/youlaiorg/youlai-nest) 。 提供开发简版[vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) 和 JS 版本[vue3-element-admin-js](https://gitee.com/youlaiorg/vue3-element-admin) 供开发者快速开发。
+
+
+## 项目特色
+
+- **简洁易用**:基于 [vue-element-admin](https://gitee.com/panjiachen/vue-element-admin) 升级的 Vue3 版本,无过渡封装 ,易上手。
+- **数据交互**: 支持 `Mock` 数据和[线上接口文档](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5),并提供配套的 [Java](https://gitee.com/youlaiorg/youlai-boot) 和 [Node](https://gitee.com/youlaiorg/youlai-nest) 后端源码。
+
+- **系统功能:** 提供用户管理、角色管理、菜单管理、部门管理、字典管理等功能模块。
+- **权限管理:** 支持动态路由、按钮权限、角色权限和数据权限等多种权限管理方式。
+
+- **基础设施:** 提供国际化、多布局、暗黑模式、全屏、水印、接口文档和代码生成器等功能。
+- **持续更新**:项目持续开源更新,实时更新工具和依赖。
+
+
+## 项目截图
+
+🖥️ **控制台**
+
+
+
+⚡**接口文档**
+
+
+
+📲 **移动端**
+
+
+
+## 项目源码
+
+| 项目 | Gitee | Github | GitCode|
+| ---- | ----| ---- | ---- |
+| vue3-element-admin ✅| [vue3-element-admin](https://gitee.com/youlaiorg/vue3-element-admin) | [vue3-element-admin](https://github.com/youlaitech/vue3-element-admin) | [vue3-element-admin](https://gitcode.com/youlai/vue3-element-admin) |
+| vue3-element-admin JS版| [vue3-element-admin-js](https://gitee.com/youlaiorg/vue3-element-admin-js) | [vue3-element-admin-js](https://github.com/youlaitech/vue3-element-admin-js) | [vue3-element-admin-js](https://gitcode.com/youlai/vue3-element-admin-js) |
+| vue3-element-admin 精简版 | [vue3-element-template](https://gitee.com/youlaiorg/vue3-element-template) | [vue3-element-template](https://github.com/youlaitech/vue3-element-template) |[vue3-element-template](https://gitcode.com/youlai/vue3-element-template)|
+| vue-uniapp-admin 移动版 | [vue-uniapp-admin](https://gitee.com/youlaiorg/vue-uniapp-admin) | [vue-uniapp-admin](https://github.com/youlaitech/vue-uniapp-admin) |[vue-uniapp-admin](https://gitcode.com/youlai/vue-uniapp-admin)|
+| Java 后端 | [youlai-boot](https://gitee.com/youlaiorg/youlai-boot) | [youlai-boot](https://github.com/haoxianrui/youlai-boot.git) |[youlai-boot](https://gitcode.com/youlai/youlai-boot.git)|
+| Node 后端 | [youlai-nest](https://gitee.com/youlaiorg/youlai-nest) | [youlai-nest](https://github.com/haoxianrui/youlai-nest.git) |[youlai-nest](https://gitcode.com/youlai/youlai-nest.git)|
+
+
+
+## 开发指南
+
+| 名称 | 地址 |
+|---------------|--------------------|
+| 视频教程 | [https://www.bilibili.com/video/BV1eFUuYyEFj](https://www.bilibili.com/video/BV1eFUuYyEFj) |
+| 项目搭建 | [基于 Vue3 + Vite + TypeScript + Element-Plus 从0到1搭建后台管理系统](https://blog.csdn.net/u013737132/article/details/130191394) |
+| 官方文档 | [https://www.youlai.tech/vue3-element-admin/](https://www.youlai.tech/vue3-element-admin/) |
+| 代码规范 | [ESLint V9 + Prettier + Stylelint + EditorConfig 约束和统一前端代码规范](https://youlai.blog.csdn.net/article/details/145608723) |
+| 提交规范 | [Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交规范](https://youlai.blog.csdn.net/article/details/145615236) |
+| 接口文档 | [https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5) |
+
+
+
+## 项目启动
+
+
+- **环境准备**
+
+| 环境类型 | 名称 |
+|----------------|-----------------------------|
+| **开发工具** | [Visual Studio Code](https://code.visualstudio.com/Download) |
+| **运行环境** | Node 18 + (推荐[22.9.0](https://npmmirror.com/mirrors/node/v22.9.0/)) |
+> ⚠️ 注意:Node.js 20.6.0版本存在兼容性问题,请勿使用
+
+
+- **快速开始**
+
+```bash
+# 克隆代码
+git clone https://gitee.com/youlaiorg/vue3-element-admin.git
+
+# 切换目录
+cd vue3-element-admin
+
+# 安装 pnpm
+npm install pnpm -g
+
+# 设置镜像源(可忽略)
+pnpm config set registry https://registry.npmmirror.com
+
+# 安装依赖
+pnpm install
+
+# 启动运行
+pnpm run dev
+```
+
+
+## 项目部署
+
+执行 `pnpm run build` 命令后,项目将被打包并生成 `dist` 目录。接下来,将 `dist` 目录下的文件上传到服务器 `/usr/share/nginx/html` 目录下,并配置 Nginx 进行反向代理。
+
+```bash
+pnpm run build
+```
+
+以下是 Nginx 的配置示例:
+
+```nginx
+server {
+ listen 80;
+ server_name localhost;
+
+ location / {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ }
+
+ # 反向代理配置
+ location /prod-api/ {
+ # 请将 api.youlai.tech 替换为您的后端 API 地址,并注意保留后面的斜杠 /
+ proxy_pass http://api.youlai.tech/;
+ }
+}
+```
+
+更多详细信息,请参考这篇文章:[Nginx 安装和配置](https://blog.csdn.net/u013737132/article/details/145667694)。
+
+## 本地Mock
+
+项目同时支持在线和本地 Mock 接口,默认使用线上接口,如需替换为 Mock 接口,修改文件 `.env.development` 的 `VITE_MOCK_DEV_SERVER` 为 `true` **即可**。
+
+## 后端接口
+
+> 如果您具备Java开发基础,按照以下步骤将在线接口转为本地后端接口,创建企业级前后端分离开发环境,助您走向全栈之路。
+
+1. 获取基于 `Java` 和 `SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码。
+2. 根据后端工程的说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动。
+3. 修改 `.env.development` 文件中的 `VITE_APP_API_URL` 的值,将其从 https://api.youlai.tech 更改为 http://localhost:8989 即可。
+
+
+## 注意事项
+
+- **自动导入插件自动生成默认关闭**
+
+ 模板项目的组件类型声明已自动生成。如果添加和使用新的组件,请按照图示方法开启自动生成。在自动生成完成后,记得将其设置为 `false`,避免重复执行引发冲突。
+
+ 
+
+- **项目启动浏览器访问空白**
+
+ 请升级浏览器尝试,低版本浏览器内核可能不支持某些新的 JavaScript 语法,比如可选链操作符 `?.`。
+
+- **项目同步仓库更新升级**
+
+ 项目同步仓库更新升级之后,建议 `pnpm install` 安装更新依赖之后启动 。
+
+- **项目组件、函数和引用爆红**
+
+ 重启 VSCode 尝试
+
+- **其他问题**
+
+ 如果有其他问题或者建议,建议 [ISSUE](https://gitee.com/youlaiorg/vue3-element-admin/issues/new)
+
+
+## 提交规范
+
+执行 `pnpm run commit` 唤起 git commit 交互,根据提示完成信息的输入和选择。
+
+
+
+
+## 项目统计
+
+
+
+
+Thanks to all the contributors!
+
+[](https://github.com/youlaitech/vue3-element-admin/graphs/contributors)
+
+
+## 特别感谢
+
+- 感谢 [GitCode](https://gitcode.com/) 官方的 [G-Star](https://gitcode.com/g-star) 认证
+ 
+
+## 加群交流
+
+① 关注「有来技术」公众号,点击菜单 **交流群** 获取加群二维码(此举防止广告进群,感谢理解和支持)。
+
+② 直接添加微信 **`haoxianrui`** 备注「前端/后端/全栈」。
+
+
diff --git a/commitlint.config.cjs b/commitlint.config.cjs
new file mode 100644
index 0000000..5f556e2
--- /dev/null
+++ b/commitlint.config.cjs
@@ -0,0 +1,93 @@
+module.exports = {
+ // 继承的规则
+ extends: ["@commitlint/config-conventional"],
+ // 自定义规则
+ rules: {
+ // @see https://commitlint.js.org/#/reference-rules
+
+ // 提交类型枚举,git提交type必须是以下类型
+ "type-enum": [
+ 2,
+ "always",
+ [
+ "feat", // 新增功能
+ "fix", // 修复缺陷
+ "docs", // 文档变更
+ "style", // 代码格式(不影响功能,例如空格、分号等格式修正)
+ "refactor", // 代码重构(不包括 bug 修复、功能新增)
+ "perf", // 性能优化
+ "test", // 添加疏漏测试或已有测试改动
+ "build", // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
+ "ci", // 修改 CI 配置、脚本
+ "revert", // 回滚 commit
+ "chore", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
+ "wip", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
+ ],
+ ],
+ "subject-case": [0], // subject大小写不做校验
+ },
+
+ prompt: {
+ messages: {
+ type: "选择你要提交的类型 :",
+ scope: "选择一个提交范围(可选):",
+ customScope: "请输入自定义的提交范围 :",
+ subject: "填写简短精炼的变更描述 :\n",
+ body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
+ breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
+ footerPrefixesSelect: "选择关联issue前缀(可选):",
+ customFooterPrefix: "输入自定义issue前缀 :",
+ footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
+ generatingByAI: "正在通过 AI 生成你的提交简短描述...",
+ generatedSelectByAI: "选择一个 AI 生成的简短描述:",
+ confirmCommit: "是否提交或修改commit ?",
+ },
+ // prettier-ignore
+ types: [
+ { value: "feat", name: "特性: ✨ 新增功能", emoji: ":sparkles:" },
+ { value: "fix", name: "修复: 🐛 修复缺陷", emoji: ":bug:" },
+ { value: "docs", name: "文档: 📝 文档变更(更新README文件,或者注释)", emoji: ":memo:" },
+ { value: "style", name: "格式: 🌈 代码格式(空格、格式化、缺失的分号等)", emoji: ":lipstick:" },
+ { value: "refactor", name: "重构: 🔄 代码重构(不修复错误也不添加特性的代码更改)", emoji: ":recycle:" },
+ { value: "perf", name: "性能: 🚀 性能优化", emoji: ":zap:" },
+ { value: "test", name: "测试: 🧪 添加疏漏测试或已有测试改动", emoji: ":white_check_mark:"},
+ { value: "build", name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)", emoji: ":package:"},
+ { value: "ci", name: "集成: ⚙️ 修改 CI 配置、脚本", emoji: ":ferris_wheel:"},
+ { value: "revert", name: "回退: ↩️ 回滚 commit",emoji: ":rewind:"},
+ { value: "chore", name: "其他: 🛠️ 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)", emoji: ":hammer:"},
+ { value: "wip", name: "开发中: 🚧 开发阶段临时提交", emoji: ":construction:"},
+ ],
+ useEmoji: true,
+ emojiAlign: "center",
+ useAI: false,
+ aiNumber: 1,
+ themeColorCode: "",
+ scopes: [],
+ allowCustomScopes: true,
+ allowEmptyScopes: true,
+ customScopesAlign: "bottom",
+ customScopesAlias: "custom",
+ emptyScopesAlias: "empty",
+ upperCaseSubject: false,
+ markBreakingChangeMode: false,
+ allowBreakingChanges: ["feat", "fix"],
+ breaklineNumber: 100,
+ breaklineChar: "|",
+ skipQuestions: [],
+ issuePrefixes: [{ value: "closed", name: "closed: ISSUES has been processed" }],
+ customIssuePrefixAlign: "top",
+ emptyIssuePrefixAlias: "skip",
+ customIssuePrefixAlias: "custom",
+ allowCustomIssuePrefix: true,
+ allowEmptyIssuePrefix: true,
+ confirmColorize: true,
+ maxHeaderLength: Infinity,
+ maxSubjectLength: Infinity,
+ minSubjectLength: 0,
+ scopeOverrides: undefined,
+ defaultBody: "",
+ defaultIssues: "",
+ defaultScope: "",
+ defaultSubject: "",
+ },
+};
diff --git a/eslint.config.ts b/eslint.config.ts
new file mode 100644
index 0000000..319b85f
--- /dev/null
+++ b/eslint.config.ts
@@ -0,0 +1,176 @@
+// https://eslint.org/docs/latest/use/configure/configuration-files-new
+
+import eslint from "@eslint/js";
+import pluginVue from "eslint-plugin-vue";
+import pluginTypeScript from "@typescript-eslint/eslint-plugin";
+import parserTypeScript from "@typescript-eslint/parser";
+import vueParser from "vue-eslint-parser";
+import globals from "globals";
+import configPrettier from "eslint-config-prettier";
+
+// 解析自动导入配置
+import fs from "node:fs";
+let autoImportGlobals = {};
+try {
+ autoImportGlobals =
+ JSON.parse(fs.readFileSync("./.eslintrc-auto-import.json", "utf-8")).globals || {};
+} catch (error) {
+ // 文件不存在或解析错误时使用空对象
+ console.warn("Could not load auto-import globals", error);
+}
+
+// Element Plus组件
+const elementPlusComponents = {
+ // Element Plus 组件添加为全局变量,避免 no-undef 报错
+ ElInput: "readonly",
+ ElSelect: "readonly",
+ ElSwitch: "readonly",
+ ElCascader: "readonly",
+ ElInputNumber: "readonly",
+ ElTimePicker: "readonly",
+ ElTimeSelect: "readonly",
+ ElDatePicker: "readonly",
+ ElTreeSelect: "readonly",
+ ElText: "readonly",
+ ElRadioGroup: "readonly",
+ ElCheckboxGroup: "readonly",
+ ElOption: "readonly",
+ ElRadio: "readonly",
+ ElCheckbox: "readonly",
+ ElInputTag: "readonly",
+ ElForm: "readonly",
+ ElFormItem: "readonly",
+ ElTable: "readonly",
+ ElTableColumn: "readonly",
+ ElButton: "readonly",
+ ElDialog: "readonly",
+ ElPagination: "readonly",
+ ElMessage: "readonly",
+ ElMessageBox: "readonly",
+ ElNotification: "readonly",
+ ElTree: "readonly",
+};
+
+export default [
+ // 全局配置
+ {
+ // 指定要检查的文件
+ files: ["**/*.js", "**/*.ts", "**/*.vue"],
+ ignores: ["node_modules/**", "dist/**", "build/**"],
+ languageOptions: {
+ ecmaVersion: 2022,
+ sourceType: "module",
+ globals: {
+ ...globals.browser, // 浏览器环境全局变量
+ ...globals.node, // Node.js 环境全局变量
+ ...autoImportGlobals, // 自动导入的 API 函数
+ ...elementPlusComponents, // Element Plus 组件
+ // 全局类型定义,解决 TypeScript 中定义但 ESLint 不识别的问题
+ PageQuery: "readonly",
+ PageResult: "readonly",
+ OptionType: "readonly",
+ ResponseData: "readonly",
+ ExcelResult: "readonly",
+ TagView: "readonly",
+ AppSettings: "readonly",
+ __APP_INFO__: "readonly",
+ },
+ parser: parserTypeScript,
+ parserOptions: {
+ sourceType: "module",
+ },
+ },
+ rules: {
+ // 全局规则
+ "no-unused-vars": [
+ "error",
+ {
+ vars: "all",
+ args: "after-used",
+ ignoreRestSiblings: true,
+ argsIgnorePattern: "^_", // 忽略以下划线开头的参数
+ varsIgnorePattern: "^[A-Z][A-Z0-9_]*$", // 忽略全大写的常量/枚举
+ },
+ ],
+ // 禁用未定义变量检查,TypeScript 已处理类型检查
+ "no-undef": "off",
+ },
+ },
+
+ // 基础 JavaScript 配置
+ eslint.configs.recommended,
+
+ // Vue 配置
+ {
+ files: ["**/*.vue"],
+ plugins: {
+ vue: pluginVue,
+ },
+ languageOptions: {
+ parser: vueParser,
+ parserOptions: {
+ ecmaVersion: 2022,
+ sourceType: "module",
+ parser: parserTypeScript,
+ },
+ },
+ processor: pluginVue.processors[".vue"],
+ rules: {
+ "vue/multi-word-component-names": "off",
+ "vue/no-v-html": "off",
+ "vue/require-default-prop": "off",
+ "vue/html-self-closing": [
+ "error",
+ {
+ html: {
+ void: "always",
+ normal: "never",
+ component: "always",
+ },
+ },
+ ],
+ "vue/no-unused-vars": "off",
+ },
+ },
+
+ // TypeScript 配置
+ {
+ files: ["**/*.ts", "**/*.tsx", "**/*.vue"],
+ plugins: {
+ "@typescript-eslint": pluginTypeScript,
+ },
+ rules: {
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/no-empty-function": "off",
+ "@typescript-eslint/no-empty-object-type": "off",
+ "@typescript-eslint/ban-ts-comment": "off",
+ "@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ vars: "all",
+ args: "after-used",
+ ignoreRestSiblings: true,
+ argsIgnorePattern: "^_", // 忽略以下划线开头的参数
+ varsIgnorePattern: "^[A-Z][A-Z0-9_]*$", // 忽略全大写的常量/枚举
+ },
+ ],
+ },
+ },
+
+ // CURD 组件配置
+ {
+ files: ["**/components/CURD/**/*.{ts,vue}"],
+ rules: {
+ "no-unused-vars": "off",
+ "@typescript-eslint/no-unused-vars": "off",
+ },
+ },
+
+ // Prettier 集成
+ {
+ rules: {
+ ...configPrettier.rules,
+ },
+ },
+];
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..82beb14
--- /dev/null
+++ b/index.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+ 红与蓝授权管理系统
+
+
+
+
+
+
+
+
+
diff --git a/mock/auth.mock.ts b/mock/auth.mock.ts
new file mode 100644
index 0000000..153142c
--- /dev/null
+++ b/mock/auth.mock.ts
@@ -0,0 +1,44 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "auth/captcha",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ captchaKey: "534b8ef2b0a24121bec76391ddd159f9",
+ captchaBase64:
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAAkCAIAAADNSmkJAAAFKUlEQVR4Xu2ZXUwcVRiGV70wMWo08V5NvPXCrDbFaGpMaZW2hqQxaoiJTRsaMBCNSYtpa2JTKiFSelFa+Q/QZcMWqEhBlh+htbEpZhMrBQrlJ0hBywLLyrJ0WZbje3bqOvPNLHPWrDvdOE9ONmfe78zkzMs335wzWJhJQrBQweS/wTQ6QWgYHdoIOcecOe05O+t2WkutO+p2ZF3Ksg/YV9ZW6FATYajR3nveg60H9327r3O8c35lHgp+r05dPdJzBL73TPSQ8SaCKIxGLsPlop+K0JHrEkPuoT31e5qGmmjARACF0agYyGVNlyVm/pzZXrN9fHGcBkz0UBid+31u93i3XFFT80vN8cvHqWqih8Lo1NpUqS5vwh3vnd223VQ10UNh9NbyrcFQUK6oCawHUipSqGqiB83oBf+CXFGDMp1mS6OqiR4Ko7FexkpOrqhpHGw82nOUqiZ6KIzGrkRuorW0dJMmOy+hOCfYGzb2RBFv6HRO0gEJw/U7y+pgL1bwmTxexN6sZ31TdEwEhdG+gA+7EqyXpUO1uZH20cWL8hMTRt1N9tBXzCJrOIRoCPJpSO2RAp4HmtCdIfZ+2JWgEBN9LbR28seTGU0Zue1tMLp+YIAMSADzfvbkKX4/eb28j4YODiGin3heqmIlLja5hAUCu+nmGY3JWKvpMAlqNGgebsauBOvlqSX+JEx7p7EbTLen53XlzfmWUioqXikrc68Y8N2juJ/fyVsNChGHEE//rBANYWaZz+TRQqpLaBgNsPfDrgSpbS21YtV87IdjrlkX9JZbt5DOma2t9ITo5F+5glN22WwL/n+yDv00mw06orKxOqQ5+J04hhViwzAXETIcJDVm8uxZqktoGx2Nj9t43Wgaul/ERQiGQvtbWnDWgZYW9CXlQFjZ/7ciyHNn+Z2MexTimIeLz59TiIln0M1e+IbPpOAaDUnEYPTi6iqKxpbycs/qKo1tCslfKcffPn9enuMiPPY1vxO/ckeFQ4h46cdGqUWoidE/y54q5tPY5WDrGzQqIXot4BgchEE57e00IMCw2/1qZSVO/7SjA78o9INzcxsbrL+fnTnDDh9mmZn8F30oG1Hm+nABv5mQMopDS/h1HxtqTzWbABMe9sxpPoe9zezeOo1GELqWhPS8t46M0IAYHbdvR1aHbaOjbjfLz2eFhez6dba4yAfgF30o0BFVE8+Mjh/wFxPI+I5mAEHU6Ls+38vhTFwOBGhMDF8gkFpbC5ffsdv/uBs6dIj19dExEtARVXv9YNbop8NFY3aZ6gRRo+tu3IBHnzmdNCBMXldXJKPfL74WzWUJRE+coDUknqsOdZXQbAJYwluVTbOZI3Qt8GFzMwxyjo3RgBiN4fr+elXVpZGRLWXl6PdOTtJBSlBDUK/lnIrjOlrtqWYTQDJaF6FrTXu9sOa1ysrVoM5HVE1GFxZQcyJ/p+xzv6K/rbr6N6+XDpUBl0tKFIrbz78qWB6YnWFMCBld4XLBms+7df75ook/GNzb0GCV7U1Qfz9p64TyQWNjYD3qe9rj4SMJtQP3MyjSDPzWIRHPjH7X4YAvfXoPuyZf9Pbi3PcuXIh4mp3NllYC6XY79C+jl2o8PBipxjnBttn4MgMNnWgfcRJGPI2OL8hTj3LloIlmRicvBhiNykvecpqoa3RSY4DRcLAwyicuOepVR1JjgNFYHWONHL04czTX0UmNAUYD7Pr+xc4wqTHGaBb2OtZvHUmNYUazcA2J6etdUmOk0f8rTKMTxF91RG0D1SwYGwAAAABJRU5ErkJggg==",
+ },
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "auth/login",
+ method: ["POST"],
+ body: {
+ code: "00000",
+ data: {
+ accessToken:
+ "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGF0YVNjb3BlIjoxLCJ1c2VySWQiOjIsImlhdCI6MTcyODE5MzA1MiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJhZDg3NzlhZDZlYWY0OWY3OTE4M2ZmYmI5OWM4MjExMSJ9.58YHwL3sNNC22jyAmOZeSm-7MITzfHb_epBIz7LvWeA",
+ tokenType: "Bearer",
+ refreshToken:
+ "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGF0YVNjb3BlIjoxLCJ1c2VySWQiOjIsImlhdCI6MTcyODE5MzA1MiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9BRE1JTiJdLCJqdGkiOiJhZDg3NzlhZDZlYWY0OWY3OTE4M2ZmYmI5OWM4MjExMSJ9.58YHwL3sNNC22jyAmOZeSm-7MITzfHb_epBIz7LvWeA",
+ expires: null,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "auth/logout",
+ method: ["DELETE"],
+ body: {
+ code: "00000",
+ data: {},
+ msg: "string",
+ },
+ },
+]);
diff --git a/mock/base.ts b/mock/base.ts
new file mode 100644
index 0000000..e68e642
--- /dev/null
+++ b/mock/base.ts
@@ -0,0 +1,7 @@
+import path from "path";
+import { createDefineMock } from "vite-plugin-mock-dev-server";
+
+export const defineMock = createDefineMock((mock) => {
+ // 拼接url
+ mock.url = path.join(import.meta.env.VITE_APP_BASE_API + "/api/v1/", mock.url);
+});
diff --git a/mock/dept.mock.ts b/mock/dept.mock.ts
new file mode 100644
index 0000000..e9b6d1b
--- /dev/null
+++ b/mock/dept.mock.ts
@@ -0,0 +1,153 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "dept/options",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ value: 1,
+ label: "有来技术",
+ children: [
+ {
+ value: 2,
+ label: "研发部门",
+ },
+ {
+ value: 3,
+ label: "测试部门",
+ },
+ ],
+ },
+ ],
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "dept",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ id: 1,
+ parentId: 0,
+ name: "有来技术",
+ code: "YOULAI",
+ sort: 1,
+ status: 1,
+ children: [
+ {
+ id: 2,
+ parentId: 1,
+ name: "研发部门",
+ code: "RD001",
+ sort: 1,
+ status: 1,
+ children: [],
+ createTime: null,
+ updateTime: "2022-04-19 12:46",
+ },
+ {
+ id: 3,
+ parentId: 1,
+ name: "测试部门",
+ code: "QA001",
+ sort: 1,
+ status: 1,
+ children: [],
+ createTime: null,
+ updateTime: "2022-04-19 12:46",
+ },
+ ],
+ createTime: null,
+ updateTime: null,
+ },
+ ],
+ msg: "一切ok",
+ },
+ },
+
+ // 新增部门
+ {
+ url: "dept",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增部门" + body.name + "成功",
+ };
+ },
+ },
+
+ // 获取部门表单数据
+ {
+ url: "dept/:id/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: deptMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+
+ // 修改部门
+ {
+ url: "dept/:id",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改部门" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除部门
+ {
+ url: "dept/:id",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除部门" + params.id + "成功",
+ };
+ },
+ },
+]);
+
+// 部门映射表数据
+const deptMap: Record = {
+ 1: {
+ id: 1,
+ name: "有来技术",
+ code: "YOULAI",
+ parentId: 0,
+ status: 1,
+ sort: 1,
+ },
+ 2: {
+ id: 2,
+ name: "研发部门",
+ code: "RD001",
+ parentId: 1,
+ status: 1,
+ sort: 1,
+ },
+ 3: {
+ id: 3,
+ name: "测试部门",
+ code: "QA001",
+ parentId: 1,
+ status: 1,
+ sort: 1,
+ },
+};
diff --git a/mock/dict.mock.ts b/mock/dict.mock.ts
new file mode 100644
index 0000000..c108bb5
--- /dev/null
+++ b/mock/dict.mock.ts
@@ -0,0 +1,312 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "dicts/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 1,
+ name: "性别",
+ dictCode: "gender",
+ status: 1,
+ },
+ ],
+ total: 1,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ /**
+ * 字典列表
+ */
+ {
+ url: "dicts",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ value: "gender",
+ label: "性别",
+ },
+ ],
+ total: 1,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ // 新增字典
+ {
+ url: "dicts",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增字典" + body.name + "成功",
+ };
+ },
+ },
+
+ // 获取字典表单数据
+ {
+ url: "dicts/:id/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: dictMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+
+ // 修改字典
+ {
+ url: "dicts/:id",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改字典" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除字典
+ {
+ url: "dicts/:ids",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除字典" + params.ids + "成功",
+ };
+ },
+ },
+
+ //---------------------------------------------------
+ // 字典项相关接口
+ //---------------------------------------------------
+
+ // 字典项分页列表
+ {
+ url: "dicts/:dictCode/items/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 1,
+ dictCode: "gender",
+ label: "男",
+ value: "1",
+ sort: 1,
+ status: 1,
+ },
+ {
+ id: 2,
+ dictCode: "gender",
+ label: "女",
+ value: "2",
+ sort: 2,
+ status: 1,
+ },
+ {
+ id: 3,
+ dictCode: "gender",
+ label: "保密",
+ value: "0",
+ sort: 3,
+ status: 1,
+ },
+ ],
+ total: 3,
+ },
+ msg: "一切ok",
+ },
+ },
+ // 字典项列表
+ {
+ url: "dicts/:dictCode/items",
+ method: ["GET"],
+ body: ({ params }) => {
+ const dictCode = params.dictCode;
+
+ let list = null;
+
+ if (dictCode == "gender") {
+ list = [
+ {
+ value: "1",
+ label: "男",
+ },
+ {
+ value: "2",
+ label: "女",
+ },
+ {
+ value: "0",
+ label: "保密",
+ },
+ ];
+ } else if (dictCode == "notice_level") {
+ list = [
+ {
+ value: "L",
+ label: "低",
+ tag: "info",
+ },
+ {
+ value: "M",
+ label: "中",
+ tag: "warning",
+ },
+ {
+ value: "H",
+ label: "高",
+ tag: "danger",
+ },
+ ];
+ } else if (dictCode == "notice_type") {
+ list = [
+ {
+ value: "1",
+ label: "系统升级",
+ tag: "success",
+ },
+ {
+ value: "2",
+ label: "系统维护",
+ tag: "primary",
+ },
+ {
+ value: "3",
+ label: "安全警告",
+ tag: "danger",
+ },
+ {
+ value: "4",
+ label: "假期通知",
+ tag: "success",
+ },
+ {
+ value: "5",
+ label: "公司新闻",
+ tag: "primary",
+ },
+ {
+ value: "99",
+ label: "其他",
+ tag: "info",
+ },
+ ];
+ }
+
+ return {
+ code: "00000",
+ data: list,
+ msg: "一切ok",
+ };
+ },
+ },
+ // 新增字典项
+ {
+ url: "dicts/:dictCode/items",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增字典" + body.name + "成功",
+ };
+ },
+ },
+
+ // 字典项表单数据
+ {
+ url: "dicts/:dictCode/items/:itemId/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: dictItemMap[params.itemId],
+ msg: "一切ok",
+ };
+ },
+ },
+
+ // 修改字典项
+ {
+ url: "dicts/:dictCode/items/:itemId",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改字典项" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除字典
+ {
+ url: "dicts/:dictCode/items/:itemId",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除字典" + params.itemId + "成功",
+ };
+ },
+ },
+]);
+
+// 字典映射表数据
+const dictMap: Record = {
+ 1: {
+ id: 1,
+ name: "性别",
+ dictCode: "gender",
+ status: 1,
+ },
+};
+
+// 字典项映射表数据
+const dictItemMap: Record = {
+ 1: {
+ id: 1,
+ value: "1",
+ label: "男",
+ sort: 1,
+ status: 1,
+ tagType: "primary",
+ },
+ 2: {
+ id: 2,
+ value: "2",
+ label: "女",
+ sort: 2,
+ status: 1,
+ tagType: "danger",
+ },
+ 3: {
+ id: 3,
+ value: "0",
+ label: "保密",
+ sort: 3,
+ status: 1,
+ tagType: "info",
+ },
+};
diff --git a/mock/log.mock.ts b/mock/log.mock.ts
new file mode 100644
index 0000000..b75963e
--- /dev/null
+++ b/mock/log.mock.ts
@@ -0,0 +1,207 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "logs/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 36192,
+ module: "菜单",
+ content: "菜单列表",
+ requestUri: "/api/v1/menus",
+ method: null,
+ ip: "183.156.148.241",
+ region: "浙江省 杭州市",
+ browser: "Chrome 109.0.0.0",
+ os: "OSX",
+ executionTime: 5,
+ createBy: null,
+ createTime: "2024-07-07 20:38:47",
+ operator: "系统管理员",
+ },
+ {
+ id: 36190,
+ module: "字典",
+ content: "字典分页列表",
+ requestUri: "/api/v1/dict/page",
+ method: null,
+ ip: "183.156.148.241",
+ region: "浙江省 杭州市",
+ browser: "Chrome 109.0.0.0",
+ os: "OSX",
+ executionTime: 9,
+ createBy: null,
+ createTime: "2024-07-07 20:38:45",
+ operator: "系统管理员",
+ },
+ {
+ id: 36193,
+ module: "部门",
+ content: "部门列表",
+ requestUri: "/api/v1/dept",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 27,
+ createBy: null,
+ createTime: "2024-07-07 20:38:45",
+ operator: "系统管理员",
+ },
+ {
+ id: 36191,
+ module: "菜单",
+ content: "菜单列表",
+ requestUri: "/api/v1/menus",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 39,
+ createBy: null,
+ createTime: "2024-07-07 20:38:44",
+ operator: "系统管理员",
+ },
+ {
+ id: 36189,
+ module: "角色",
+ content: "角色分页列表",
+ requestUri: "/api/v1/roles/page",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 55,
+ createBy: null,
+ createTime: "2024-07-07 20:38:43",
+ operator: "系统管理员",
+ },
+ {
+ id: 36188,
+ module: "用户",
+ content: "用户分页列表",
+ requestUri: "/api/v1/users/page",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 92,
+ createBy: null,
+ createTime: "2024-07-07 20:38:42",
+ operator: "系统管理员",
+ },
+ {
+ id: 36187,
+ module: "登录",
+ content: "登录",
+ requestUri: "/api/v1/auth/login",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 19340,
+ createBy: null,
+ createTime: "2024-07-07 20:38:09",
+ operator: "系统管理员",
+ },
+ {
+ id: 36186,
+ module: "登录",
+ content: "登录",
+ requestUri: "/api/v1/auth/login",
+ method: null,
+ ip: "192.168.31.134",
+ region: "0 内网IP",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 19869,
+ createBy: null,
+ createTime: "2024-07-07 20:37:59",
+ operator: "系统管理员",
+ },
+ {
+ id: 36185,
+ module: "登录",
+ content: "登录",
+ requestUri: "/api/v1/auth/login",
+ method: null,
+ ip: "112.103.111.59",
+ region: "黑龙江省 哈尔滨市",
+ browser: "Chrome 97.0.4692.98",
+ os: "Android",
+ executionTime: 96,
+ createBy: null,
+ createTime: "2024-07-07 20:37:21",
+ operator: "系统管理员",
+ },
+ {
+ id: 36184,
+ module: "登录",
+ content: "登录",
+ requestUri: "/api/v1/auth/login",
+ method: null,
+ ip: "114.86.204.190",
+ region: "上海 上海市",
+ browser: "Chrome 125.0.0.0",
+ os: "Windows 10 or Windows Server 2016",
+ executionTime: 89,
+ createBy: null,
+ createTime: "2024-07-07 20:29:37",
+ operator: "系统管理员",
+ },
+ ],
+ total: 36188,
+ },
+ msg: "一切ok",
+ },
+ },
+ {
+ url: "logs/visit-trend",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ dates: [
+ "2024-06-30",
+ "2024-07-01",
+ "2024-07-02",
+ "2024-07-03",
+ "2024-07-04",
+ "2024-07-05",
+ "2024-07-06",
+ "2024-07-07",
+ ],
+ pvList: [1751, 5168, 4882, 5301, 4721, 4885, 1901, 1003],
+ uvList: null,
+ ipList: [207, 566, 565, 631, 579, 496, 222, 152],
+ },
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "logs/visit-stats",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ todayPvCount: 1629,
+ totalPvCount: 286086,
+ pvGrowthRate: -0.65,
+ todayIpCount: 169,
+ totalIpCount: 19985,
+ ipGrowthRate: -0.57,
+ },
+ msg: "一切ok",
+ },
+ },
+]);
diff --git a/mock/menu.mock.ts b/mock/menu.mock.ts
new file mode 100644
index 0000000..02d72db
--- /dev/null
+++ b/mock/menu.mock.ts
@@ -0,0 +1,2082 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "menus/routes",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ path: "/system",
+ component: "Layout",
+ redirect: "/system/user",
+ name: "/system",
+ meta: {
+ title: "系统管理",
+ icon: "system",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "user",
+ component: "system/user/index",
+ name: "User",
+ meta: {
+ title: "用户管理",
+ icon: "el-icon-User",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "role",
+ component: "system/role/index",
+ name: "Role",
+ meta: {
+ title: "角色管理",
+ icon: "role",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "menu",
+ component: "system/menu/index",
+ name: "SysMenu",
+ meta: {
+ title: "菜单管理",
+ icon: "menu",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "dept",
+ component: "system/dept/index",
+ name: "Dept",
+ meta: {
+ title: "部门管理",
+ icon: "tree",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "dict",
+ component: "system/dict/index",
+ name: "Dict",
+ meta: {
+ title: "字典管理",
+ icon: "dict",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "log",
+ component: "system/log/index",
+ name: "Log",
+ meta: {
+ title: "系统日志",
+ icon: "document",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "dict-item",
+ component: "system/dict/dict-item",
+ name: "DictItem",
+ meta: {
+ title: "字典项",
+ icon: "",
+ hidden: true,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "config",
+ component: "system/config/index",
+ name: "Config",
+ meta: {
+ title: "系统配置",
+ icon: "setting",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "notice",
+ component: "system/notice/index",
+ name: "Notice",
+ meta: {
+ title: "通知公告",
+ icon: "",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ {
+ path: "/codegen",
+ component: "Layout",
+ name: "/codegen",
+ meta: {
+ title: "系统工具",
+ icon: "menu",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "codegen",
+ component: "codegen/index",
+ name: "Codegen",
+ meta: {
+ title: "代码生成",
+ icon: "code",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ {
+ path: "/api",
+ component: "Layout",
+ name: "/api",
+ meta: {
+ title: "接口文档",
+ icon: "api",
+ hidden: false,
+ alwaysShow: true,
+ params: null,
+ },
+ children: [
+ {
+ path: "apifox",
+ component: "demo/api/apifox",
+ name: "Apifox",
+ meta: {
+ title: "Apifox",
+ icon: "api",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ {
+ path: "/doc",
+ component: "Layout",
+ redirect: "https://juejin.cn/post/7228990409909108793",
+ name: "/doc",
+ meta: {
+ title: "平台文档",
+ icon: "document",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "internal-doc",
+ component: "demo/internal-doc",
+ name: "InternalDoc",
+ meta: {
+ title: "document",
+ icon: "document",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "https://juejin.cn/post/7228990409909108793",
+ name: "Https://juejin.cn/post/7228990409909108793",
+ meta: {
+ title: "平台文档(外链)",
+ icon: "link",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ {
+ path: "/multi-level",
+ component: "Layout",
+ name: "/multiLevel",
+ meta: {
+ title: "多级菜单",
+ icon: "cascader",
+ hidden: false,
+ alwaysShow: true,
+ params: null,
+ },
+ children: [
+ {
+ path: "multi-level1",
+ component: "demo/multi-level/level1",
+ name: "MultiLevel1",
+ meta: {
+ title: "菜单一级",
+ icon: "",
+ hidden: false,
+ alwaysShow: true,
+ params: null,
+ },
+ children: [
+ {
+ path: "multi-level2",
+ component: "demo/multi-level/children/level2",
+ name: "MultiLevel2",
+ meta: {
+ title: "菜单二级",
+ icon: "",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "multi-level3-1",
+ component: "demo/multi-level/children/children/level3-1",
+ name: "MultiLevel31",
+ meta: {
+ title: "菜单三级-1",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "multi-level3-2",
+ component: "demo/multi-level/children/children/level3-2",
+ name: "MultiLevel32",
+ meta: {
+ title: "菜单三级-2",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ path: "/component",
+ component: "Layout",
+ name: "/component",
+ meta: {
+ title: "组件封装",
+ icon: "menu",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "curd",
+ component: "demo/curd/index",
+ name: "Curd",
+ meta: {
+ title: "增删改查",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "table-select",
+ component: "demo/table-select/index",
+ name: "TableSelect",
+ meta: {
+ title: "列表选择器",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "wang-editor",
+ component: "demo/wang-editor",
+ name: "WangEditor",
+ meta: {
+ title: "富文本编辑器",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "upload",
+ component: "demo/upload",
+ name: "Upload",
+ meta: {
+ title: "图片上传",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "dict-demo",
+ component: "demo/dictionary",
+ name: "DictDemo",
+ meta: {
+ title: "字典组件",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "icon-selector",
+ component: "demo/icon-selector",
+ name: "IconSelector",
+ meta: {
+ title: "图标选择器",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "drag",
+ component: "demo/drag",
+ name: "Drag",
+ meta: {
+ title: "拖拽组件",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "text-scroll",
+ component: "demo/text-scroll",
+ name: "TextScroll",
+ meta: {
+ title: "滚动文本",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ {
+ path: "/route-param",
+ component: "Layout",
+ name: "/routeParam",
+ meta: {
+ title: "路由参数",
+ icon: "el-icon-ElementPlus",
+ hidden: false,
+ alwaysShow: true,
+ params: null,
+ },
+ children: [
+ {
+ path: "route-param-type1",
+ component: "demo/route-param",
+ name: "RouteParamType1",
+ meta: {
+ title: "参数(type=1)",
+ icon: "el-icon-Star",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: {
+ type: "1",
+ },
+ },
+ },
+ {
+ path: "route-param-type2",
+ component: "demo/route-param",
+ name: "RouteParamType2",
+ meta: {
+ title: "参数(type=2)",
+ icon: "el-icon-StarFilled",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: {
+ type: "2",
+ },
+ },
+ },
+ ],
+ },
+ {
+ path: "/function",
+ component: "Layout",
+ name: "/function",
+ meta: {
+ title: "功能演示",
+ icon: "menu",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ children: [
+ {
+ path: "icon-demo",
+ component: "demo/icons",
+ name: "IconDemo",
+ meta: {
+ title: "Icons",
+ icon: "el-icon-Notification",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "/function/websocket",
+ component: "demo/websocket",
+ name: "/function/websocket",
+ meta: {
+ title: "Websocket",
+ icon: "",
+ hidden: false,
+ keepAlive: true,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ {
+ path: "other/:id",
+ component: "demo/other",
+ name: "Other/:id",
+ meta: {
+ title: "敬请期待...",
+ icon: "",
+ hidden: false,
+ alwaysShow: false,
+ params: null,
+ },
+ },
+ ],
+ },
+ ],
+ msg: "一切ok",
+ },
+ },
+
+ // 获取菜单树形表格列表
+ {
+ url: "menus",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ id: 1,
+ parentId: 0,
+ name: "系统管理",
+ type: "CATALOG",
+ routeName: "",
+ routePath: "/system",
+ component: "Layout",
+ sort: 1,
+ visible: 1,
+ icon: "system",
+ redirect: "/system/user",
+ perm: null,
+ children: [
+ {
+ id: 2,
+ parentId: 1,
+ name: "用户管理",
+ type: "MENU",
+ routeName: "User",
+ routePath: "user",
+ component: "system/user/index",
+ sort: 1,
+ visible: 1,
+ icon: "el-icon-User",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 105,
+ parentId: 2,
+ name: "用户查询",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 0,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:user:query",
+ children: [],
+ },
+ {
+ id: 31,
+ parentId: 2,
+ name: "用户新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: "sys:user:add",
+ children: [],
+ },
+ {
+ id: 32,
+ parentId: 2,
+ name: "用户编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: "sys:user:edit",
+ children: [],
+ },
+ {
+ id: 33,
+ parentId: 2,
+ name: "用户删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: "sys:user:delete",
+ children: [],
+ },
+ {
+ id: 88,
+ parentId: 2,
+ name: "重置密码",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:user:password:reset",
+ children: [],
+ },
+ {
+ id: 106,
+ parentId: 2,
+ name: "用户导入",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 5,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:user:import",
+ children: [],
+ },
+ {
+ id: 107,
+ parentId: 2,
+ name: "用户导出",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 6,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:user:export",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 3,
+ parentId: 1,
+ name: "角色管理",
+ type: "MENU",
+ routeName: "Role",
+ routePath: "role",
+ component: "system/role/index",
+ sort: 2,
+ visible: 1,
+ icon: "role",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 70,
+ parentId: 3,
+ name: "角色新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:role:add",
+ children: [],
+ },
+ {
+ id: 71,
+ parentId: 3,
+ name: "角色编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:role:edit",
+ children: [],
+ },
+ {
+ id: 72,
+ parentId: 3,
+ name: "角色删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:role:delete",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 4,
+ parentId: 1,
+ name: "菜单管理",
+ type: "MENU",
+ routeName: "Menu",
+ routePath: "menu",
+ component: "system/menu/index",
+ sort: 3,
+ visible: 1,
+ icon: "menu",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 73,
+ parentId: 4,
+ name: "菜单新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:menu:add",
+ children: [],
+ },
+ {
+ id: 74,
+ parentId: 4,
+ name: "菜单编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:menu:edit",
+ children: [],
+ },
+ {
+ id: 75,
+ parentId: 4,
+ name: "菜单删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:menu:delete",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 5,
+ parentId: 1,
+ name: "部门管理",
+ type: "MENU",
+ routeName: "Dept",
+ routePath: "dept",
+ component: "system/dept/index",
+ sort: 4,
+ visible: 1,
+ icon: "tree",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 76,
+ parentId: 5,
+ name: "部门新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dept:add",
+ children: [],
+ },
+ {
+ id: 77,
+ parentId: 5,
+ name: "部门编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dept:edit",
+ children: [],
+ },
+ {
+ id: 78,
+ parentId: 5,
+ name: "部门删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dept:delete",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 6,
+ parentId: 1,
+ name: "字典管理",
+ type: "MENU",
+ routeName: "Dict",
+ routePath: "dict",
+ component: "system/dict/index",
+ sort: 5,
+ visible: 1,
+ icon: "dict",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 79,
+ parentId: 6,
+ name: "字典新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict:add",
+ children: [],
+ },
+ {
+ id: 81,
+ parentId: 6,
+ name: "字典编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict_type:edit",
+ children: [],
+ },
+ {
+ id: 84,
+ parentId: 6,
+ name: "字典删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict_type:delete",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 135,
+ parentId: 1,
+ name: "字典项",
+ type: "MENU",
+ routeName: "DictData",
+ routePath: "dict-item",
+ component: "system/dict/dict-item",
+ sort: 6,
+ visible: 0,
+ icon: "",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 136,
+ parentId: 135,
+ name: "字典项新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict-item:add",
+ children: [],
+ },
+ {
+ id: 137,
+ parentId: 135,
+ name: "字典项编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 5,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict-item:edit",
+ children: [],
+ },
+ {
+ id: 138,
+ parentId: 135,
+ name: "字典项删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 6,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:dict-item:delete",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 117,
+ parentId: 1,
+ name: "系统日志",
+ type: "MENU",
+ routeName: "Log",
+ routePath: "log",
+ component: "system/log/index",
+ sort: 6,
+ visible: 1,
+ icon: "document",
+ redirect: null,
+ perm: null,
+ children: [],
+ },
+ {
+ id: 120,
+ parentId: 1,
+ name: "系统配置",
+ type: "MENU",
+ routeName: "Config",
+ routePath: "config",
+ component: "system/config/index",
+ sort: 7,
+ visible: 1,
+ icon: "setting",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 121,
+ parentId: 120,
+ name: "查询系统配置",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:config:query",
+ children: [],
+ },
+ {
+ id: 122,
+ parentId: 120,
+ name: "新增系统配置",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:config:add",
+ children: [],
+ },
+ {
+ id: 123,
+ parentId: 120,
+ name: "修改系统配置",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:config:update",
+ children: [],
+ },
+ {
+ id: 124,
+ parentId: 120,
+ name: "删除系统配置",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:config:delete",
+ children: [],
+ },
+ {
+ id: 125,
+ parentId: 120,
+ name: "刷新系统配置",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 5,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:config:refresh",
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 126,
+ parentId: 1,
+ name: "通知公告",
+ type: "MENU",
+ routeName: "Notice",
+ routePath: "notice",
+ component: "system/notice/index",
+ sort: 9,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 127,
+ parentId: 126,
+ name: "查询",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:query",
+ children: [],
+ },
+ {
+ id: 128,
+ parentId: 126,
+ name: "新增",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:add",
+ children: [],
+ },
+ {
+ id: 129,
+ parentId: 126,
+ name: "编辑",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:edit",
+ children: [],
+ },
+ {
+ id: 130,
+ parentId: 126,
+ name: "删除",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:delete",
+ children: [],
+ },
+ {
+ id: 133,
+ parentId: 126,
+ name: "发布",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 5,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:publish",
+ children: [],
+ },
+ {
+ id: 134,
+ parentId: 126,
+ name: "撤回",
+ type: "BUTTON",
+ routeName: null,
+ routePath: "",
+ component: null,
+ sort: 6,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: "sys:notice:revoke",
+ children: [],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 118,
+ parentId: 0,
+ name: "系统工具",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/codegen",
+ component: "Layout",
+ sort: 2,
+ visible: 1,
+ icon: "menu",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 119,
+ parentId: 118,
+ name: "代码生成",
+ type: "MENU",
+ routeName: "Codegen",
+ routePath: "codegen",
+ component: "codegen/index",
+ sort: 1,
+ visible: 1,
+ icon: "code",
+ redirect: null,
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 40,
+ parentId: 0,
+ name: "接口文档",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/api",
+ component: "Layout",
+ sort: 7,
+ visible: 1,
+ icon: "api",
+ redirect: "",
+ perm: null,
+ children: [
+ {
+ id: 41,
+ parentId: 40,
+ name: "Apifox",
+ type: "MENU",
+ routeName: null,
+ routePath: "apifox",
+ component: "demo/api/apifox",
+ sort: 1,
+ visible: 1,
+ icon: "api",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 26,
+ parentId: 0,
+ name: "平台文档",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/doc",
+ component: "Layout",
+ sort: 8,
+ visible: 1,
+ icon: "document",
+ redirect: "https://juejin.cn/post/7228990409909108793",
+ perm: null,
+ children: [
+ {
+ id: 102,
+ parentId: 26,
+ name: "平台文档(内嵌)",
+ type: "EXTLINK",
+ routeName: null,
+ routePath: "internal-doc",
+ component: "demo/internal-doc",
+ sort: 1,
+ visible: 1,
+ icon: "document",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 30,
+ parentId: 26,
+ name: "平台文档(外链)",
+ type: "EXTLINK",
+ routeName: null,
+ routePath: "https://juejin.cn/post/7228990409909108793",
+ component: "",
+ sort: 2,
+ visible: 1,
+ icon: "link",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 20,
+ parentId: 0,
+ name: "多级菜单",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/multi-level",
+ component: "Layout",
+ sort: 9,
+ visible: 1,
+ icon: "cascader",
+ redirect: "",
+ perm: null,
+ children: [
+ {
+ id: 21,
+ parentId: 20,
+ name: "菜单一级",
+ type: "MENU",
+ routeName: null,
+ routePath: "multi-level1",
+ component: "demo/multi-level/level1",
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [
+ {
+ id: 22,
+ parentId: 21,
+ name: "菜单二级",
+ type: "MENU",
+ routeName: null,
+ routePath: "multi-level2",
+ component: "demo/multi-level/children/level2",
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 23,
+ parentId: 22,
+ name: "菜单三级-1",
+ type: "MENU",
+ routeName: null,
+ routePath: "multi-level3-1",
+ component: "demo/multi-level/children/children/level3-1",
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 24,
+ parentId: 22,
+ name: "菜单三级-2",
+ type: "MENU",
+ routeName: null,
+ routePath: "multi-level3-2",
+ component: "demo/multi-level/children/children/level3-2",
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 36,
+ parentId: 0,
+ name: "组件封装",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/component",
+ component: "Layout",
+ sort: 10,
+ visible: 1,
+ icon: "menu",
+ redirect: "",
+ perm: null,
+ children: [
+ {
+ id: 108,
+ parentId: 36,
+ name: "增删改查",
+ type: "MENU",
+ routeName: null,
+ routePath: "curd",
+ component: "demo/curd/index",
+ sort: 0,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 109,
+ parentId: 36,
+ name: "列表选择器",
+ type: "MENU",
+ routeName: null,
+ routePath: "table-select",
+ component: "demo/table-select/index",
+ sort: 1,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 37,
+ parentId: 36,
+ name: "富文本编辑器",
+ type: "MENU",
+ routeName: null,
+ routePath: "wang-editor",
+ component: "demo/wang-editor",
+ sort: 2,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 38,
+ parentId: 36,
+ name: "图片上传",
+ type: "MENU",
+ routeName: null,
+ routePath: "upload",
+ component: "demo/upload",
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 95,
+ parentId: 36,
+ name: "字典组件",
+ type: "MENU",
+ routeName: null,
+ routePath: "dict-demo",
+ component: "demo/dict",
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 39,
+ parentId: 36,
+ name: "图标选择器",
+ type: "MENU",
+ routeName: null,
+ routePath: "icon-selector",
+ component: "demo/icon-selector",
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 110,
+ parentId: 0,
+ name: "路由参数",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/route-param",
+ component: "Layout",
+ sort: 11,
+ visible: 1,
+ icon: "el-icon-ElementPlus",
+ redirect: null,
+ perm: null,
+ children: [
+ {
+ id: 111,
+ parentId: 110,
+ name: "参数(type=1)",
+ type: "MENU",
+ routeName: null,
+ routePath: "route-param-type1",
+ component: "demo/route-param",
+ sort: 1,
+ visible: 1,
+ icon: "el-icon-Star",
+ redirect: null,
+ perm: null,
+ children: [],
+ },
+ {
+ id: 112,
+ parentId: 110,
+ name: "参数(type=2)",
+ type: "MENU",
+ routeName: null,
+ routePath: "route-param-type2",
+ component: "demo/route-param",
+ sort: 2,
+ visible: 1,
+ icon: "el-icon-StarFilled",
+ redirect: null,
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ {
+ id: 89,
+ parentId: 0,
+ name: "功能演示",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "/function",
+ component: "Layout",
+ sort: 12,
+ visible: 1,
+ icon: "menu",
+ redirect: "",
+ perm: null,
+ children: [
+ {
+ id: 97,
+ parentId: 89,
+ name: "Icons",
+ type: "MENU",
+ routeName: null,
+ routePath: "icon-demo",
+ component: "demo/icons",
+ sort: 2,
+ visible: 1,
+ icon: "el-icon-Notification",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 90,
+ parentId: 89,
+ name: "Websocket",
+ type: "MENU",
+ routeName: null,
+ routePath: "/function/websocket",
+ component: "demo/websocket",
+ sort: 3,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ {
+ id: 91,
+ parentId: 89,
+ name: "敬请期待...",
+ type: "CATALOG",
+ routeName: null,
+ routePath: "other/:id",
+ component: "demo/other",
+ sort: 4,
+ visible: 1,
+ icon: "",
+ redirect: "",
+ perm: null,
+ children: [],
+ },
+ ],
+ },
+ ],
+ msg: "一切ok",
+ },
+ },
+
+ // 获取菜单树形下拉列表
+ {
+ url: "menus/options",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ value: "1",
+ label: "系统管理",
+ children: [
+ {
+ value: "2",
+ label: "用户管理",
+ children: [
+ {
+ value: "105",
+ label: "用户查询",
+ },
+ {
+ value: "31",
+ label: "用户新增",
+ },
+ {
+ value: "32",
+ label: "用户编辑",
+ },
+ {
+ value: "33",
+ label: "用户删除",
+ },
+ {
+ value: "88",
+ label: "重置密码",
+ },
+ {
+ value: "106",
+ label: "用户导入",
+ },
+ {
+ value: "107",
+ label: "用户导出",
+ },
+ ],
+ },
+ {
+ value: "3",
+ label: "角色管理",
+ children: [
+ {
+ value: "139",
+ label: "角色查询",
+ },
+ {
+ value: "70",
+ label: "角色新增",
+ },
+ {
+ value: "71",
+ label: "角色编辑",
+ },
+ {
+ value: "72",
+ label: "角色删除",
+ },
+ ],
+ },
+ {
+ value: "4",
+ label: "菜单管理",
+ children: [
+ {
+ value: "73",
+ label: "菜单新增",
+ },
+ {
+ value: "140",
+ label: "菜单查询",
+ },
+ {
+ value: "75",
+ label: "菜单删除",
+ },
+ {
+ value: "74",
+ label: "菜单编辑",
+ },
+ ],
+ },
+ {
+ value: "5",
+ label: "部门管理",
+ children: [
+ {
+ value: "76",
+ label: "部门新增",
+ },
+ {
+ value: "141",
+ label: "部门查询",
+ },
+ {
+ value: "77",
+ label: "部门编辑",
+ },
+ {
+ value: "78",
+ label: "部门删除",
+ },
+ ],
+ },
+ {
+ value: "6",
+ label: "字典管理",
+ children: [
+ {
+ value: "79",
+ label: "字典新增",
+ },
+ {
+ value: "142",
+ label: "字典查询",
+ },
+ {
+ value: "81",
+ label: "字典编辑",
+ },
+ {
+ value: "84",
+ label: "字典删除",
+ },
+ ],
+ },
+ {
+ value: "117",
+ label: "系统日志",
+ },
+ {
+ value: "135",
+ label: "字典项",
+ children: [
+ {
+ value: "143",
+ label: "字典项查询",
+ },
+ {
+ value: "136",
+ label: "字典项新增",
+ },
+ {
+ value: "137",
+ label: "字典项编辑",
+ },
+ {
+ value: "138",
+ label: "字典项删除",
+ },
+ ],
+ },
+ {
+ value: "120",
+ label: "系统配置",
+ children: [
+ {
+ value: "121",
+ label: "系统配置查询",
+ },
+ {
+ value: "122",
+ label: "系统配置新增",
+ },
+ {
+ value: "123",
+ label: "系统配置修改",
+ },
+ {
+ value: "124",
+ label: "系统配置删除",
+ },
+ {
+ value: "125",
+ label: "系统配置刷新",
+ },
+ ],
+ },
+ {
+ value: "126",
+ label: "通知公告",
+ children: [
+ {
+ value: "127",
+ label: "通知查询",
+ },
+ {
+ value: "128",
+ label: "通知新增",
+ },
+ {
+ value: "129",
+ label: "通知编辑",
+ },
+ {
+ value: "130",
+ label: "通知删除",
+ },
+ {
+ value: "133",
+ label: "通知发布",
+ },
+ {
+ value: "134",
+ label: "通知撤回",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ value: "118",
+ label: "系统工具",
+ children: [
+ {
+ value: "119",
+ label: "代码生成",
+ },
+ ],
+ },
+ {
+ value: "40",
+ label: "接口文档",
+ children: [
+ {
+ value: "41",
+ label: "Apifox",
+ },
+ ],
+ },
+ {
+ value: "26",
+ label: "平台文档",
+ children: [
+ {
+ value: "102",
+ label: "document",
+ },
+ {
+ value: "30",
+ label: "平台文档(外链)",
+ },
+ ],
+ },
+ {
+ value: "20",
+ label: "多级菜单",
+ children: [
+ {
+ value: "21",
+ label: "菜单一级",
+ children: [
+ {
+ value: "22",
+ label: "菜单二级",
+ children: [
+ {
+ value: "23",
+ label: "菜单三级-1",
+ },
+ {
+ value: "24",
+ label: "菜单三级-2",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ value: "36",
+ label: "组件封装",
+ children: [
+ {
+ value: "108",
+ label: "增删改查",
+ },
+ {
+ value: "109",
+ label: "列表选择器",
+ },
+ {
+ value: "37",
+ label: "富文本编辑器",
+ },
+ {
+ value: "38",
+ label: "图片上传",
+ },
+ {
+ value: "39",
+ label: "图标选择器",
+ },
+ {
+ value: "95",
+ label: "字典组件",
+ },
+ ],
+ },
+ {
+ value: "110",
+ label: "路由参数",
+ children: [
+ {
+ value: "111",
+ label: "参数(type=1)",
+ },
+ {
+ value: "112",
+ label: "参数(type=2)",
+ },
+ ],
+ },
+ {
+ value: "89",
+ label: "功能演示",
+ children: [
+ {
+ value: "97",
+ label: "Icons",
+ },
+ {
+ value: "90",
+ label: "Websocket",
+ },
+ {
+ value: "91",
+ label: "敬请期待...",
+ },
+ ],
+ },
+ ],
+
+ msg: "一切ok",
+ },
+ },
+
+ // 新增菜单
+ {
+ url: "menus",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增菜单" + body.name + "成功",
+ };
+ },
+ },
+
+ // 获取菜单表单数据
+ {
+ url: "menus/:id/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: menuMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+
+ // 修改菜单
+ {
+ url: "menus/:id",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改菜单" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除菜单
+ {
+ url: "menus/:id",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除菜单" + params.id + "成功",
+ };
+ },
+ },
+]);
+
+// 菜单映射表数据
+const menuMap: Record = {
+ 1: {
+ id: 1,
+ parentId: 0,
+ name: "系统管理",
+ type: "CATALOG",
+ routeName: "",
+ routePath: "/system",
+ component: "Layout",
+ perm: null,
+ visible: 1,
+ sort: 1,
+ icon: "system",
+ redirect: "/system/user",
+ keepAlive: null,
+ alwaysShow: null,
+ params: null,
+ },
+ 2: {
+ id: 2,
+ parentId: 1,
+ name: "用户管理",
+ type: "MENU",
+ routeName: "User",
+ routePath: "user",
+ component: "system/user/index",
+ perm: null,
+ visible: 1,
+ sort: 1,
+ icon: "user",
+ redirect: null,
+ keepAlive: 1,
+ alwaysShow: null,
+ },
+ 3: {
+ id: 3,
+ parentId: 1,
+ name: "角色管理",
+ type: "MENU",
+ routeName: "Role",
+ routePath: "role",
+ component: "system/role/index",
+ perm: null,
+ visible: 1,
+ sort: 2,
+ icon: "role",
+ redirect: null,
+ keepAlive: 1,
+ alwaysShow: null,
+ },
+ 4: {
+ id: 4,
+ parentId: 1,
+ name: "菜单管理",
+ type: "MENU",
+ routeName: "Menu",
+ routePath: "menu",
+ component: "system/menu/index",
+ perm: null,
+ visible: 1,
+ sort: 3,
+ icon: "menu",
+ redirect: null,
+ keepAlive: 1,
+ alwaysShow: null,
+ },
+ 5: {
+ id: 5,
+ parentId: 1,
+ name: "部门管理",
+ type: "MENU",
+ routeName: "Dept",
+ routePath: "dept",
+ component: "system/dept/index",
+ perm: null,
+ visible: 1,
+ sort: 4,
+ icon: "tree",
+ redirect: null,
+ keepAlive: 1,
+ alwaysShow: null,
+ },
+ 6: {
+ id: 6,
+ parentId: 1,
+ name: "字典管理",
+ type: "MENU",
+ routeName: "Dict",
+ routePath: "dict",
+ component: "system/dict/index",
+ perm: null,
+ visible: 1,
+ sort: 5,
+ icon: "dict",
+ redirect: null,
+ keepAlive: 1,
+ alwaysShow: null,
+ },
+};
diff --git a/mock/notice.mock.ts b/mock/notice.mock.ts
new file mode 100644
index 0000000..c140c16
--- /dev/null
+++ b/mock/notice.mock.ts
@@ -0,0 +1,416 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "notices/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 1,
+ title: "v2.12.0 新增系统日志,访问趋势统计功能。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:21",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 2,
+ title: "v2.13.0 新增菜单搜索。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:22",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 3,
+ title: "\r\nv2.14.0 新增个人中心。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:23",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 4,
+ title: "v2.15.0 登录页面改造。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:24",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 5,
+ title: "v2.16.0 通知公告、字典翻译组件。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:25",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 6,
+ title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
+ publishStatus: 1,
+ type: 2,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:26",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 7,
+ title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
+ publishStatus: 1,
+ type: 3,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:27",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 8,
+ title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
+ publishStatus: 1,
+ type: 4,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:28",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 9,
+ title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
+ publishStatus: 1,
+ type: 5,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:29",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ {
+ id: 10,
+ title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ publishTime: "2024-09-30 17:30",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ ],
+ total: 10,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ // 新增通知
+ {
+ url: "notices",
+ method: ["POST"],
+ body() {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增成功",
+ };
+ },
+ },
+
+ // 获取通知表单数据
+ {
+ url: "notices/:id/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: noticeMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+
+ // 获取通知详情
+ {
+ url: "notices/:id/detail",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: noticeMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+ // 修改通知
+ {
+ url: "roles/:id",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改通知" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除通知
+ {
+ url: "roles/:id",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除通知" + params.id + "成功",
+ };
+ },
+ },
+
+ // 我的通知分页列表
+ {
+ url: "notices/my-page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 10,
+ title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
+ type: 1,
+ level: "L",
+ publisherName: "系统管理员",
+ publishTime: "2024-09-30 17:30",
+ isRead: 0,
+ },
+ {
+ id: 9,
+ title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
+ type: 5,
+ level: "L",
+ publisherName: "系统管理员",
+ publishTime: "2024-09-30 17:29",
+ isRead: 0,
+ },
+ {
+ id: 8,
+ title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
+ type: 4,
+ level: "L",
+ publisherName: "系统管理员",
+ publishTime: "2024-09-30 17:28",
+ isRead: 0,
+ },
+ {
+ id: 7,
+ title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
+ type: 3,
+ level: "L",
+ publisherName: "系统管理员",
+ publishTime: "2024-09-30 17:27",
+ isRead: 0,
+ },
+ {
+ id: 6,
+ title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
+ type: 2,
+ level: "L",
+ publisherName: "系统管理员",
+ publishTime: "2024-09-30 17:26",
+ isRead: 0,
+ },
+ ],
+ total: 10,
+ },
+ msg: "一切ok",
+ },
+ },
+]);
+
+// 通知映射表数据
+const noticeMap: Record = {
+ 1: {
+ id: 1,
+ title: "v2.12.0 新增系统日志,访问趋势统计功能。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:21",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 2: {
+ id: 2,
+ title: "v2.13.0 新增菜单搜索。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:22",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 3: {
+ id: 3,
+ title: "\r\nv2.14.0 新增个人中心。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:23",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 4: {
+ id: 4,
+ title: "v2.15.0 登录页面改造。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:24",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+
+ 5: {
+ id: 5,
+ title: "v2.16.0 通知公告、字典翻译组件。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:25",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 6: {
+ id: 6,
+ title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
+ publishStatus: 1,
+ type: 2,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:26",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 7: {
+ id: 7,
+ title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
+ publishStatus: 1,
+ type: 3,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:27",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 8: {
+ id: 8,
+ title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
+ publishStatus: 1,
+ type: 4,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:28",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 9: {
+ id: 9,
+ title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
+ publishStatus: 1,
+ type: 5,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:29",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+ 10: {
+ id: 10,
+ title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
+ publishStatus: 1,
+ type: 1,
+ publisherName: "系统管理员",
+ level: "L",
+ levelLabel: null,
+ publishTime: "2024-09-30 17:30",
+ isRead: null,
+ targetType: 1,
+ createTime: "2024-09-28 11:21",
+ revokeTime: "2024-09-30 17:21",
+ },
+};
diff --git a/mock/role.mock.ts b/mock/role.mock.ts
new file mode 100644
index 0000000..ee85699
--- /dev/null
+++ b/mock/role.mock.ts
@@ -0,0 +1,334 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "roles/options",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: [
+ {
+ value: 2,
+ label: "系统管理员",
+ },
+ {
+ value: 4,
+ label: "系统管理员1",
+ },
+ {
+ value: 5,
+ label: "系统管理员2",
+ },
+ {
+ value: 6,
+ label: "系统管理员3",
+ },
+ {
+ value: 7,
+ label: "系统管理员4",
+ },
+ {
+ value: 8,
+ label: "系统管理员5",
+ },
+ {
+ value: 9,
+ label: "系统管理员6",
+ },
+ {
+ value: 10,
+ label: "系统管理员7",
+ },
+ {
+ value: 11,
+ label: "系统管理员8",
+ },
+ {
+ value: 12,
+ label: "系统管理员9",
+ },
+ {
+ value: 3,
+ label: "访问游客",
+ },
+ ],
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "roles/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 2,
+ name: "系统管理员",
+ code: "ADMIN",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 3,
+ name: "访问游客",
+ code: "GUEST",
+ status: 1,
+ sort: 3,
+ createTime: "2021-05-26 15:49:05",
+ updateTime: "2019-05-05 16:00:00",
+ },
+ {
+ id: 4,
+ name: "系统管理员1",
+ code: "ADMIN1",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 5,
+ name: "系统管理员2",
+ code: "ADMIN2",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 6,
+ name: "系统管理员3",
+ code: "ADMIN3",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 7,
+ name: "系统管理员4",
+ code: "ADMIN4",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 8,
+ name: "系统管理员5",
+ code: "ADMIN5",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 9,
+ name: "系统管理员6",
+ code: "ADMIN6",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: "2023-12-04 11:43:15",
+ },
+ {
+ id: 10,
+ name: "系统管理员7",
+ code: "ADMIN7",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ {
+ id: 11,
+ name: "系统管理员8",
+ code: "ADMIN8",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ ],
+ total: 10,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ // 新增角色
+ {
+ url: "roles",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增角色" + body.name + "成功",
+ };
+ },
+ },
+
+ // 获取角色表单数据
+ {
+ url: "roles/:id/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: roleMap[params.id],
+ msg: "一切ok",
+ };
+ },
+ },
+ // 修改角色
+ {
+ url: "roles/:id",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改角色" + body.name + "成功",
+ };
+ },
+ },
+
+ // 删除角色
+ {
+ url: "roles/:id",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除角色" + params.id + "成功",
+ };
+ },
+ },
+ // 获取角色拥有的菜单ID
+ {
+ url: "roles/:id/menuIds",
+ method: ["GET"],
+ body: ({}) => {
+ return {
+ code: "00000",
+ data: [
+ 1, 2, 31, 32, 33, 88, 3, 70, 71, 72, 4, 73, 75, 74, 5, 76, 77, 78, 6, 79, 81, 84, 85, 86,
+ 87, 40, 41, 26, 30, 20, 21, 22, 23, 24, 89, 90, 91, 36, 37, 38, 39, 93, 94, 95, 97, 102,
+ 89, 90, 91, 93, 94, 95, 97, 102, 103, 104,
+ ],
+ msg: "一切ok",
+ };
+ },
+ },
+ // 保存角色菜单
+ {
+ url: "roles/:id/menus",
+ method: ["PUT"],
+ body: {
+ code: "00000",
+ data: null,
+ msg: "一切ok",
+ },
+ },
+]);
+
+// 角色映射表数据
+const roleMap: Record = {
+ 2: {
+ id: 2,
+ name: "系统管理员",
+ code: "ADMIN",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 3: {
+ id: 3,
+ name: "访问游客",
+ code: "GUEST",
+ status: 1,
+ sort: 3,
+ createTime: "2021-05-26 15:49:05",
+ updateTime: "2019-05-05 16:00:00",
+ },
+ 4: {
+ id: 4,
+ name: "系统管理员1",
+ code: "ADMIN1",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 5: {
+ id: 5,
+ name: "系统管理员2",
+ code: "ADMIN2",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+
+ 6: {
+ id: 6,
+ name: "系统管理员3",
+ code: "ADMIN3",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 7: {
+ id: 7,
+ name: "系统管理员4",
+ code: "ADMIN4",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 8: {
+ id: 8,
+ name: "系统管理员5",
+ code: "ADMIN5",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 9: {
+ id: 9,
+ name: "系统管理员6",
+ code: "ADMIN6",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: "2023-12-04 11:43:15",
+ },
+ 10: {
+ id: 10,
+ name: "系统管理员7",
+ code: "ADMIN7",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+ 11: {
+ id: 11,
+ name: "系统管理员8",
+ code: "ADMIN8",
+ status: 1,
+ sort: 2,
+ createTime: "2021-03-25 12:39:54",
+ updateTime: null,
+ },
+};
diff --git a/mock/user.mock.ts b/mock/user.mock.ts
new file mode 100644
index 0000000..bf2fc98
--- /dev/null
+++ b/mock/user.mock.ts
@@ -0,0 +1,251 @@
+import { defineMock } from "./base";
+
+export default defineMock([
+ {
+ url: "users/me",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ userId: 2,
+ username: "admin",
+ nickname: "系统管理员",
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ roles: ["ADMIN"],
+ perms: [
+ "sys:user:query",
+ "sys:user:add",
+ "sys:user:edit",
+ "sys:user:delete",
+ "sys:user:import",
+ "sys:user:export",
+ "sys:user:reset-password",
+
+ "sys:role:query",
+ "sys:role:add",
+ "sys:role:edit",
+ "sys:role:delete",
+
+ "sys:dept:query",
+ "sys:dept:add",
+ "sys:dept:edit",
+ "sys:dept:delete",
+
+ "sys:menu:query",
+ "sys:menu:add",
+ "sys:menu:edit",
+ "sys:menu:delete",
+
+ "sys:dict:query",
+ "sys:dict:add",
+ "sys:dict:edit",
+ "sys:dict:delete",
+ "sys:dict:delete",
+
+ "sys:dict-item:query",
+ "sys:dict-item:add",
+ "sys:dict-item:edit",
+ "sys:dict-item:delete",
+
+ "sys:notice:query",
+ "sys:notice:add",
+ "sys:notice:edit",
+ "sys:notice:delete",
+ "sys:notice:revoke",
+ "sys:notice:publish",
+
+ "sys:config:query",
+ "sys:config:add",
+ "sys:config:update",
+ "sys:config:delete",
+ "sys:config:refresh",
+ ],
+ },
+ msg: "一切ok",
+ },
+ },
+
+ {
+ url: "users/page",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ list: [
+ {
+ id: 2,
+ username: "admin",
+ nickname: "系统管理员",
+ mobile: "17621210366",
+ gender: 1,
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ email: "",
+ status: 1,
+ deptId: 1,
+ roleIds: [2],
+ },
+ {
+ id: 3,
+ username: "test",
+ nickname: "测试小用户",
+ mobile: "17621210366",
+ gender: 1,
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ email: "youlaitech@163.com",
+ status: 1,
+ deptId: 3,
+ roleIds: [3],
+ },
+ ],
+ total: 2,
+ },
+ msg: "一切ok",
+ },
+ },
+
+ // 新增用户
+ {
+ url: "users",
+ method: ["POST"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "新增用户" + body.nickname + "成功",
+ };
+ },
+ },
+
+ // 获取用户表单数据
+ {
+ url: "users/:userId/form",
+ method: ["GET"],
+ body: ({ params }) => {
+ return {
+ code: "00000",
+ data: userMap[params.userId],
+ msg: "一切ok",
+ };
+ },
+ },
+ // 修改用户
+ {
+ url: "users/:userId",
+ method: ["PUT"],
+ body({ body }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改用户" + body.nickname + "成功",
+ };
+ },
+ },
+
+ // 删除用户
+ {
+ url: "users/:userId",
+ method: ["DELETE"],
+ body({ params }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "删除用户" + params.id + "成功",
+ };
+ },
+ },
+
+ // 重置密码
+ {
+ url: "users/:userId/password/reset",
+ method: ["PUT"],
+ body({ query }) {
+ return {
+ code: "00000",
+ data: null,
+ msg: "重置密码成功,新密码为:" + query.password,
+ };
+ },
+ },
+
+ // 导出Excel
+ {
+ url: "users/_export",
+ method: ["GET"],
+ headers: {
+ "Content-Disposition": "attachment; filename=%E7%94%A8%E6%88%B7%E5%88%97%E8%A1%A8.xlsx",
+ "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ },
+ },
+
+ {
+ url: "users/profile",
+ method: ["GET"],
+ body: {
+ code: "00000",
+ data: {
+ id: 2,
+ username: "admin",
+ nickname: "系统管理员",
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ gender: 1,
+ mobile: "17621210366",
+ email: null,
+ deptName: "有来技术",
+ roleNames: "系统管理员",
+ createTime: "2019-10-10",
+ },
+ },
+ },
+
+ {
+ url: "users/profile",
+ method: ["PUT"],
+ body() {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改个人信息成功",
+ };
+ },
+ },
+
+ {
+ url: "users/password",
+ method: ["PUT"],
+ body() {
+ return {
+ code: "00000",
+ data: null,
+ msg: "修改密码成功",
+ };
+ },
+ },
+]);
+
+// 用户映射表数据
+const userMap: Record = {
+ 2: {
+ id: 2,
+ username: "admin",
+ nickname: "系统管理员",
+ mobile: "17621210366",
+ gender: 1,
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ email: "",
+ status: 1,
+ deptId: 1,
+ roleIds: [2],
+ },
+ 3: {
+ id: 3,
+ username: "test",
+ nickname: "测试小用户",
+ mobile: "17621210366",
+ gender: 1,
+ avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
+ email: "youlaitech@163.com",
+ status: 1,
+ deptId: 3,
+ roleIds: [3],
+ },
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..79308da
--- /dev/null
+++ b/package.json
@@ -0,0 +1,128 @@
+{
+ "name": "红与蓝授权管理",
+ "description": "红与蓝授权管理系统",
+ "version": "1.8",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vue-tsc --noEmit & vite build",
+ "preview": "vite preview",
+ "build-only": "vite build",
+ "type-check": "vue-tsc --noEmit",
+ "lint:eslint": "eslint --cache \"src/**/*.{vue,ts,js}\" --fix",
+ "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,css,scss,vue,html,md}\"",
+ "lint:stylelint": "stylelint --cache \"**/*.{css,scss,vue}\" --fix",
+ "lint:lint-staged": "lint-staged",
+ "lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:stylelint",
+ "preinstall": "npx only-allow pnpm",
+ "prepare": "husky",
+ "commit": "git-cz"
+ },
+ "config": {
+ "commitizen": {
+ "path": "node_modules/cz-git"
+ }
+ },
+ "lint-staged": {
+ "*.{js,ts}": [
+ "eslint --fix",
+ "prettier --write"
+ ],
+ "*.{cjs,json}": [
+ "prettier --write"
+ ],
+ "*.{vue,html}": [
+ "eslint --fix",
+ "prettier --write",
+ "stylelint --fix"
+ ],
+ "*.{scss,css}": [
+ "stylelint --fix",
+ "prettier --write"
+ ],
+ "*.md": [
+ "prettier --write"
+ ]
+ },
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.3.1",
+ "@stomp/stompjs": "^7.1.1",
+ "@vueuse/core": "^12.8.2",
+ "@wangeditor-next/editor": "^5.6.34",
+ "@wangeditor-next/editor-for-vue": "^5.1.14",
+ "animate.css": "^4.1.1",
+ "axios": "^1.9.0",
+ "codemirror": "^5.65.19",
+ "codemirror-editor-vue3": "^2.8.0",
+ "default-passive-events": "^2.0.0",
+ "echarts": "^5.6.0",
+ "element-plus": "^2.11.7",
+ "exceljs": "^4.4.0",
+ "lodash-es": "^4.17.21",
+ "nprogress": "^0.2.0",
+ "path-browserify": "^1.0.1",
+ "path-to-regexp": "^8.2.0",
+ "pinia": "^3.0.2",
+ "qs": "^6.14.0",
+ "sortablejs": "^1.15.6",
+ "vue": "^3.5.13",
+ "vue-draggable-plus": "^0.6.0",
+ "vue-i18n": "^11.1.3",
+ "vue-router": "^4.5.1"
+ },
+ "devDependencies": {
+ "@commitlint/cli": "^19.8.1",
+ "@commitlint/config-conventional": "^19.8.1",
+ "@eslint/js": "^9.26.0",
+ "@iconify/utils": "^2.3.0",
+ "@types/codemirror": "^5.60.15",
+ "@types/lodash-es": "^4.17.12",
+ "@types/node": "^22.15.18",
+ "@types/nprogress": "^0.2.3",
+ "@types/path-browserify": "^1.0.3",
+ "@types/qs": "^6.9.18",
+ "@types/sortablejs": "^1.15.8",
+ "@typescript-eslint/eslint-plugin": "^8.32.1",
+ "@typescript-eslint/parser": "^8.32.1",
+ "@vitejs/plugin-vue": "^5.2.4",
+ "autoprefixer": "^10.4.21",
+ "commitizen": "^4.3.1",
+ "cz-git": "^1.11.1",
+ "eslint": "^9.26.0",
+ "eslint-config-prettier": "^10.1.5",
+ "eslint-plugin-prettier": "^5.4.0",
+ "eslint-plugin-vue": "^10.1.0",
+ "globals": "^15.15.0",
+ "husky": "^9.1.7",
+ "lint-staged": "^15.5.2",
+ "postcss": "^8.5.3",
+ "postcss-html": "^1.8.0",
+ "postcss-scss": "^4.0.9",
+ "prettier": "^3.5.3",
+ "sass": "^1.88.0",
+ "stylelint": "^16.19.1",
+ "stylelint-config-html": "^1.1.0",
+ "stylelint-config-recess-order": "^6.0.0",
+ "stylelint-config-recommended": "^15.0.0",
+ "stylelint-config-recommended-scss": "^14.1.0",
+ "stylelint-config-recommended-vue": "^1.6.0",
+ "stylelint-prettier": "^5.0.3",
+ "terser": "^5.39.1",
+ "typescript": "^5.8.3",
+ "typescript-eslint": "^8.32.1",
+ "unocss": "65.4.3",
+ "unplugin-auto-import": "^19.2.0",
+ "unplugin-vue-components": "^28.5.0",
+ "vite": "6.3.2",
+ "vite-plugin-mock-dev-server": "^1.8.7",
+ "vue-eslint-parser": "^10.1.3",
+ "vue-tsc": "^2.2.10"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
+ "author": "有来开源组织",
+ "license": "MIT"
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..328ef79852e3ce88858e7617d79f2146f06fc4ee
GIT binary patch
literal 3439
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
Z>n*&xiYE2qrC$6$#|-}$h5PS;{{X3grc(d_
literal 0
HcmV?d00001
diff --git a/public/files/20250717/332f8fa543dc4f7f8262e05aae95a110.jpg b/public/files/20250717/332f8fa543dc4f7f8262e05aae95a110.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c617464987cb7f50d5902f8e91e59771c55270aa
GIT binary patch
literal 19961
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