From 1075c8ae4f542bf363f2f19c3b2e358648ddfe7b Mon Sep 17 00:00:00 2001
From: TsMask <340112800@qq.com>
Date: Tue, 5 Sep 2023 14:38:23 +0800
Subject: [PATCH] =?UTF-8?q?init:=20=E5=88=9D=E5=A7=8B=E7=B3=BB=E7=BB=9F?=
=?UTF-8?q?=E6=A8=A1=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.editorconfig | 11 +
.env.development | 17 +
.env.production | 19 +
.gitignore | 33 +
.prettierrc.json | 11 +
README.md | 18 +
index.html | 15 +
init.md | 1 -
package.json | 42 +
public/favicon.ico | Bin 0 -> 4286 bytes
public/font_8d5l8fzk5b87iudi.js | 1 +
public/loading.js | 205 +++
src/App.vue | 80 +
src/api/login.ts | 59 +
src/api/monitor/cache.ts | 86 +
src/api/monitor/job.ts | 121 ++
src/api/monitor/jobLog.ts | 53 +
src/api/monitor/logininfor.ts | 67 +
src/api/monitor/online.ts | 26 +
src/api/monitor/operlog.ts | 55 +
src/api/monitor/server.ts | 9 +
src/api/profile.ts | 56 +
src/api/router.ts | 12 +
src/api/system/config.ts | 103 ++
src/api/system/dept.ts | 99 ++
src/api/system/dict/data.ts | 90 ++
src/api/system/dict/type.ts | 102 ++
src/api/system/menu.ts | 87 +
src/api/system/notice.ts | 64 +
src/api/system/post.ts | 78 +
src/api/system/role.ts | 134 ++
src/api/system/user.ts | 141 ++
src/api/tool/file.ts | 195 +++
src/assets/background.svg | 69 +
src/assets/donate.jpg | Bin 0 -> 494083 bytes
src/assets/images/default_avatar.png | Bin 0 -> 8428 bytes
src/assets/js/icon_font_8d5l8fzk5b87iudi.ts | 130 ++
src/assets/logo.png | Bin 0 -> 8428 bytes
src/components/CronModal/components/Day.vue | 141 ++
src/components/CronModal/components/Hour.vue | 137 ++
.../CronModal/components/Minute.vue | 139 ++
src/components/CronModal/components/Month.vue | 141 ++
.../CronModal/components/Second.vue | 138 ++
src/components/CronModal/index.vue | 112 ++
src/components/DictTag/index.vue | 48 +
src/components/IconFont/index.vue | 30 +
src/components/LinkiFrame/index.vue | 40 +
src/constants/admin-constants.ts | 5 +
src/constants/app-constants.ts | 5 +
src/constants/cache-keys-constants.ts | 11 +
src/constants/menu-constants.ts | 20 +
src/constants/token-constants.ts | 11 +
src/directive/index.ts | 10 +
src/directive/perms-directive.ts | 38 +
src/directive/roles-directive.ts | 38 +
src/hooks/useI18n.ts | 26 +
src/hooks/useLoading.ts | 16 +
src/hooks/useTheme.ts | 58 +
src/i18n/index.ts | 16 +
src/i18n/locales/en-US.ts | 62 +
src/i18n/locales/zh-CN.ts | 60 +
src/layouts/BasicLayout.vue | 212 +++
src/layouts/BlankLayout.vue | 7 +
src/layouts/LinkLayout.vue | 47 +
src/layouts/components/RightContent.vue | 155 ++
src/layouts/components/Tabs.vue | 187 +++
src/main.ts | 16 +
src/plugins/auth-token.ts | 17 +
src/plugins/auth-user.ts | 54 +
src/plugins/http-fetch.ts | 270 ++++
src/router/index.ts | 289 ++++
src/store/index.ts | 5 +
src/store/modules/app.ts | 31 +
src/store/modules/dict.ts | 63 +
src/store/modules/layout.ts | 91 ++
src/store/modules/router.ts | 152 ++
src/store/modules/tabs.ts | 189 +++
src/store/modules/user.ts | 171 ++
src/typings/components.d.ts | 54 +
src/typings/dict.d.ts | 7 +
src/typings/router.d.ts | 13 +
src/typings/vite-env.d.ts | 8 +
src/utils/cache-local-utils.ts | 40 +
src/utils/cache-session-utils.ts | 40 +
src/utils/date-utils.ts | 72 +
src/utils/parse-tree-utils.ts | 188 +++
src/utils/regular-utils.ts | 67 +
src/views/account/components/base-info.vue | 248 +++
src/views/account/components/reset-passwd.vue | 158 ++
src/views/account/components/style-layout.vue | 165 ++
src/views/account/profile.vue | 198 +++
src/views/account/settings.vue | 30 +
src/views/dome/dome1.vue | 27 +
src/views/dome/dome2.vue | 61 +
src/views/dome/dome3.vue | 30 +
src/views/domes/dynamic-match.vue | 87 +
src/views/domes/page-info.vue | 58 +
src/views/domes/page-typography.vue | 102 ++
src/views/error/403.vue | 21 +
src/views/error/404.vue | 26 +
src/views/index.vue | 123 ++
src/views/login.vue | 469 ++++++
src/views/monitor/cache/index.vue | 498 ++++++
src/views/monitor/cache/info.vue | 222 +++
src/views/monitor/job/index.vue | 1087 +++++++++++++
src/views/monitor/job/log.vue | 682 ++++++++
src/views/monitor/logininfor/index.vue | 546 +++++++
src/views/monitor/online/index.vue | 338 ++++
src/views/monitor/operlog/index.vue | 692 ++++++++
src/views/monitor/server/info.vue | 329 ++++
src/views/redirect/index.vue | 11 +
src/views/register.vue | 313 ++++
src/views/system/config/index.vue | 809 ++++++++++
src/views/system/dept/index.vue | 800 +++++++++
src/views/system/dict/data.vue | 883 ++++++++++
src/views/system/dict/index.vue | 809 ++++++++++
src/views/system/menu/index.vue | 1103 +++++++++++++
src/views/system/notice/index.vue | 734 +++++++++
src/views/system/post/index.vue | 759 +++++++++
src/views/system/role/auth-user.vue | 508 ++++++
.../role/components/auth-user-select.vue | 301 ++++
src/views/system/role/index.vue | 1281 +++++++++++++++
.../user/components/UploadXlsxImport.vue | 185 +++
src/views/system/user/index.vue | 1433 +++++++++++++++++
src/views/tool/build/index.vue | 11 +
src/views/tool/swagger/index.vue | 14 +
src/views/tool/upload/index.vue | 236 +++
tsconfig.json | 24 +
tsconfig.node.json | 9 +
vite.config.ts | 76 +
130 files changed, 22531 insertions(+), 1 deletion(-)
create mode 100644 .editorconfig
create mode 100644 .env.development
create mode 100644 .env.production
create mode 100644 .gitignore
create mode 100644 .prettierrc.json
create mode 100644 README.md
create mode 100644 index.html
delete mode 100644 init.md
create mode 100644 package.json
create mode 100644 public/favicon.ico
create mode 100644 public/font_8d5l8fzk5b87iudi.js
create mode 100644 public/loading.js
create mode 100644 src/App.vue
create mode 100644 src/api/login.ts
create mode 100644 src/api/monitor/cache.ts
create mode 100644 src/api/monitor/job.ts
create mode 100644 src/api/monitor/jobLog.ts
create mode 100644 src/api/monitor/logininfor.ts
create mode 100644 src/api/monitor/online.ts
create mode 100644 src/api/monitor/operlog.ts
create mode 100644 src/api/monitor/server.ts
create mode 100644 src/api/profile.ts
create mode 100644 src/api/router.ts
create mode 100644 src/api/system/config.ts
create mode 100644 src/api/system/dept.ts
create mode 100644 src/api/system/dict/data.ts
create mode 100644 src/api/system/dict/type.ts
create mode 100644 src/api/system/menu.ts
create mode 100644 src/api/system/notice.ts
create mode 100644 src/api/system/post.ts
create mode 100644 src/api/system/role.ts
create mode 100644 src/api/system/user.ts
create mode 100644 src/api/tool/file.ts
create mode 100644 src/assets/background.svg
create mode 100644 src/assets/donate.jpg
create mode 100644 src/assets/images/default_avatar.png
create mode 100644 src/assets/js/icon_font_8d5l8fzk5b87iudi.ts
create mode 100644 src/assets/logo.png
create mode 100644 src/components/CronModal/components/Day.vue
create mode 100644 src/components/CronModal/components/Hour.vue
create mode 100644 src/components/CronModal/components/Minute.vue
create mode 100644 src/components/CronModal/components/Month.vue
create mode 100644 src/components/CronModal/components/Second.vue
create mode 100644 src/components/CronModal/index.vue
create mode 100644 src/components/DictTag/index.vue
create mode 100644 src/components/IconFont/index.vue
create mode 100644 src/components/LinkiFrame/index.vue
create mode 100644 src/constants/admin-constants.ts
create mode 100644 src/constants/app-constants.ts
create mode 100644 src/constants/cache-keys-constants.ts
create mode 100644 src/constants/menu-constants.ts
create mode 100644 src/constants/token-constants.ts
create mode 100644 src/directive/index.ts
create mode 100644 src/directive/perms-directive.ts
create mode 100644 src/directive/roles-directive.ts
create mode 100644 src/hooks/useI18n.ts
create mode 100644 src/hooks/useLoading.ts
create mode 100644 src/hooks/useTheme.ts
create mode 100644 src/i18n/index.ts
create mode 100644 src/i18n/locales/en-US.ts
create mode 100644 src/i18n/locales/zh-CN.ts
create mode 100644 src/layouts/BasicLayout.vue
create mode 100644 src/layouts/BlankLayout.vue
create mode 100644 src/layouts/LinkLayout.vue
create mode 100644 src/layouts/components/RightContent.vue
create mode 100644 src/layouts/components/Tabs.vue
create mode 100644 src/main.ts
create mode 100644 src/plugins/auth-token.ts
create mode 100644 src/plugins/auth-user.ts
create mode 100644 src/plugins/http-fetch.ts
create mode 100644 src/router/index.ts
create mode 100644 src/store/index.ts
create mode 100644 src/store/modules/app.ts
create mode 100644 src/store/modules/dict.ts
create mode 100644 src/store/modules/layout.ts
create mode 100644 src/store/modules/router.ts
create mode 100644 src/store/modules/tabs.ts
create mode 100644 src/store/modules/user.ts
create mode 100644 src/typings/components.d.ts
create mode 100644 src/typings/dict.d.ts
create mode 100644 src/typings/router.d.ts
create mode 100644 src/typings/vite-env.d.ts
create mode 100644 src/utils/cache-local-utils.ts
create mode 100644 src/utils/cache-session-utils.ts
create mode 100644 src/utils/date-utils.ts
create mode 100644 src/utils/parse-tree-utils.ts
create mode 100644 src/utils/regular-utils.ts
create mode 100644 src/views/account/components/base-info.vue
create mode 100644 src/views/account/components/reset-passwd.vue
create mode 100644 src/views/account/components/style-layout.vue
create mode 100644 src/views/account/profile.vue
create mode 100644 src/views/account/settings.vue
create mode 100644 src/views/dome/dome1.vue
create mode 100644 src/views/dome/dome2.vue
create mode 100644 src/views/dome/dome3.vue
create mode 100644 src/views/domes/dynamic-match.vue
create mode 100644 src/views/domes/page-info.vue
create mode 100644 src/views/domes/page-typography.vue
create mode 100644 src/views/error/403.vue
create mode 100644 src/views/error/404.vue
create mode 100644 src/views/index.vue
create mode 100644 src/views/login.vue
create mode 100644 src/views/monitor/cache/index.vue
create mode 100644 src/views/monitor/cache/info.vue
create mode 100644 src/views/monitor/job/index.vue
create mode 100644 src/views/monitor/job/log.vue
create mode 100644 src/views/monitor/logininfor/index.vue
create mode 100644 src/views/monitor/online/index.vue
create mode 100644 src/views/monitor/operlog/index.vue
create mode 100644 src/views/monitor/server/info.vue
create mode 100644 src/views/redirect/index.vue
create mode 100644 src/views/register.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/data.vue
create mode 100644 src/views/system/dict/index.vue
create mode 100644 src/views/system/menu/index.vue
create mode 100644 src/views/system/notice/index.vue
create mode 100644 src/views/system/post/index.vue
create mode 100644 src/views/system/role/auth-user.vue
create mode 100644 src/views/system/role/components/auth-user-select.vue
create mode 100644 src/views/system/role/index.vue
create mode 100644 src/views/system/user/components/UploadXlsxImport.vue
create mode 100644 src/views/system/user/index.vue
create mode 100644 src/views/tool/build/index.vue
create mode 100644 src/views/tool/swagger/index.vue
create mode 100644 src/views/tool/upload/index.vue
create mode 100644 tsconfig.json
create mode 100644 tsconfig.node.json
create mode 100644 vite.config.ts
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..4c7f8a8e
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+# 🎨 editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
\ No newline at end of file
diff --git a/.env.development b/.env.development
new file mode 100644
index 00000000..e4a07bd0
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,17 @@
+# 历史路径-哈希带井号标识
+VITE_HISTORY_HASH = false
+
+# 历史路径-前缀URL如:/h5
+VITE_HISTORY_BASE_URL = /
+
+# 应用名称
+VITE_APP_NAME = Mask管理系统
+
+# 应用标识
+VITE_APP_CODE = maskAntd
+
+# 应用版本
+VITE_APP_VERSION = '0.2.1'
+
+# 接口基础URL地址-不带/后缀
+VITE_API_BASE_URL = /dev-api
diff --git a/.env.production b/.env.production
new file mode 100644
index 00000000..cb4095cd
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,19 @@
+# 历史路径-哈希带井号标识
+VITE_HISTORY_HASH = true
+
+# 历史路径-前缀URL如:/h5
+VITE_HISTORY_BASE_URL = /mask-antd
+
+# 应用名称
+VITE_APP_NAME = Mask管理系统
+
+# 应用标识
+VITE_APP_CODE = maskAntd
+
+# 应用版本
+VITE_APP_VERSION = '0.2.1'
+
+# 接口基础URL地址-不带/后缀
+# VITE_API_BASE_URL = https://mock.apifox.cn/m1/1551143-0-default
+VITE_API_BASE_URL = http://124.223.91.248:8102/prod-api
+# VITE_API_BASE_URL = http://192.168.56.1:6275
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..a2583a80
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 00000000..41e79eac
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,11 @@
+{
+ "printWidth": 80,
+ "tabWidth": 2,
+ "useTabs": false,
+ "singleQuote": true,
+ "semi": true,
+ "trailingComma": "es5",
+ "bracketSpacing": true,
+ "jsxBracketSameLine": false,
+ "arrowParens": "avoid"
+}
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..59631a78
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# 基于 Ant-Design-Vue + Vue3 的管理系统
+
+[](https://gitee.com/TsMask/mask_antd_vue3/stargazers)
+
+
+
+
+
+## 简介
+
+该项目选择 [RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3) 进行功能适配。
+
+- 系统布局使用 [@ant-design-vue/pro-layout](https://github.com/vueComponent/pro-components)
+- 图标来源 [@ant-design/icons-vue](https://ant.design/components/icon)
+- 菜单图标使用自定义iconfont `font_8d5l8fzk5b87iudi.js`图标文件
+
+> 有任何问题或者建议,可以在 [_Issues_](https://gitee.com/TsMask/mask_api_midwayjs/issues) 或通过QQ群:[_57242844_](https://jq.qq.com/?_wv=1027&k=z6Y4YQcB) 提出想法。
+> 如果觉得项目对您有帮助,可以来个Star ⭐
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..1369a698
--- /dev/null
+++ b/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/init.md b/init.md
deleted file mode 100644
index b5754e20..00000000
--- a/init.md
+++ /dev/null
@@ -1 +0,0 @@
-ok
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..28145b4b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "ems_frontend_vue3",
+ "type": "module",
+ "description": "核心网管理系统",
+ "author": "TsMask",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "scripts": {
+ "dev": "vite",
+ "build": "vue-tsc && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@ant-design-vue/pro-layout": "^3.2.4",
+ "@ant-design/icons-vue": "^6.1.0",
+ "ant-design-vue": "^3.2.20",
+ "dayjs": "^1.11.8",
+ "echarts": "^5.4.2",
+ "file-saver": "^2.0.5",
+ "js-base64": "^3.7.5",
+ "js-cookie": "^3.0.5",
+ "nprogress": "^0.2.0",
+ "pinia": "^2.1.4",
+ "vue": "^3.3.4",
+ "vue-router": "^4.2.2"
+ },
+ "devDependencies": {
+ "@types/file-saver": "^2.0.5",
+ "@types/js-cookie": "^3.0.3",
+ "@types/node": "^18.0.0",
+ "@types/nprogress": "^0.2.0",
+ "@vitejs/plugin-vue": "^4.2.3",
+ "less": "^4.1.3",
+ "typescript": "^5.1.3",
+ "unplugin-vue-components": "^0.25.1",
+ "vite": "^4.3.9",
+ "vite-plugin-compression": "^0.5.1",
+ "vue-i18n": "^9.3.0-beta.27",
+ "vue-tsc": "^1.8.0"
+ }
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..4814a3f3bef6ed876beefba949d3ee42bbde2c1d
GIT binary patch
literal 4286
zcmeI0e@v8h9LK-UJ%6Q#d~Ton-aXIV
zz2Ber=l%J7pPf>MJmTY(epdA}l!{bJ&5@8(>JbTj-gn5g+mB=w%>B5p!9VeUTRh`7
z{u|9ScDzK4=HLsL_}6()Je(ppNyL78$c=wIicbB#4DLX?e?h#*cb
zR%EGcp0eH$9){q%L=UY)V6{jwoWu!ko;iynAuHKv%V4pZf!kD+sxsa)f8!bZ4l=D}
zq#5xfiXLt?EnxLXlzd`D-vug^u9yuBEUct+(c8Q_x0H3!hu9t3O{Ka>x$30Ic$oy7
zl6p+&aaUT1zY|6C`Qbr4l;9*vDNf~=bLA_zbY`6XFQNN0FV&4>yjecL;m2>X>%m^~
z)fVZEM3M}LXrRNtKGFRZFE!1IbaG;kjr?@QcJ(m*)!lRocGst)44n1SC$DSH!p;j`
zj$MG)JziFsuuvVH;syUaksw}6lDtc&Pa`8NnkUr~uH`h))hfB47VOVqP~wLcFFQ`c
zf%9H=UK*q9Iam=jEcl5e8@4Gt{;n3f&n)H{ndI5llWSB`Xw*?;Z{&-RHhR}z=f@5h
z5Zt~qFeDs~e*)#lVe{8sBHAE+_0NJmQ?TuR;Jc*u1`CWl9y6QqSVt+b>c}^1dBJSr
zdRPb7_6%}Eym0+A49nUge71`ITfZ5{`4fb1Y$rv}1>ch7R7ucTd*4_wwfq5
z-e+k>JKI
z%cEuu9@~eMxLe8Gbd%>R;oMtZE}w^vtI*m5dnJ#f?!4D%nb53-=d*Hu*H8;94i~6z7#&lg~nyjun!Jy@N%FCa+dTG8x$im*b;32bf3i6tLBhu
zXfGOM8;f|y>Y>&?LajN%VKv0TgkPvCkjT8j8V|%KR>*gB?jd)T`&14o;=^e9%{Ar*
z_Bk%I%ih7>pl_*iU17h~%~tgh%NGw5ll`4|Zo1&=xqJ7yPvr0P?P=*Mn%(w`R6Ba8
z6b{?WR?5_Vic}$U!g7d`IwVJw2(HdOaQmNI_5j_31x5kutaoL$Kg|-A$Gp%8R^^(c
z$$l3b`wGcvbpgkoS_9q3nn#@A%@8kaTwyS{%_P(2Aa3?cxE&7&eqcQJXWT#b46Q|~
zcp*-r&=rKoX_p=i!ENa|AGn(T75?OT-@TahMYMR#t>>FB0^_$yj61FR{y@*DiO=0z
W>^pJ0e|@qp|Nr&&{{!yz``-Z^D#F14
literal 0
HcmV?d00001
diff --git a/public/font_8d5l8fzk5b87iudi.js b/public/font_8d5l8fzk5b87iudi.js
new file mode 100644
index 00000000..699f245c
--- /dev/null
+++ b/public/font_8d5l8fzk5b87iudi.js
@@ -0,0 +1 @@
+(function(window){var svgSprite="";var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window)
\ No newline at end of file
diff --git a/public/loading.js b/public/loading.js
new file mode 100644
index 00000000..36664037
--- /dev/null
+++ b/public/loading.js
@@ -0,0 +1,205 @@
+/**
+ * loading 占位
+ * 解决首次加载时白屏的问题
+ */
+(function () {
+ const _app = document.querySelector('#app');
+ if (_app && _app.innerHTML === '') {
+ const styleStr = `
+ `;
+
+ let loadInfo = {
+ title: '正在加载资源',
+ titleSub: '初次加载资源可能需要较多时间',
+ msg: '请耐心等待',
+ };
+ document.title = "管理系统";
+
+ // 判断选择语言
+ const lang = localStorage.getItem('cache:local:i18n') || 'zh_CN';
+ if (lang === 'en_US') {
+ loadInfo = {
+ title: 'Loading Resources',
+ titleSub: 'Loading resources for the first time may take a lot of time',
+ msg: 'Please be patient',
+ };
+ document.title = "Managerial System";
+ }
+
+ const divStr = `
+
+
+
+ ${loadInfo.title}
+
+
+ ${loadInfo.titleSub} ${loadInfo.msg}
+
+
`;
+
+ _app.innerHTML = styleStr + divStr;
+ }
+})();
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 00000000..98d5fd18
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/api/login.ts b/src/api/login.ts
new file mode 100644
index 00000000..225c9327
--- /dev/null
+++ b/src/api/login.ts
@@ -0,0 +1,59 @@
+import { request } from '@/plugins/http-fetch';
+
+// 登录方法
+export function login(data: Record) {
+ return request({
+ url: '/login',
+ method: 'post',
+ data: data,
+ whithToken: false,
+ });
+}
+
+/**
+ * 注册方法
+ * @param data 注册对象
+ * @returns object
+ */
+export function register(data: Record) {
+ return request({
+ url: '/register',
+ method: 'post',
+ data: data,
+ whithToken: false,
+ });
+}
+
+/**
+ * 获取用户详细信息
+ * @returns object
+ */
+export function getInfo() {
+ return request({
+ url: '/getInfo',
+ method: 'get',
+ });
+}
+
+/**
+ * 退出方法
+ * @returns object
+ */
+export function logout() {
+ return request({
+ url: '/logout',
+ method: 'post',
+ });
+}
+
+/**
+ * 获取验证码
+ * @returns object
+ */
+export function getCaptchaImage() {
+ return request({
+ url: '/captchaImage',
+ method: 'get',
+ whithToken: false,
+ });
+}
diff --git a/src/api/monitor/cache.ts b/src/api/monitor/cache.ts
new file mode 100644
index 00000000..b5fc7479
--- /dev/null
+++ b/src/api/monitor/cache.ts
@@ -0,0 +1,86 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询缓存详细
+ * @returns object
+ */
+export function getCache() {
+ return request({
+ url: '/monitor/cache',
+ method: 'get',
+ });
+}
+
+/**
+ * 查询缓存名称列表
+ * @returns object
+ */
+export function listCacheName() {
+ return request({
+ url: '/monitor/cache/getNames',
+ method: 'get',
+ });
+}
+
+/**
+ * 查询缓存名称下键名列表
+ * @param cacheName 缓存名称列表中得到的缓存名称
+ * @returns object
+ */
+export function listCacheKey(cacheName: string) {
+ return request({
+ url: `/monitor/cache/getKeys/${cacheName}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 查询缓存内容
+ * @param cacheName 键名列表中得到的缓存名称
+ * @param cacheKey 键名列表中得到的缓存键名
+ * @returns object
+ */
+export function getCacheValue(cacheName: string, cacheKey: string) {
+ return request({
+ url: `/monitor/cache/getValue/${cacheName}/${cacheKey}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 删除缓存名称下键名列表
+ * @param cacheName 缓存名称列表中得到的缓存名称
+ * @returns object
+ */
+export function clearCacheName(cacheName: string) {
+ return request({
+ url: `/monitor/cache/clearCacheName/${cacheName}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 删除缓存键名
+ * @param cacheName 键名列表中得到的缓存名称
+ * @param cacheKey 键名列表中得到的缓存键名
+ * @returns object
+ */
+export function clearCacheKey(cacheName: string, cacheKey: string) {
+ return request({
+ url: `/monitor/cache/clearCacheKey/${cacheName}/${cacheKey}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 安全清理缓存名称
+ *
+ * 指定可清理的缓存key
+ * @returns object
+ */
+export function clearCacheSafe() {
+ return request({
+ url: '/monitor/cache/clearCacheSafe',
+ method: 'delete',
+ });
+}
diff --git a/src/api/monitor/job.ts b/src/api/monitor/job.ts
new file mode 100644
index 00000000..09ec7d5b
--- /dev/null
+++ b/src/api/monitor/job.ts
@@ -0,0 +1,121 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 定时任务调度列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportJob(query: Record) {
+ return request({
+ url: '/monitor/job/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询定时任务调度列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listJob(query: Record) {
+ return request({
+ url: '/monitor/job/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询定时任务调度详细
+ * @param jobId 任务ID
+ * @returns object
+ */
+export function getJob(jobId: string | number) {
+ return request({
+ url: `/monitor/job/${jobId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增定时任务调度
+ * @param data 任务对象
+ * @returns object
+ */
+export function addJob(data: Record) {
+ return request({
+ url: '/monitor/job',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改定时任务调度
+ * @param data 任务对象
+ * @returns object
+ */
+export function updateJob(data: Record) {
+ return request({
+ url: '/monitor/job',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除定时任务调度
+ * @param jobId 任务ID
+ * @returns object
+ */
+export function delJob(jobId: string | number) {
+ return request({
+ url: `/monitor/job/${jobId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 任务状态修改
+ * @param jobId 任务ID
+ * @param status 变更状态值
+ * @returns
+ */
+export function changeJobStatus(
+ jobId: string | number,
+ status: string | number
+) {
+ return request({
+ url: '/monitor/job/changeStatus',
+ method: 'put',
+ data: {
+ jobId,
+ status,
+ },
+ });
+}
+
+/**
+ * 定时任务立即执行一次
+ * @param jobId 任务ID
+ * @returns object
+ */
+export function runJob(jobId: string) {
+ return request({
+ url: `/monitor/job/run/${jobId}`,
+ method: 'put',
+ });
+}
+
+/**
+ * 重置刷新队列
+ * @returns object
+ */
+export function resetQueueJob() {
+ return request({
+ url: '/monitor/job/resetQueueJob',
+ method: 'put',
+ });
+}
diff --git a/src/api/monitor/jobLog.ts b/src/api/monitor/jobLog.ts
new file mode 100644
index 00000000..ade7b771
--- /dev/null
+++ b/src/api/monitor/jobLog.ts
@@ -0,0 +1,53 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 定时任务调度日志列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportJobLog(
+ query: Record
+) {
+ return request({
+ url: '/monitor/jobLog/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询调度日志列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listJobLog(query: Record) {
+ return request({
+ url: '/monitor/jobLog/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 删除调度日志
+ * @param jobLogId 任务日志Id
+ * @returns object
+ */
+export function delJobLog(jobLogId: string) {
+ return request({
+ url: `/monitor/jobLog/${jobLogId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 清空调度日志
+ * @returns object
+ */
+export function cleanJobLog() {
+ return request({
+ url: '/monitor/jobLog/clean',
+ method: 'delete',
+ });
+}
diff --git a/src/api/monitor/logininfor.ts b/src/api/monitor/logininfor.ts
new file mode 100644
index 00000000..8e0388e5
--- /dev/null
+++ b/src/api/monitor/logininfor.ts
@@ -0,0 +1,67 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 登录日志列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportLogininfor(
+ query: Record
+) {
+ return request({
+ url: '/monitor/logininfor/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询登录日志列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listLogininfor(
+ query: Record
+) {
+ return request({
+ url: '/monitor/logininfor/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 删除登录日志
+ * @param infoId 登录日志Id
+ * @returns object
+ */
+export function delLogininfor(infoId: string) {
+ return request({
+ url: `/monitor/logininfor/${infoId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 清空登录日志
+ * @returns object
+ */
+export function cleanLogininfor() {
+ return request({
+ url: '/monitor/logininfor/clean',
+ method: 'delete',
+ });
+}
+
+/**
+ * 解锁用户登录状态
+ * @param userName 登录账号
+ * @returns object
+ */
+export function unlockLogininfor(userName: string) {
+ return request({
+ url: `/monitor/logininfor/unlock/${userName}`,
+ method: 'put',
+ });
+}
diff --git a/src/api/monitor/online.ts b/src/api/monitor/online.ts
new file mode 100644
index 00000000..4faa13ea
--- /dev/null
+++ b/src/api/monitor/online.ts
@@ -0,0 +1,26 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询在线用户列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listOnline(query: Record) {
+ return request({
+ url: '/monitor/online/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 强退用户
+ * @param tokenId 授权标识
+ * @returns object
+ */
+export function forceLogout(tokenId: string) {
+ return request({
+ url: `/monitor/online/${tokenId}`,
+ method: 'delete',
+ });
+}
diff --git a/src/api/monitor/operlog.ts b/src/api/monitor/operlog.ts
new file mode 100644
index 00000000..04bfb101
--- /dev/null
+++ b/src/api/monitor/operlog.ts
@@ -0,0 +1,55 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 操作日志列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportOperlog(
+ query: Record
+) {
+ return request({
+ url: '/monitor/operlog/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询操作日志列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listOperlog(
+ query: Record
+) {
+ return request({
+ url: '/monitor/operlog/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 删除操作日志
+ * @param operId 操作日志ID
+ * @returns object
+ */
+export function delOperlog(operId: string) {
+ return request({
+ url: `/monitor/operlog/${operId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 清空操作日志
+ * @returns object
+ */
+export function cleanOperlog() {
+ return request({
+ url: '/monitor/operlog/clean',
+ method: 'delete',
+ });
+}
diff --git a/src/api/monitor/server.ts b/src/api/monitor/server.ts
new file mode 100644
index 00000000..eea90e35
--- /dev/null
+++ b/src/api/monitor/server.ts
@@ -0,0 +1,9 @@
+import { request } from '@/plugins/http-fetch';
+
+/**获取服务信息 */
+export function getServer() {
+ return request({
+ url: '/monitor/server',
+ method: 'get',
+ });
+}
diff --git a/src/api/profile.ts b/src/api/profile.ts
new file mode 100644
index 00000000..be793283
--- /dev/null
+++ b/src/api/profile.ts
@@ -0,0 +1,56 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询用户个人信息
+ * @returns object
+ */
+export function getUserProfile() {
+ return request({
+ url: '/system/user/profile',
+ method: 'get',
+ });
+}
+
+/**
+ * 修改用户个人信息
+ * @param data 用户对象
+ * @returns object
+ */
+export function updateUserProfile(data: Record) {
+ return request({
+ url: '/system/user/profile',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 用户密码重置
+ * @param userId 用户ID
+ * @param status 变更状态值
+ * @returns object
+ */
+export function updateUserPwd(oldPassword: string, newPassword: string) {
+ return request({
+ url: '/system/user/profile/updatePwd',
+ method: 'put',
+ data: {
+ oldPassword,
+ newPassword,
+ },
+ });
+}
+
+/**
+ * 用户头像上传
+ * @param data 表单数据对象
+ * @returns object
+ */
+export function uploadAvatar(data: FormData) {
+ return request({
+ url: '/system/user/profile/avatar',
+ method: 'post',
+ data,
+ dataType: 'form-data',
+ });
+}
diff --git a/src/api/router.ts b/src/api/router.ts
new file mode 100644
index 00000000..a0b810cf
--- /dev/null
+++ b/src/api/router.ts
@@ -0,0 +1,12 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 获取路由
+ * @returns object
+ */
+export const getRouters = () => {
+ return request({
+ url: '/getRouters',
+ method: 'get',
+ });
+};
diff --git a/src/api/system/config.ts b/src/api/system/config.ts
new file mode 100644
index 00000000..2358eb7c
--- /dev/null
+++ b/src/api/system/config.ts
@@ -0,0 +1,103 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 参数配置列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportConfig(
+ query: Record
+) {
+ return request({
+ url: '/system/config/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询参数配置列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listConfig(query: Record) {
+ return request({
+ url: '/system/config/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询参数详细
+ * @param configId 参数配置ID
+ * @returns object
+ */
+export function getConfig(configId: string | number) {
+ return request({
+ url: `/system/config/${configId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 根据参数键名查询参数值
+ * @param configKey 参数键名
+ * @returns object
+ */
+export function getConfigKey(configKey: string) {
+ return request({
+ url: `/system/config/configKey/${configKey}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增参数配置
+ * @param data 参数配置对象
+ * @returns object
+ */
+export function addConfig(data: Record) {
+ return request({
+ url: '/system/config',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改参数配置
+ * @param data 参数配置对象
+ * @returns object
+ */
+export function updateConfig(data: Record) {
+ return request({
+ url: '/system/config',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除参数配置
+ * @param configId 参数配置ID
+ * @returns object
+ */
+export function delConfig(configId: string | number) {
+ return request({
+ url: `/system/config/${configId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 刷新参数缓存
+ * @returns object
+ */
+export function refreshCache() {
+ return request({
+ url: '/system/config/refreshCache',
+ method: 'put',
+ });
+}
diff --git a/src/api/system/dept.ts b/src/api/system/dept.ts
new file mode 100644
index 00000000..288a16ef
--- /dev/null
+++ b/src/api/system/dept.ts
@@ -0,0 +1,99 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询部门列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listDept(query: Record) {
+ return request({
+ url: '/system/dept/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询部门列表(排除节点)
+ * @param deptId 部门ID
+ * @returns object
+ */
+export function listDeptExcludeChild(deptId: string | number) {
+ return request({
+ url: `/system/dept/list/exclude/${deptId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 查询部门详细
+ * @param deptId 部门ID
+ * @returns object
+ */
+export function getDept(deptId: string | number) {
+ return request({
+ url: `/system/dept/${deptId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增部门
+ * @param data 部门对象
+ * @returns object
+ */
+export function addDept(data: Record) {
+ return request({
+ url: '/system/dept',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改部门
+ * @param data 部门对象
+ * @returns object
+ */
+export function updateDept(data: Record) {
+ return request({
+ url: '/system/dept',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除部门
+ * @param deptId 部门ID
+ * @returns object
+ */
+export function delDept(deptId: string | number) {
+ return request({
+ url: `/system/dept/${deptId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 查询部门下拉树结构
+ * @returns object
+ */
+export function deptTreeSelect() {
+ return request({
+ url: '/system/dept/treeSelect',
+ method: 'get',
+ });
+}
+
+/**
+ * 部门树结构列表(指定角色)
+ * @param roleId 角色ID
+ * @returns object
+ */
+export function roleDeptTreeSelect(roleId: string | number) {
+ return request({
+ url: `/system/dept/roleDeptTreeSelect/${roleId}`,
+ method: 'get',
+ });
+}
diff --git a/src/api/system/dict/data.ts b/src/api/system/dict/data.ts
new file mode 100644
index 00000000..f4fc8df4
--- /dev/null
+++ b/src/api/system/dict/data.ts
@@ -0,0 +1,90 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 字典数据列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportData(query: Record) {
+ return request({
+ url: '/system/dict/data/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询字典数据列表
+ * @param query 查询值
+ * @returns
+ */
+export function listData(query: Record) {
+ return request({
+ url: '/system/dict/data/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询字典数据详细
+ * @param dictCode 字典代码值
+ * @returns object
+ */
+export function getData(dictCode: string | number) {
+ return request({
+ url: `/system/dict/data/${dictCode}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增字典数据
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function addData(data: Record) {
+ return request({
+ url: '/system/dict/data',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改字典数据
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function updateData(data: Record) {
+ return request({
+ url: '/system/dict/data',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除字典数据
+ * @param dictCode 字典代码值
+ * @returns object
+ */
+export function delData(dictCode: string | number) {
+ return request({
+ url: `/system/dict/data/${dictCode}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 字典数据列表(指定字典类型)
+ * @param dictType 字典类型
+ * @returns object
+ */
+export function getDictDataType(dictType: string) {
+ return request({
+ url: `/system/dict/data/type/${dictType}`,
+ method: 'get',
+ });
+}
diff --git a/src/api/system/dict/type.ts b/src/api/system/dict/type.ts
new file mode 100644
index 00000000..040b0329
--- /dev/null
+++ b/src/api/system/dict/type.ts
@@ -0,0 +1,102 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 字典类型列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportType(query: Record) {
+ return request({
+ url: '/system/dict/type/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询字典类型列表
+ * @param query 查询值
+ * @returns
+ */
+export function listType(query: Record) {
+ return request({
+ url: '/system/dict/type/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询字典类型详细
+ * @param dictId 字典编号
+ * @returns object
+ */
+export function getType(dictId: string | number) {
+ return request({
+ url: `/system/dict/type/${dictId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增字典类型
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function addType(data: Record) {
+ return request({
+ url: '/system/dict/type',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改字典类型
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function updateType(data: Record) {
+ return request({
+ url: '/system/dict/type',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除字典类型
+ * @param dictCode 字典代码值
+ * @returns object
+ */
+export function delType(dictId: string | number) {
+ return request({
+ url: `/system/dict/type/${dictId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 刷新字典缓存
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function refreshCache() {
+ return request({
+ url: '/system/dict/type/refreshCache',
+ method: 'put',
+ });
+}
+
+/**
+ * 获取字典选择框列表
+ * @param data 字典数据对象
+ * @returns object
+ */
+export function getDictOptionselect() {
+ return request({
+ url: '/system/dict/type/getDictOptionselect',
+ method: 'get',
+ });
+}
diff --git a/src/api/system/menu.ts b/src/api/system/menu.ts
new file mode 100644
index 00000000..4827d770
--- /dev/null
+++ b/src/api/system/menu.ts
@@ -0,0 +1,87 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询菜单列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listMenu(query?: Record) {
+ return request({
+ url: '/system/menu/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询菜单详细
+ * @param menuId 菜单ID
+ * @returns object
+ */
+export function getMenu(menuId: string | number) {
+ return request({
+ url: `/system/menu/${menuId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 查询菜单下拉树结构
+ * @returns object
+ */
+export function menuTreeSelect() {
+ return request({
+ url: '/system/menu/treeSelect',
+ method: 'get',
+ });
+}
+
+/**
+ * 根据角色ID查询菜单下拉树结构
+ * @param roleId 角色ID
+ * @returns object
+ */
+export function roleMenuTreeSelect(roleId: string | number) {
+ return request({
+ url: `/system/menu/roleMenuTreeSelect/${roleId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增菜单
+ * @param data 菜单对象
+ * @returns object
+ */
+export function addMenu(data: Record) {
+ return request({
+ url: '/system/menu',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改菜单
+ * @param data 菜单对象
+ * @returns object
+ */
+export function updateMenu(data: Record) {
+ return request({
+ url: '/system/menu',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除菜单
+ * @param menuId 菜单ID
+ * @returns object
+ */
+export function delMenu(menuId: string | number) {
+ return request({
+ url: `/system/menu/${menuId}`,
+ method: 'delete',
+ });
+}
diff --git a/src/api/system/notice.ts b/src/api/system/notice.ts
new file mode 100644
index 00000000..d3046fce
--- /dev/null
+++ b/src/api/system/notice.ts
@@ -0,0 +1,64 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 查询公告列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listNotice(query: Record) {
+ return request({
+ url: '/system/notice/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询公告详细
+ * @param menuId 公告ID
+ * @returns object
+ */
+export function getNotice(noticeId: string | number) {
+ return request({
+ url: `/system/notice/${noticeId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增公告
+ * @param data 公告对象
+ * @returns object
+ */
+export function addNotice(data: Record) {
+ return request({
+ url: '/system/notice',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改公告
+ * @param data 公告对象
+ * @returns object
+ */
+export function updateNotice(data: Record) {
+ return request({
+ url: '/system/notice',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除公告
+ * @param noticeId 公告ID
+ * @returns object
+ */
+export function delNotice(noticeId: string | number) {
+ return request({
+ url: `/system/notice/${noticeId}`,
+ method: 'delete',
+ });
+}
diff --git a/src/api/system/post.ts b/src/api/system/post.ts
new file mode 100644
index 00000000..da63bc92
--- /dev/null
+++ b/src/api/system/post.ts
@@ -0,0 +1,78 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 岗位列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportPost(query: Record) {
+ return request({
+ url: '/system/post/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询岗位列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listPost(query: Record) {
+ return request({
+ url: '/system/post/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询岗位详细
+ * @param postId 岗位ID
+ * @returns object
+ */
+export function getPost(postId: string | number) {
+ return request({
+ url: `/system/post/${postId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增岗位
+ * @param data 岗位对象
+ * @returns object
+ */
+export function addPost(data: Record) {
+ return request({
+ url: '/system/post',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改岗位
+ * @param data 岗位对象
+ * @returns object
+ */
+export function updatePost(data: Record) {
+ return request({
+ url: '/system/post',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除岗位
+ * @param postId 岗位ID
+ * @returns object
+ */
+export function delPost(postId: string | number) {
+ return request({
+ url: `/system/post/${postId}`,
+ method: 'delete',
+ });
+}
diff --git a/src/api/system/role.ts b/src/api/system/role.ts
new file mode 100644
index 00000000..2f426836
--- /dev/null
+++ b/src/api/system/role.ts
@@ -0,0 +1,134 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 角色列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportRole(query: Record) {
+ return request({
+ url: '/system/role/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询角色列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listRole(query: Record) {
+ return request({
+ url: '/system/role/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询角色详细
+ * @param roleId 角色ID
+ * @returns object
+ */
+export function getRole(roleId: string | number) {
+ return request({
+ url: `/system/role/${roleId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增角色
+ * @param data 角色对象
+ * @returns object
+ */
+export function addRole(data: Record) {
+ return request({
+ url: '/system/role',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改角色
+ * @param data 角色对象
+ * @returns object
+ */
+export function updateRole(data: Record) {
+ return request({
+ url: '/system/role',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除角色
+ * @param roleId 角色ID
+ * @returns object
+ */
+export function delRole(roleId: string | number) {
+ return request({
+ url: `/system/role/${roleId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 角色状态修改
+ * @param roleId 角色ID
+ * @param status 角色状态
+ * @returns object
+ */
+export function changeRoleStatus(roleId: string, status: string | number) {
+ return request({
+ url: '/system/role/changeStatus',
+ method: 'put',
+ data: {
+ roleId,
+ status,
+ },
+ });
+}
+
+/**
+ * 修改角色数据权限
+ * @param data 角色对象
+ * @returns object
+ */
+export function dataScope(data: Record) {
+ return request({
+ url: '/system/role/dataScope',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 角色分配用户列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function authUserAllocatedList(query: Record) {
+ return request({
+ url: '/system/role/authUser/allocatedList',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 角色分配选择授权
+ * @param data 角色对象
+ * @returns object
+ */
+export function authUserChecked(data: Record) {
+ return request({
+ url: '/system/role/authUser/checked',
+ method: 'put',
+ data: data,
+ });
+}
diff --git a/src/api/system/user.ts b/src/api/system/user.ts
new file mode 100644
index 00000000..febcce9e
--- /dev/null
+++ b/src/api/system/user.ts
@@ -0,0 +1,141 @@
+import { request } from '@/plugins/http-fetch';
+
+/**
+ * 导入用户模板数据
+ * @param data 表单数据对象
+ * @returns object
+ */
+export function importData(data: FormData) {
+ return request({
+ url: '/system/user/importData',
+ method: 'post',
+ data,
+ dataType: 'form-data',
+ });
+}
+
+/**
+ * 导入用户模板下载
+ * @returns bolb
+ */
+export function importTemplate() {
+ return request({
+ url: '/system/user/importTemplate',
+ method: 'get',
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 用户列表导出
+ * @param query 查询参数
+ * @returns bolb
+ */
+export function exportUser(query: Record) {
+ return request({
+ url: '/system/user/export',
+ method: 'post',
+ data: query,
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 查询用户列表
+ * @param query 查询参数
+ * @returns object
+ */
+export function listUser(query: Record) {
+ return request({
+ url: '/system/user/list',
+ method: 'get',
+ params: query,
+ });
+}
+
+/**
+ * 查询用户详细
+ * @param userId 用户ID,新增0
+ * @returns object
+ */
+export function getUser(userId: string | number = '0') {
+ return request({
+ url: `/system/user/${userId}`,
+ method: 'get',
+ });
+}
+
+/**
+ * 新增用户
+ * @param data 用户对象
+ * @returns object
+ */
+export function addUser(data: Record) {
+ return request({
+ url: '/system/user',
+ method: 'post',
+ data: data,
+ });
+}
+
+/**
+ * 修改用户
+ * @param data 用户对象
+ * @returns object
+ */
+export function updateUser(data: Record) {
+ return request({
+ url: '/system/user',
+ method: 'put',
+ data: data,
+ });
+}
+
+/**
+ * 删除用户
+ * @param userId 用户ID
+ * @returns object
+ */
+export function delUser(userId: string | number) {
+ return request({
+ url: `/system/user/${userId}`,
+ method: 'delete',
+ });
+}
+
+/**
+ * 用户密码重置
+ * @param userId 用户ID
+ * @param password 密码
+ * @returns object
+ */
+export function resetUserPwd(userId: string | number, password: string) {
+ return request({
+ url: '/system/user/resetPwd',
+ method: 'put',
+ data: {
+ userId,
+ password,
+ },
+ });
+}
+
+/**
+ * 用户状态修改
+ * @param userId 用户ID
+ * @param status 变更状态值
+ * @returns object
+ */
+export function changeUserStatus(
+ userId: string | number,
+ status: string | number
+) {
+ return request({
+ url: '/system/user/changeStatus',
+ method: 'put',
+ data: {
+ userId,
+ status,
+ },
+ });
+}
diff --git a/src/api/tool/file.ts b/src/api/tool/file.ts
new file mode 100644
index 00000000..6d454b17
--- /dev/null
+++ b/src/api/tool/file.ts
@@ -0,0 +1,195 @@
+import { request } from '@/plugins/http-fetch';
+import { encode } from 'js-base64';
+
+/**
+ * 下载文件
+ * @param filePath 文件路径带/,如:/upload/default/2023/06/xx.png
+ * @param range 断点续传标识,填入字符串 `bytes=${startByte}-${endByte}`
+ * @returns object
+ */
+export async function downloadFile(filePath: string, range?: string) {
+ return request({
+ url: `/file/download/${encode(filePath)}`,
+ method: 'get',
+ headers: range ? { range } : {},
+ responseType: 'blob',
+ });
+}
+
+/**
+ * 下载文件切片
+ * @param filePath 文件路径带/,如:/upload/default/2023/06/xx.png
+ * @param chunkSize 数据块大小MB,默认1MB
+ * @returns bolb
+ */
+export async function downloadFileChunk(
+ filePath: string,
+ chunkSize: number = 1
+): Promise {
+ chunkSize = chunkSize * 1024 * 1024;
+ let start = 0; // 文件块的起始字节
+ let end = chunkSize - 1; // 文件块的结束字节
+ let totalSize = 0; // 文件总大小
+ let downloadedSize = 0; // 已下载的文件大小
+ let filePart: Blob[] = []; // 文件数据块内容
+
+ // 发送带有 Range 请求头的 HTTP 请求
+ async function sendRequest() {
+ const range = `bytes=${start}-${end}`;
+ const res = await downloadFile(filePath, range);
+ if (res.code === 200 && res.status === 206) {
+ // 总大小
+ const contentRange = res.headers.get('content-range') || '0/0';
+ totalSize = parseInt(contentRange.split('/')[1]);
+ // 已下载大小
+ const contentLength = res.headers.get('content-length') || '0';
+ const chunkSize = parseInt(contentLength);
+ // 下一段数据块区间
+ start += chunkSize;
+ end = Math.min(start + chunkSize - 1, totalSize - 1);
+ // 记录下载结果
+ filePart.push(res.data);
+ downloadedSize += chunkSize;
+ // 小于总大小继续下载后续数据
+ if (downloadedSize < totalSize) {
+ await sendRequest();
+ }
+ } else {
+ return res;
+ }
+ }
+
+ await sendRequest();
+ return new Blob(filePart, { type: 'application/octet-stream' });
+}
+
+/**
+ * 上传文件
+ * @param data 表单数据对象
+ * @returns object
+ */
+export function uploadFile(data: FormData) {
+ return request({
+ url: '/file/upload',
+ method: 'post',
+ data,
+ dataType: 'form-data',
+ });
+}
+
+/**
+ * 上传切片文件
+ * @param file 文件对象
+ * @param chunkSize 数据块大小MB,默认1MB
+ * @param subPath 归属子路径, 默认default
+ * @returns
+ */
+export async function uploadFileChunk(
+ fileData: File,
+ chunkSize: number = 1,
+ subPath: string = 'default'
+) {
+ const { name, size } = fileData;
+ const chunkSizeInBytes = chunkSize * 1024 * 1024;
+ // 文件标识使用唯一编码 MD5(文件名+文件大小)
+ const fileIdentifier = `${name}-${size}`;
+ // 文件切分为多少份进行上传
+ const chunksCount = Math.ceil(size / chunkSizeInBytes);
+ // 切块的数据数据用于上传
+ const fileChunks: { index: number; chunk: Blob }[] = [];
+
+ for (let i = 0; i < chunksCount; i++) {
+ const start = i * chunkSizeInBytes;
+ const end = Math.min(start + chunkSizeInBytes, size);
+ fileChunks.push({
+ index: i,
+ chunk: fileData.slice(start, end),
+ });
+ }
+
+ // 检查是否已上传部分数据块
+ const resCheck = await chunkCheck(fileIdentifier, name);
+ if (resCheck.code !== 200) {
+ return resCheck;
+ }
+
+ let uploadedSize = 0;
+ let uploadProgress = 0;
+
+ for (const { index, chunk } of fileChunks) {
+ const chunksIndex = `${index}`;
+ // 跳过已上传块
+ if (resCheck.data.includes(chunksIndex)) {
+ continue;
+ }
+
+ // 上传数据块
+ const formData = new FormData();
+ formData.append('file', chunk, name);
+ formData.append('index', chunksIndex);
+ formData.append('identifier', fileIdentifier);
+
+ const resUpload = await chunkUpload(formData);
+ if (resUpload.code === 200) {
+ uploadedSize += chunk.size;
+ uploadProgress = (uploadedSize / size) * 100;
+ console.log(`上传进度:${uploadProgress}%`);
+ } else {
+ // 上传失败处理
+ break;
+ }
+ }
+
+ // 上传数据完整后合并数据块
+ if (uploadedSize === size) {
+ return await chunkMerge(fileIdentifier, name, subPath);
+ }
+ return { code: 500, msg: '上传出错,请重试' };
+}
+
+/**
+ * 切片文件检查
+ * @param identifier 文件标识
+ * @param fileName 原文件名称
+ * @returns object
+ */
+export function chunkCheck(identifier: string, fileName: string) {
+ return request({
+ url: '/file/chunkCheck',
+ method: 'post',
+ data: { identifier, fileName },
+ });
+}
+
+/**
+ * 切片文件合并
+ * @param identifier 文件标识
+ * @param fileName 原文件名称
+ * @param subPath 文件归属
+ * @returns object
+ */
+export function chunkMerge(
+ identifier: string,
+ fileName: string,
+ subPath: string = 'default'
+) {
+ return request({
+ url: '/file/chunkMerge',
+ method: 'post',
+ data: { identifier, fileName, subPath },
+ });
+}
+
+/**
+ * 切片文件上传
+ * @param data 表单数据对象
+ * @returns object
+ */
+export function chunkUpload(data: FormData) {
+ return request({
+ url: '/file/chunkUpload',
+ method: 'post',
+ data,
+ dataType: 'form-data',
+ });
+}
diff --git a/src/assets/background.svg b/src/assets/background.svg
new file mode 100644
index 00000000..43adc8a6
--- /dev/null
+++ b/src/assets/background.svg
@@ -0,0 +1,69 @@
+
+
\ No newline at end of file
diff --git a/src/assets/donate.jpg b/src/assets/donate.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6d62f6c45a2c062fee3922494ce49ced295891eb
GIT binary patch
literal 494083
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