Compare commits

...

256 Commits

Author SHA1 Message Date
xiaoxian521
46a48a5650 release: update 2.8.5 2022-01-21 16:46:48 +08:00
xiaoxian521
8fa3448af2 chore: update typescript 2022-01-21 16:33:45 +08:00
xiaoxian521
f236829b0f refactor: use @iconify-icons/ep 2022-01-21 16:10:10 +08:00
xiaoxian521
47dea87275 fix: update lintstagedrc 2022-01-18 17:06:15 +08:00
xiaoxian521
5e9198c2e0 fix: vscode setting 2022-01-18 17:05:42 +08:00
xiaoxian521
c9c8f20cc5 docs: update 2022-01-09 18:44:23 +08:00
xiaoxian521
a19c97f152 fix: add vite-plugin-live-reload 2022-01-09 12:11:50 +08:00
xiaoxian521
5e1e9d3c5f feat: 添加线上环境删console插件vite-plugin-remove-console 2022-01-07 17:57:55 +08:00
xiaoxian521
96153f8a14 feat: 添加WindiCSS支持 2022-01-07 17:20:25 +08:00
xiaoxian521
14adf692ab perf: theme 2022-01-07 14:45:21 +08:00
xiaoxian521
aa845fc3f5 release: update 2.8.0 2022-01-04 19:52:05 +08:00
xiaoxian521
079a455181 perf: router 2022-01-04 17:28:36 +08:00
xiaoxian521
07794d000c chore: update element-plus@1.3.0-beta.1 2021-12-31 14:09:59 +08:00
啝裳
e787f46414 Merge pull request #166 from xiaoxian521/perf/storage
perf: storage
2021-12-30 13:57:30 +08:00
lrl
e61d6109d7 perf: modify showLogo type: from string to Boolean 2021-12-29 22:45:18 +08:00
lrl
34eda14473 perf: storage 2021-12-29 21:51:05 +08:00
xiaoxian521
0eb0b7395e perf: layout style 2021-12-29 13:26:56 +08:00
xiaoxian521
73705eb0e4 perf: 优化国际化 2021-12-29 11:21:59 +08:00
xiaoxian521
d94fb0ef06 docs: update 2021-12-28 15:09:17 +08:00
xiaoxian521
17470ecce2 docs: update 2021-12-28 13:21:16 +08:00
一万
12db6966fb feat: guide page (#164)
* feat: add guide page

* perf: guide page
2021-12-27 10:51:25 +08:00
xiaoxian521
5070568b89 perf: theme 2021-12-24 10:46:39 +08:00
lrl
ef91f113ee fix: 动态标签页标记改为refreshRedirect 2021-12-22 22:49:34 +08:00
xiaoxian521
c875d20e83 perf: layout set 2021-12-22 13:40:59 +08:00
xiaoxian521
c86aae7b8b fix: 首页同一图表组件引入多次,只显示一个 2021-12-22 09:53:59 +08:00
一万
ee30cba471 perf: theme (#157) 2021-12-21 22:06:09 +08:00
xiaoxian521
7bcd8a800a perf: theme 2021-12-21 16:57:35 +08:00
xiaoxian521
903e298951 fix: delete realPath 2021-12-21 10:34:28 +08:00
啝裳
955b76f30a feat: ep theme (#156)
* feat: ep-theme

* perf: ep-theme

Co-authored-by: lrl <742798240@qq.com>
2021-12-20 22:27:47 +08:00
lrl
1b052023b6 perf: multiTags route delete realPath 2021-12-20 22:25:45 +08:00
xiaoxian521
3af52cf6c4 docs: update 2021-12-20 16:10:36 +08:00
xiaoxian521
660b6f4be8 feat: 暗黑模式 2021-12-20 14:19:38 +08:00
xiaoxian521
836c9e7cab release: update 2.7.0 2021-12-18 13:56:21 +08:00
xiaoxian521
4ded2a7a0c chore: update 2021-12-18 13:38:53 +08:00
xiaoxian521
dc1caecf1c fix: 修复动态路由子集设置rank为0报错 2021-12-17 18:27:06 +08:00
xiaoxian521
8de3e8b37f docs: update 2021-12-17 16:45:39 +08:00
xiaoxian521
ab93216dbe perf: breadCrumb 2021-12-17 14:46:30 +08:00
lrl
86177e430e fix: breadcrumb 2021-12-17 12:53:41 +08:00
lrl
93ac4fa813 perf: breadcrumb 2021-12-17 12:53:41 +08:00
xiaoxian521
0903008ced perf: menu tree 2021-12-16 13:47:13 +08:00
xiaoxian521
10fa0ee8c8 feat: 添加菜单树结构事例 2021-12-16 11:03:20 +08:00
xiaoxian521
eb0771e7ec feat: 打包后的文件提供传统浏览器兼容性支持 2021-12-15 13:25:18 +08:00
xiaoxian521
39159d5e7b docs: update 2021-12-15 11:41:40 +08:00
xiaoxian521
501891a21c docs: update 2021-12-15 11:36:18 +08:00
啝裳
cbffe31c70 Merge pull request #149 from xiaoxian521/fix/menuModel
fix: tag
2021-12-15 11:08:44 +08:00
xiaoxian521
3ef9444bcb docs: update 2021-12-15 11:05:50 +08:00
xiaoxian521
c81227bb4c docs: update 2021-12-15 11:04:12 +08:00
lrl
05ed941638 fix: menuModel 2021-12-14 22:04:52 +08:00
lrl
77c798eaed fix: menuModel 2021-12-14 21:59:54 +08:00
xiaoxian521
6ab9997a56 fix: router 2021-12-14 13:40:11 +08:00
lrl
b961659c2f fix: router 2021-12-14 13:23:02 +08:00
xiaoxian521
81bf66eca9 fix: router 2021-12-13 23:25:27 +08:00
啝裳
b251f8ff79 Merge pull request #148 from xiaoxian521/fix/router
fix: router
2021-12-13 21:34:29 +08:00
lrl
bae16008db fix: router 2021-12-13 21:13:54 +08:00
xiaoxian521
a0c54a6ac9 fix: types 2021-12-13 17:39:13 +08:00
xiaoxian521
438aab9bfc fix: router 2021-12-13 17:30:08 +08:00
xiaoxian521
e97bd9c8c4 feat: add hasPermissions util 2021-12-13 14:08:12 +08:00
xiaoxian521
653bafaa2b fix: permission directive 2021-12-13 13:54:28 +08:00
xiaoxian521
b82a3d3a2e docs: update 2021-12-13 11:23:12 +08:00
xiaoxian521
b8c8251c64 feat: 路由历史模式从env读取并支持base参数 2021-12-13 11:20:50 +08:00
xiaoxian521
00cc5a88e0 perf: router 2021-12-12 19:46:58 +08:00
xiaoxian521
5d6ed8da33 fix: nest menu 2021-12-12 18:25:04 +08:00
啝裳
d57e0e379e refactor: router (#145)
* refactor: router

* perf: router

* perf: router

* perf: router

Co-authored-by: lrl <742798240@qq.com>
2021-12-12 17:49:19 +08:00
xiaoxian521
7811f6bdeb style: layout 2021-12-11 11:04:00 +08:00
xiaoxian521
113e5f9db2 fix: layout style 2021-12-08 20:02:44 +08:00
xiaoxian521
1758711174 fix: vite build 2021-12-08 14:27:39 +08:00
啝裳
12879f9553 perf(router): refresh (#142)
* feat: set add multiTagsCache

* perf(router): refresh

* fix(multiTags): clear storage when close other tag

Co-authored-by: lrl <742798240@qq.com>
2021-12-07 15:40:10 +08:00
xiaoxian521
d6a358e851 fix: color name 2021-12-07 14:27:08 +08:00
xiaoxian521
9e7d78fd80 fix: layout style 2021-12-06 11:40:11 +08:00
xiaoxian521
570154a4f1 fix: delete useless pictures 2021-12-06 11:05:50 +08:00
xiaoxian521
5564250e7d fix: layout icon 2021-12-06 11:00:58 +08:00
GeeHon
8d65f8ee92 style: 解决eslint换行符告警 (#139) 2021-12-06 08:31:34 +08:00
xiaoxian521
11bf711838 refactor: axios methods and env 2021-12-04 01:16:50 +08:00
xiaoxian521
a845d4f237 fix: types 2021-12-02 10:17:05 +08:00
xiaoxian521
02c3a88ed6 perf: tag 2021-12-01 20:18:00 +08:00
xiaoxian521
a8a3e5b303 perf: tags 2021-12-01 17:20:25 +08:00
一万
cec5af55d9 fix(router): refresh (#137) 2021-11-30 22:57:28 +08:00
一万
d04ba7563a fix: router refresh (#136) 2021-11-30 21:42:30 +08:00
xiaoxian521
0450f004d3 docs: update 2021-11-28 23:43:52 +08:00
xiaoxian521
24a899bba0 chore: update wangeditor 2021-11-28 16:08:09 +08:00
啝裳
6c75296a02 Merge pull request #135 from xiaoxian521/feat/expandTag
feat: expand tag
2021-11-28 15:30:14 +08:00
lrl
6cca0d3ab2 Merge branch 'feat/expandTag' of https://github.com/xiaoxian521/vue-pure-admin into feat/expandTag 2021-11-28 15:08:02 +08:00
lrl
3d34663eda feat: tabs operation view 2021-11-28 15:06:22 +08:00
xiaoxian521
4bbf4c8548 fix: style 2021-11-28 12:07:04 +08:00
xiaoxian521
8685092260 feat: 菜单支持fontawesome、iconfont、ep/icons、自定义svg 2021-11-28 01:07:16 +08:00
啝裳
622464a8a4 Merge pull request #134 from xiaoxian521/refactor/tabs
refactor: tabs
2021-11-27 19:51:21 +08:00
lrl
be3a8a6949 perf: storage tags 2021-11-27 19:04:14 +08:00
一万
3acb65d42c perf: router (#133) 2021-11-27 16:38:18 +08:00
lrl
6d3a8c5a88 fix: update 2021-11-27 15:16:50 +08:00
xiaoxian521
b65b972353 fix: update 2021-11-27 10:05:36 +08:00
xiaoxian521
8c31ca1bad fix: update name 2021-11-26 22:54:29 +08:00
一万
8cb21b6321 Merge pull request #131 from xiaoxian521/perf/progress
perf: not show spinner
2021-11-25 21:45:30 +08:00
lrl
6d6eb98562 perf: not show Spinner 2021-11-25 21:41:33 +08:00
xiaoxian521
aca6a667f3 refactor: tabs 2021-11-25 21:30:44 +08:00
啝裳
d79e63f673 Merge pull request #130 from xiaoxian521/perf/layout
perf: layout
2021-11-25 21:11:37 +08:00
lrl
e67d2df677 perf: layout 2021-11-25 20:52:23 +08:00
xiaoxian521
d44da67dc4 perf: layout 2021-11-25 12:30:02 +08:00
啝裳
9d45e80856 Merge pull request #126 from xiaoxian521/fix/tag
fix(tag): the route is not normally closed and the close icon is repeated
2021-11-22 20:24:52 +08:00
lrl
be66c8bfb9 fix(tag): the route is not normally closed and the close icon is repeated 2021-11-22 20:15:37 +08:00
xiaoxian521
e26a0f949d perf: tag 2021-11-21 11:00:13 +08:00
啝裳
3e991e6e43 Merge pull request #125 from xiaoxian521/fix/sidebar
fix(sidebarItem): span focus and enter the border that appears
2021-11-20 22:41:05 +08:00
lrl
0337a0300c fix(sidebarItem): span focus and enter the border that appears 2021-11-20 22:29:14 +08:00
xiaoxian521
ee8e0eb733 docs: update 2021-11-20 19:47:28 +08:00
啝裳
39cca9ac25 Merge pull request #124 from xiaoxian521/refactor/tag
Refactor/tag
2021-11-20 19:19:22 +08:00
lrl
95140986b9 perf: tag 2021-11-20 19:06:23 +08:00
lrl
034f1577c2 perf: tag 2021-11-20 16:41:30 +08:00
xiaoxian521
c3645fd760 fix: 删除滚动支持 2021-11-20 11:09:52 +08:00
xiaoxian521
b1b236f736 style: fix 2021-11-20 11:00:40 +08:00
xiaoxian521
0b79b65575 refactor: tag 2021-11-19 15:13:28 +08:00
啝裳
067ed96de4 Merge pull request #120 from xiaoxian521/feat/headerNotice
feat: add header notice
2021-11-17 22:48:18 +08:00
xiaoxian521
f25e5d19a4 revert: will roll to the upper level 2021-11-17 22:45:54 +08:00
xiaoxian521
0380d4a17a style: notices style 2021-11-17 22:31:10 +08:00
lrl
89dc4e5052 perf: notice add scrollbar 2021-11-17 18:10:01 +08:00
lrl
12492a522f Merge branch 'main' into feat/headerNotice 2021-11-16 23:53:26 +08:00
lrl
5d9638758b perf: headerNotice 2021-11-16 23:46:34 +08:00
xiaoxian521
6b064bdef9 fix: icon 2021-11-16 22:21:05 +08:00
paobai
7aa895a2b7 perf: storage hooks 2021-11-16 15:52:58 +08:00
xiaoxian521
35f2f9e93f fix: i18n 2021-11-16 13:49:24 +08:00
xiaoxian521
f0a5f02588 fix: i18n 2021-11-16 13:16:04 +08:00
lrl
c4a6a337a3 Merge branch 'main' into feat/headerNotice 2021-11-16 10:04:36 +08:00
hb0730
44a4c9346b fix: i18n (#110) 2021-11-16 09:53:46 +08:00
lrl
bcf533af62 feat: add headerNotice 2021-11-15 23:19:00 +08:00
hb0730
aa8005a982 feat(i18n): 菜单动态支持i18n (#109)
* feat(i18n): 菜单动态支持i18n
2021-11-15 16:45:09 +08:00
hb0730
2d6ad99f6f feat(icon): findIcon function (#107)
* feat(icon): findIcon function

支持ElementPlus icon组件和 FontAwesomeIcon

* fix(menu): 支持第三方icon组件
2021-11-15 16:41:51 +08:00
xiaoxian521
1e1747a355 docs: update 2021-11-14 09:22:15 +08:00
xiaoxian521
6ba0bd7739 docs: update 2021-11-14 09:15:20 +08:00
xiaoxian521
b4088f4612 docs: update 2021-11-14 08:46:43 +08:00
xiaoxian521
3c4619d071 feat: 兼容fontawesome4和5版本 2021-11-13 14:39:38 +08:00
hb0730
10e8b296e3 fix: #100 (#103) 2021-11-12 12:39:08 +08:00
xiaoxian521
b702703472 docs: update 2021-11-10 20:40:06 +08:00
xiaoxian521
7590dc308c chore: update vite-plugin-theme-preprocessor 2021-11-10 18:08:40 +08:00
xiaoxian521
2f457ac6b2 Merge branch 'refactor/theme' into main 2021-11-10 13:30:48 +08:00
xiaoxian521
cbc6743b5a fix: update 2021-11-10 12:37:25 +08:00
xiaoxian521
af01d80db2 fix: update 2021-11-10 11:50:29 +08:00
xiaoxian521
b45a10b98f fix: update 2021-11-10 09:55:01 +08:00
xiaoxian521
cd668c11d8 fix: update 2021-11-10 09:10:32 +08:00
xiaoxian521
753491a7eb fix: update 2021-11-10 09:00:39 +08:00
xiaoxian521
fd4706f2d3 fix: update 2021-11-10 08:39:47 +08:00
xiaoxian521
db580366fd fix: update 2021-11-10 07:59:33 +08:00
xiaoxian521
487920375b fix: update 2021-11-10 07:27:50 +08:00
xiaoxian521
42eb52bd88 fix: update 2021-11-10 07:04:19 +08:00
lrl
3943164ad6 style: sidebar icon position 2021-11-09 22:05:17 +08:00
lrl
e98dee9f0a refactor: setting 2021-11-09 19:24:55 +08:00
xiaoxian521
782cea9995 fix: update 2021-11-09 09:04:20 +08:00
xiaoxian521
41a0fde036 fix: update 2021-11-08 09:21:14 +08:00
xiaoxian521
7d453fdca7 fix: update 2021-11-07 21:11:23 +08:00
xiaoxian521
c935fce27b fix: update 2021-11-07 19:28:33 +08:00
xiaoxian521
ff4b18b73c fix: update 2021-11-07 19:02:42 +08:00
xiaoxian521
cf78f6aa6a fix: update 2021-11-07 17:45:24 +08:00
xiaoxian521
0ad3418239 fix: update vertical style 2021-11-07 16:56:15 +08:00
xiaoxian521
d501339274 chore: update 2021-11-07 13:51:18 +08:00
xiaoxian521
ad2f7358db Merge branch 'main' into refactor/theme 2021-11-07 13:32:38 +08:00
xiaoxian521
a7ca161271 fix: build svg 404 2021-11-06 20:39:29 +08:00
xiaoxian521
3a1f28667b perf: login page 2021-11-06 19:47:57 +08:00
xiaoxian521
ef1c47bac5 Merge branch 'main' of github.com:xiaoxian521/vue-pure-admin into main 2021-11-06 19:16:03 +08:00
xiaoxian521
aa7a073b4a refactor: login page 2021-11-06 19:15:10 +08:00
xiaoxian521
544e474e98 refactor: login page 2021-11-06 17:03:40 +08:00
xiaoxian521
4b16bac5dc feat: update 2021-11-06 16:15:25 +08:00
sedice
ea7266c04c fix: 修复首页柱状图在大屏下显示比例问题 (#97) 2021-11-05 00:07:49 +08:00
xiaoxian521
c18dbea3cd fix: update 2021-11-04 20:34:59 +08:00
xiaoxian521
f19f27510b chore: set vite build minify is false 2021-11-04 12:34:27 +08:00
lrl
57e32bab16 style: hideSidebar add marginLeft 2021-11-04 11:02:01 +08:00
xiaoxian521
e63fe92cd9 fix: update 2021-11-04 10:25:01 +08:00
xiaoxian521
c95126adf5 fix: update 2021-11-04 10:20:22 +08:00
xiaoxian521
54a0e457b4 feat: 剔除vxe强依赖 2021-11-03 23:55:18 +08:00
xiaoxian521
8436f964e4 Merge branch 'main' into refactor/theme 2021-11-03 23:24:53 +08:00
一万
709cb87c2b style: editor add margin (#96) 2021-11-03 22:28:15 +08:00
一万
e0551251d3 style: perf sidebar style (#95) 2021-11-03 20:51:16 +08:00
xiaoxian521
dae0b5dc08 workflow: update 2021-11-03 14:20:54 +08:00
xiaoxian521
077276463f workflow: update 2021-11-03 14:18:16 +08:00
xiaoxian521
43a8baee3d workflow: update 2021-11-03 14:16:34 +08:00
xiaoxian521
91fe227e8c chore: update 2021-11-03 14:04:13 +08:00
xiaoxian521
3f526873d8 chore: update 2021-11-03 14:01:48 +08:00
xiaoxian521
def4c60395 workflow: update 2021-11-03 14:00:50 +08:00
xiaoxian521
6c02e97157 chore: use pnpm replace yarn 2021-11-03 13:58:24 +08:00
一万
c25b130b7d perf: perf sidebar (#91) 2021-11-03 10:13:27 +08:00
xiaoxian521
c266a675a2 feat: update 2021-11-02 13:26:25 +08:00
xiaoxian521
6b151eae1b Merge branch 'main' into refactor/theme 2021-11-02 07:48:14 +08:00
xiaoxian521
0615902632 perf: home page 2021-11-01 13:31:49 +08:00
xiaoxian521
b773fb582d perf: style 2021-10-31 21:52:39 +08:00
一万
9ddf449ea7 perf: perf style (#89)
perf: perf style
2021-10-31 20:24:57 +08:00
xiaoxian521
8a14519467 feat: update 2021-10-31 15:42:46 +08:00
xiaoxian521
321b9da9a8 feat: update 2021-10-31 14:19:08 +08:00
xiaoxian521
594efc6204 feat: update 2021-10-31 13:42:51 +08:00
xiaoxian521
c819554e54 feat: update 2021-10-31 10:49:35 +08:00
xiaoxian521
3e12372d9c chore: update 2021-10-31 10:20:36 +08:00
艾阳
0fb7b5e983 fix: 修改面包屑重定向到第一个子级 (#87) 2021-10-31 00:40:01 +08:00
xiaoxian521
9d061c6406 feat: update 2021-10-30 22:11:18 +08:00
xiaoxian521
5f349775a8 feat: update 2021-10-30 21:14:25 +08:00
一万
4e04fdd657 fix(panel): fix setting tooltip (#85)
* fix(panel): fix setting tooltip
2021-10-30 19:50:47 +08:00
xiaoxian521
c418ab03a2 style: 优化样式 2021-10-30 18:56:37 +08:00
hb0730
8ffd341443 fix(axios): 修复封装的axios请求过快beforeRequestCallback,beforeResponseCallback只触发一次 (#84) 2021-10-30 13:56:42 +08:00
一万
72224717f9 style: 恢复标签页横向滚动条 (#83)
* style: 恢复标签页横向滚动条
2021-10-30 13:19:41 +08:00
一万
d4237aa596 fix: 修复菜单隐藏,内容显示问题 (#81) 2021-10-29 22:04:51 +08:00
一万
ae72cccbb9 fix: 菜单名称过长添加tooltip (#78)
* fix: 菜单名称过长添加tooltip
2021-10-29 18:41:57 +08:00
xiaoxian521
3389f3118a fix: 修复封装的axios请求过快beforeRequestCallback只触发一次 2021-10-29 15:37:48 +08:00
xiaoxian521
15ccd5db5b fix: update 2021-10-29 15:07:06 +08:00
xiaoxian521
a28eb4b203 feat: update 2021-10-29 14:50:10 +08:00
xiaoxian521
f921996563 feat: update 2021-10-29 14:09:05 +08:00
xiaoxian521
71bd7e89d4 feat: update 2021-10-29 14:09:05 +08:00
xiaoxian521
02f2cd9747 feat: update 2021-10-29 14:09:04 +08:00
xiaoxian521
af6a1b03cd fix: update 2021-10-29 14:09:04 +08:00
xiaoxian521
b248d9ea31 fix: delete toggleTheme.ts 2021-10-29 14:09:04 +08:00
xiaoxian521
3851d284bf feat: update 2021-10-29 14:09:04 +08:00
xiaoxian521
b520e234a1 feat: update 2021-10-29 14:08:00 +08:00
xiaoxian521
b40cd2db74 fix: xgplayer path error 2021-10-29 14:08:00 +08:00
xiaoxian521
fc4bfc35d7 refactor: theme 2021-10-29 14:08:00 +08:00
huohuoit
769e684c61 * feat:新增vscode中的vue3.2.setup-snippets代码片段文件
* feat:新增vscode中的vue3.2.setup-snippets代码片段文件
2021-10-28 11:43:34 +08:00
一万
25c37bb2fa fix: xgplayer path error (#76) 2021-10-27 18:27:27 +08:00
一万
ab06aa00ed fix: 修复取消固定头部问题 (#74) 2021-10-27 14:45:40 +08:00
啝裳
1fa5793ec4 fix: 修复取消固定头部问题 (#75)
* fix: 修复取消固定头部问题

* perf: simplify the layout code
2021-10-27 14:40:31 +08:00
xiaoxian521
5a78685ac9 docs: update README.md 2021-10-26 12:35:06 +08:00
一万
ae161e8b48 feat(backtop): add backtop (#71) 2021-10-25 08:55:17 +08:00
lrl
8d2824fe82 perf: 隐藏标签页功能优化 2021-10-24 15:39:01 +08:00
xiaoxian521
822261c922 docs: update README.md 2021-10-24 14:02:24 +08:00
xiaoxian521
3e4b49b4be style: 调整地图的高度 2021-10-24 13:54:36 +08:00
xiaoxian521
c5d6d2c76e refactor: login page 2021-10-24 13:48:33 +08:00
xiaoxian521
2d9c185b4e style: 修改layout样式 2021-10-24 11:53:43 +08:00
一万
70af35dbf5 fix: 修复隐藏标签页问题 (#69)
* fix: 修复隐藏标签页问题
2021-10-23 22:50:03 +08:00
xiaoxian521
7dcf98a178 style: 优化导航样式 2021-10-23 20:40:32 +08:00
xiaoxian521
089dea8441 Merge branches 'main' and 'main' of github.com:xiaoxian521/vue-pure-admin into main 2021-10-23 19:16:12 +08:00
xiaoxian521
c7b61febc3 docs: update README.md 2021-10-23 19:15:54 +08:00
一万
8b8cd52f64 style(flow-chart): 流程图数据弹窗样式优化 (#68) 2021-10-22 21:21:42 +08:00
xiaoxian521
eb8d3ca96e perf: icon 2021-10-22 20:38:19 +08:00
xiaoxian521
7e6768208d docs: update README.md 2021-10-22 17:52:38 +08:00
xiaoxian521
3980c9a876 docs: update readme.me 2021-10-22 17:49:48 +08:00
xiaoxian521
ca849c94e2 fix: 修复流程图打包后出错 2021-10-21 18:55:46 +08:00
xiaoxian521
430e5d75b0 docs: update readme.me 2021-10-21 13:00:11 +08:00
xiaoxian521
5f294356a9 docs: update readme.md 2021-10-21 10:39:21 +08:00
xiaoxian521
4a6fcdb8e5 docs: update readme.md 2021-10-21 10:35:16 +08:00
xiaoxian521
52394cc550 docs: update docs 2021-10-21 09:51:01 +08:00
xiaoxian521
f7036143a4 chore: update some packages version 2021-10-20 22:30:52 +08:00
xiaoxian521
7d0367dc58 Merge branch 'main' of github.com:xiaoxian521/vue-pure-admin into main 2021-10-20 21:26:54 +08:00
xiaoxian521
f872ea1a23 fix: 修复vxe-table打包找不到css问题 2021-10-20 21:26:39 +08:00
Ten-K
016948d852 fix(tag): 修复关闭左侧/右侧标签页时未删除缓存路由问题 (#66) 2021-10-20 15:45:35 +08:00
xiaoxian521
7724d6443e chore: update element-plus lastest 2021-10-20 11:40:22 +08:00
xiaoxian521
7013e57d1e fix: 右键菜单z-index问题 2021-10-19 18:58:47 +08:00
Ten-K
639a69d579 fix(tag): 删除非当前激活tag时不切换tag (#60)
* fix(tag): 删除非当前激活tag时不切换tag

* fix(tag): 修复在激活菜单时选择关闭左侧标签后当前激活的菜单非选择菜单

* perf: 自定义去重函数更改为lodash-es的uniqBy
2021-10-19 13:58:17 +08:00
xiaoxian521
b2c05e4397 docs: 更新文档 2021-10-19 12:36:13 +08:00
qingguizhang
f76f43ca0e style: 页面内全屏效果样式
* style: 页面内全屏效果样式
2021-10-19 11:59:17 +08:00
xiaoxian521
a322b8497e perf: 页面内全屏效果 2021-10-19 10:45:41 +08:00
xiaoxian521
b75eecabd2 Merge branch 'main' of github.com:xiaoxian521/vue-pure-admin into main 2021-10-19 10:07:44 +08:00
xiaoxian521
4aaffc53a8 style: use :deep() replace >>> 2021-10-19 10:07:24 +08:00
黄兵
a2a793f84e fix(icon): icon vary in size 2021-10-19 10:01:23 +08:00
黄兵
d551f372e4 style(element-ui.scss): move to component css 2021-10-19 10:01:23 +08:00
黄兵
04f4815f04 style(element-ui.scss): remove global .el-dialog
change .el-dialog to .flow-dialog
2021-10-19 10:01:23 +08:00
hb0730
cec2ffd3eb style(element-ui.scss): remove global .el-dialog
* style(element-ui.scss):  remove global  .el-dialog

change .el-dialog to .flow-dialog

* style(element-ui.scss): move to component css
2021-10-19 09:11:46 +08:00
xiaoxian521
1b56c86e07 docs: 添加配套视频教程地址 2021-10-18 22:04:57 +08:00
xiaoxian521
8b1b37b727 Merge branch 'main' of github.com:xiaoxian521/vue-pure-admin into main 2021-10-18 16:02:41 +08:00
xiaoxian521
f45588e811 fix: 主界面最外层正常情况下出现滚动条 2021-10-18 16:02:26 +08:00
zhuoyue03007
7f34b63569 perf: 主界面布局滚动条显示样式处理 (#59)
perf: 主界面布局滚动条采用el-scrollbar
2021-10-18 15:05:23 +08:00
xiaoxian521
db4855737b fix: 字典管理页面点击编辑弹出遮罩层没有覆盖到整个页面,菜单还能选择 2021-10-18 13:02:36 +08:00
xiaoxian521
ee7241da3f fix: 修复清空缓存并退出登陆后再次进入页面routerArrays未初始化问题 2021-10-18 10:34:28 +08:00
xiaoxian521
3cd4f340a1 types: ignore db.ts 2021-10-15 14:08:47 +08:00
xiaoxian521
a7c12d93d3 types: optimizate layout 2021-10-15 13:19:12 +08:00
xiaoxian521
e22e19552a perf: delete settings.ts use serverConfig.json 2021-10-15 11:38:43 +08:00
186 changed files with 14326 additions and 8211 deletions

14
.env
View File

@@ -1,14 +1,2 @@
# port
# 项目本地运行端口号
VITE_PORT = 8848
# title
VITE_TITLE = vue-pure-admin
# version
VITE_VERSION = 2.1.0
# open
VITE_OPEN = false
# public path
VITE_PUBLIC_PATH = /
# Cross-domain proxy, you can configure multiple
VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ]

View File

@@ -1,14 +1,14 @@
# port
# 项目本地运行端口号
VITE_PORT = 8848
# title
VITE_TITLE = vue-pure-admin
# version
VITE_VERSION = 2.1.0
# open
VITE_OPEN = false
# public path
# 开发环境读取配置文件路径
VITE_PUBLIC_PATH = /
# Cross-domain proxy, you can configure multiple
VITE_PROXY = [ ["/api", "http://127.0.0.1:3000" ] ]
# 开发环境代理
VITE_PROXY_DOMAIN = /api
# 开发环境路由历史模式
VITE_ROUTER_HISTORY = "hash"
# 开发环境后端地址
VITE_PROXY_DOMAIN_REAL = "http://127.0.0.1:3000"

View File

@@ -1,2 +1,11 @@
# public path
VITE_PUBLIC_PATH = /manages/
# 线上环境项目打包路径
VITE_PUBLIC_PATH = /
# 线上环境路由历史模式
VITE_ROUTER_HISTORY = "hash"
# 线上环境后端地址
VITE_PROXY_DOMAIN_REAL = ""
# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false

View File

@@ -70,6 +70,12 @@ module.exports = {
argsIgnorePattern: "^_",
varsIgnorePattern: "^_"
}
],
"prettier/prettier": [
"error",
{
endOfLine: "auto"
}
]
}
};

View File

@@ -45,11 +45,21 @@ jobs:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: "16"
registry-url: https://registry.npmjs.com/
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: latest
- name: Build
run: |
yarn install
yarn lint
yarn build
pnpm install
pnpm lint
env:
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: main

5
.gitignore vendored
View File

@@ -5,9 +5,10 @@ dist-ssr
*.local
.eslintcache
yarn.lock
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-error.log*
.pnpm-debug.log
tests/**/coverage/
# Editor directories and files

View File

@@ -3,7 +3,7 @@ command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Yarn
# Workaround for Windows 10, Git Bash and Pnpm
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

View File

@@ -1,8 +1,6 @@
module.exports = {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"
],
"{!(package)*.json,.!(browserslist)*rc}": ["prettier --write--parser json"],
"package.json": ["prettier --write"],
"*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
"*.{vue,css,scss,postcss,less}": ["stylelint --fix", "prettier --write"],

11
.markdownlint.json Normal file
View File

@@ -0,0 +1,11 @@
{
"default": true,
"MD003": false,
"MD033": false,
"MD013": false,
"MD001": false,
"MD025": false,
"MD024": false,
"MD007": { "indent": 4 },
"no-hard-tabs": false
}

16
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"recommendations": [
"johnsoncodehk.vscode-typescript-vue-plugin",
"voorjaar.windicss-intellisense",
"vscode-icons-team.vscode-icons",
"davidanson.vscode-markdownlint",
"stylelint.vscode-stylelint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"johnsoncodehk.volar",
"lokalise.i18n-ally",
"mikestead.dotenv",
"eamodio.gitlens",
"antfu.iconify"
]
}

26
.vscode/settings.json vendored
View File

@@ -1,15 +1,6 @@
{
// You should install these plugins:
// ESLint
// Prettier - Code formatter
// stylelint
// vscode-icons
// TypeScript Vue Plugin (Volar)
// Vue Language Features (Volar)
"terminal.integrated.rendererType": "dom",
"editor.formatOnType": true,
"editor.formatOnSave": true,
"window.zoomLevel": 1,
"javascript.updateImportsOnFileMove.enabled": "always",
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
@@ -25,23 +16,28 @@
"editor.suggestSelection": "first",
"editor.acceptSuggestionOnCommitCharacter": false,
"css.lint.propertyIgnoredDueToDisplay": "ignore",
// Prevent inline styles from being automatically formatted to all lowercase
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
// Automatically fix some syntax errors of ts
"tslint.autoFixOnSave": true,
"files.associations": {
// Specifies the location of snippets in the suggestion widget
"editor.snippetSuggestions": "top"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"cSpell.userWords": ["sourcemap", "vite"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
},
"typescript.tsdk": "node_modules/typescript/lib",
"i18n-ally.localesPaths": ["src/plugins/i18n"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": true,
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": ["vue", "react"]
}

17
.vscode/vue3.2.code-snippets vendored Normal file
View File

@@ -0,0 +1,17 @@
{
"Vue3.2+快速生成模板": {
"prefix": "Vue3.2+",
"body": [
"<script setup lang='ts'>",
"</script>\n",
"<template>",
"\t<div>\n",
"\t</div>",
"</template>\n",
"<style scoped>\n",
"</style>",
"$2"
],
"description": "Vue3.2+"
}
}

View File

@@ -1,3 +1,61 @@
# 2.8.5 (2022-1-21)
### 🎫 Feat
- Added `WindiCSS` support
- Add online environment remove console plugin `vite-plugin-remove-console`
### ✔️ refactor
- Replace `@element-plus/icons-vue` with `@iconify-icons/ep`
# 2.8.0(2022-1-4)
### 🎫 Feat
-Added dark theme
-Add element-plus custom theme
-Add guide page
### 🍏 Perf
-Optimize internationalization, compatible with the vscode plug-in i18n Ally smart reminder
-Optimize the back-end return routing structure
-Optimize local storage, with four built-in buttons `responsive-configure`, `responsive-locale`, `responsive-layout`, `responsive-tags`, which are basic configuration, international configuration, layout configuration, and tab persistent configuration
# 2.7.0(2021-12-18)
### 🎫 Feat
- New tab reuse
- New message reminder template
- Added front-end menu tree structure example
- Refactor routing, optimize permissions modules, and bring a more convenient experience
- Refactor the env environment and http request to bring a more convenient experience
- Currently, the tabs of the platform are forced to associate with local storage. The next step is to put the tabs in the memory by default and support configurable persistent tabs
- Navigation menu icons support fontawesome, iconfont, remixicon, element-plus/icons, custom svg
- Update font-awesome to version 5.0, because versions below 5.0 are no longer officially maintained, but the platform will still be compatible with font-awesome4 version
### 🍏 Perf
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)
### 🎫 Feat
- Refactored navigation theme color, supports multiple color schemes
- Refactored login page, illustration style
### 🍏 Perf
- Optimize the navigation style
- Eliminate strong navigation dependence on vxe-table
- Synchronously update element-plus, replace Font Icon with SVG Icon
# 2.1.0(2021-10-14)
### 🎫 Feat

View File

@@ -1,3 +1,61 @@
# 2.8.5 (2022-1-21)
### 🎫 Feat
- Added `WindiCSS` support
- Add online environment remove console plugin `vite-plugin-remove-console`
### ✔️ refactor
- Replace `@element-plus/icons-vue` with `@iconify-icons/ep`
# 2.8.0(2022-1-4)
### 🎫 Feat
-Added dark theme
-Add element-plus custom theme
-Add guide page
### 🍏 Perf
-Optimize internationalization, compatible with the vscode plug-in i18n Ally smart reminder
-Optimize the back-end return routing structure
-Optimize local storage, with four built-in buttons `responsive-configure`, `responsive-locale`, `responsive-layout`, `responsive-tags`, which are basic configuration, international configuration, layout configuration, and tab persistent configuration
# 2.7.0(2021-12-18)
### 🎫 Feat
- New tab reuse
- New message reminder template
- Added front-end menu tree structure example
- Refactor routing, optimize permissions modules, and bring a more convenient experience
- Refactor the env environment and http request to bring a more convenient experience
- Currently, the tabs of the platform are forced to associate with local storage. The next step is to put the tabs in the memory by default and support configurable persistent tabs
- Navigation menu icons support fontawesome, iconfont, remixicon, element-plus/icons, custom svg
- Update font-awesome to version 5.0, because versions below 5.0 are no longer officially maintained, but the platform will still be compatible with font-awesome4 version
### 🍏 Perf
- Optimize the tab page to bring a better interactive experience
- Routing title supports direct writing in Chinese, which can be separated from internationalization
- Route history mode is read from env and supports base parameter
- Packaged files provide traditional browser compatibility support, configure VITE_LEGACY to true
# 2.6.0(2021-11-10)
### 🎫 Feat
- Refactored navigation theme color, supports multiple color schemes
- Refactored login page, illustration style
### 🍏 Perf
- Optimize the navigation style
- Eliminate strong navigation dependence on vxe-table
- Synchronously update element-plus, replace Font Icon with SVG Icon
# 2.1.0(2021-10-14)
### 🎫 Feat

View File

@@ -1,3 +1,61 @@
# 2.8.5(2022-1-21)
### 🎫 Feat
- 添加 `WindiCSS` 支持
- 添加线上环境删 console 插件`vite-plugin-remove-console`
### ✔️ refactor
- 使用`@iconify-icons/ep`替换`@element-plus/icons-vue`
# 2.8.0(2022-1-4)
### 🎫 Feat
- 添加暗黑主题
- 添加 element-plus 自定义主题
- 添加引导页
### 🍏 Perf
- 优化国际化,兼容 vscode 插件 i18n Ally 智能提醒
- 优化后端返回路由结构
- 优化本地存储,内置四个键`responsive-configure``responsive-locale``responsive-layout``responsive-tags`,分别为基本配置、国际化配置、布局配置、标签页持久化配置
# 2.7.0(2021-12-18)
### 🎫 Feat
- 新增标签页复用
- 新增消息提醒模版
- 新增前端菜单树结构例子
- 重构路由,优化权限模块,带来更方便的体验
- 重构 env 环境和 http 请求,带来更方便的体验
- 目前平台的标签页强制关联了本地存储,下一步标签页默认放到内存中并支持可配置持久化标签页
- 导航菜单图标支持 fontawesome、iconfont、remixicon、element-plus/icons、自定义 svg
- 更新 font-awesome 到 5.0 版本,因为 5.0 以下的版本官方不再维护,但平台依旧会兼容 font-awesome4 版本
### 🍏 Perf
- 优化标签页,带来更好的交互体验
- 路由 title 支持直接写中文,可脱离国际化
- 路由历史模式从 env 读取并支持 base 参数
- 打包后的文件提供传统浏览器兼容性支持,配置 VITE_LEGACY 为 true
# 2.6.0(2021-11-10)
### 🎫 Feat
- 重构导航主题色,支持多种配色
- 重构登录页,插画风格
### 🍏 Perf
- 优化导航样式
- 剔除导航强依赖 vxe-table
- 同步更新 element-plus使用 SVG Icon 替换 Font Icon
# 2.1.0(2021-10-14)
### 🎫 Feat

View File

@@ -1,37 +1,36 @@
<h1>vue-pure-admin</h1>
[![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE)
![GitHub license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin?style=flat)
![GitHub stars](https://img.shields.io/github/stars/xiaoxian521/vue-pure-admin?color=fa6470&style=flat)
![GitHub forks](https://img.shields.io/github/forks/xiaoxian521/vue-pure-admin?style=flat)
**English** | [中文](./README.md)
## Introduction
vue-pure-admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite2`, `TypeScript`, `Element-Plus` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
vue-pure-admin is a free and open source middle and back-end template. Using the latest `vue3` `vite2` `Element-Plus` `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
## Supporting Video
- [Click Watch Tutorial](https://www.bilibili.com/video/BV1534y1S7HV)
- [Click Watch UI Design](https://www.bilibili.com/video/BV17g411T7rq)
## Docs
- [Click Watch Docs](https://pure-admin-doc.vercel.app)
## Thin
- [Click Watch Thin](https://github.com/xiaoxian521/pure-admin-thin)
## Preview
- [vue-pure-admin](http://yiming_chang.gitee.io/manages)
Click to log in without password
<p align="center">
<img alt="PureAdmin Logo" width="100%" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f5ee80eee1014fb4a53c5bb37574a5f5~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dec0672a62e141f3b7f626c22ff6c7ef~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f586f1353de74b1b88cc9f89fce2146e~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a28fc0af7ac44e3b8f30469cba4a9993~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a17e54329cda4d76aa9c1c4f2a4715d3~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d884fb611da74ee0bdc17c29014d0260~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/abed44ac1f2744e897c28d1689bcb517~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf2f068650f44a0787c699f5a20c75a6~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73c575dd06474731ad8ab9d853f1ddfd~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99389b90f5ac4db9b0d61d99dd9a1454~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1546f1c6014446db6c9983934aedc86~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cfb0093b77c34e87b094daaa4304bc2d~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fe133cc6db3245f9b1b37f231d040550~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d3110a12d63e4f6fb314e60bf18bdb66~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/45b93ec453e3406a939affe65ddcc803~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cdc2dc88c1ef4aafbaaade820442c986~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f4c91b162206485b88cc58a72ff54a01~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/549c3184697f4d268a78c9833e5ec2ea~tplv-k3u1fbpfcp-watermark.awebp?">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/381fc957fac143db9f06efdd389d88a3~tplv-k3u1fbpfcp-watermark.awebp?">
</p>
### Use Gitpod
@@ -55,20 +54,20 @@ git clone https://github.com.cnpmjs.org/xiaoxian521/vue-pure-admin.git
```bash
cd vue-pure-admin
yarn install
pnpm install
```
- run
```bash
yarn serve
pnpm serve
```
- build
```bash
yarn build
pnpm build
```
## Change Log
@@ -121,16 +120,32 @@ Support modern browsers, not IE
## Donate
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support
![donate](http://yiming_chang.gitee.io/manages/pay.jpg)
<img src="http://yiming_chang.gitee.io/manages/pay.jpg" width="150px" height="150px" />
## Exchange Group
## WeChat Exchange Group
Please scan the code to join the WeChat exchange group, if you have any questions, you can communicate in the group!
For the better development of the project, you can choose to donate 10 yuan and add the following WeChat to pull you into the group. After adding, please consciously send a screenshot of the donation
![group](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0c5f882422bd47b5af691906ea994ccf~tplv-k3u1fbpfcp-watermark.awebp?)
<img src="http://yiming_chang.gitee.io/manages/kf.jpg" width="150px" height="195px" />
## License
In principle, no fees and copyrights are charged, so you can use it with confidence
[MIT © xiaoxian521-2020](./LICENSE)
## Backers
Thank you very much for your support, I believe the project will get better and better! ! ! :heart:
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen |
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: |
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> |
## Contributors
This project exists thanks to all the people who contribute!!! :heart:
<a href="https://github.com/xiaoxian521/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=xiaoxian521/vue-pure-admin" /></a>

View File

@@ -1,37 +1,36 @@
<h1>vue-pure-admin</h1>
[![license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin.svg)](LICENSE)
![GitHub license](https://img.shields.io/github/license/xiaoxian521/vue-pure-admin?style=flat)
![GitHub stars](https://img.shields.io/github/stars/xiaoxian521/vue-pure-admin?color=fa6470&style=flat)
![GitHub forks](https://img.shields.io/github/forks/xiaoxian521/vue-pure-admin?style=flat)
**中文** | [English](./README.en-US.md)
## 简介
vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3`,`vite2`,`TypeScript`,`Element-Plus`等主流技术开发,开箱即用的中后台前端解决方案,也可用于学习参考。
vue-pure-admin 是一个免费开源的中后台模版。使用了最新的`vue3` `vite2` `Element-Plus` `TypeScript`等主流技术开发,开箱即用的中后台前端解决方案,也可用于学习参考。
## 配套视频
- [点我查看教程](https://www.bilibili.com/video/BV1534y1S7HV)
- [点我查看 UI 设计](https://www.bilibili.com/video/BV17g411T7rq)
## 配套文档
- [点我查看文档](https://pure-admin-doc.vercel.app)
## 精简版
- [点我查看精简版](https://github.com/xiaoxian521/pure-admin-thin)
## 预览
- [vue-pure-admin](http://yiming_chang.gitee.io/manages)
点击免密登录
<p align="center">
<img alt="PureAdmin Logo" width="100%" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f5ee80eee1014fb4a53c5bb37574a5f5~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dec0672a62e141f3b7f626c22ff6c7ef~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f586f1353de74b1b88cc9f89fce2146e~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a28fc0af7ac44e3b8f30469cba4a9993~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a17e54329cda4d76aa9c1c4f2a4715d3~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d884fb611da74ee0bdc17c29014d0260~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/abed44ac1f2744e897c28d1689bcb517~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cf2f068650f44a0787c699f5a20c75a6~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/73c575dd06474731ad8ab9d853f1ddfd~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/99389b90f5ac4db9b0d61d99dd9a1454~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f1546f1c6014446db6c9983934aedc86~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cfb0093b77c34e87b094daaa4304bc2d~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fe133cc6db3245f9b1b37f231d040550~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d3110a12d63e4f6fb314e60bf18bdb66~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/45b93ec453e3406a939affe65ddcc803~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cdc2dc88c1ef4aafbaaade820442c986~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f4c91b162206485b88cc58a72ff54a01~tplv-k3u1fbpfcp-watermark.image">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b4857fc7eb7d4c0f8deeefc644c1f7dd~tplv-k3u1fbpfcp-watermark.awebp?">
<img alt="PureAdmin Logo" width="100%" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/549c3184697f4d268a78c9833e5ec2ea~tplv-k3u1fbpfcp-watermark.awebp?">
<img alt="PureAdmin Logo" width="100%" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/381fc957fac143db9f06efdd389d88a3~tplv-k3u1fbpfcp-watermark.awebp?">
</p>
### 使用 Gitpod
@@ -55,20 +54,20 @@ git clone https://github.com.cnpmjs.org/xiaoxian521/vue-pure-admin.git
```bash
cd vue-pure-admin
yarn install
pnpm install
```
- 运行
```bash
yarn serve
pnpm serve
```
- 打包
```bash
yarn build
pnpm build
```
## 更新日志
@@ -121,16 +120,32 @@ yarn build
## 捐赠
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持!
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持
![donate](http://yiming_chang.gitee.io/manages/pay.jpg)
<img src="http://yiming_chang.gitee.io/manages/pay.jpg" width="150px" height="150px" />
## 交流群
## 微信交流群
请扫码加入微信交流群,有问题可以在群里沟通!
为了项目更好的发展,你可选择捐赠 10 元后添加下图微信拉你进群,添加后请自觉发捐赠截图
![group](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0c5f882422bd47b5af691906ea994ccf~tplv-k3u1fbpfcp-watermark.awebp?)
<img src="http://yiming_chang.gitee.io/manages/kf.jpg" width="150px" height="195px" />
## License
## 许可证
原则上不收取任何费用及版权,可以放心使用
[MIT © xiaoxian521-2020](./LICENSE)
## 捐赠者
非常感谢你们的支持,相信项目会越来越好!!!:heart:
| xueyuheng | taolei1990 | hang-kim | madwolfcrazy | limuen |
| :--------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: |
| <a href="https://github.com/xueyuheng"><img src="https://avatars.githubusercontent.com/u/48202935?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/taolei1990"><img src="https://avatars.githubusercontent.com/u/23173640?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/hang-kim"><img src="https://avatars.githubusercontent.com/u/52914259?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/madwolfcrazy"><img src="https://avatars.githubusercontent.com/u/223671?v=4" width="60px" height="60px" /></a> | <a href="https://github.com/limuen"><img src="https://avatars.githubusercontent.com/u/31790606?v=4" width="60px" height="60px" /></a> |
## 贡献者
这个项目的存在感谢所有做出贡献的人!!!:heart:
<a href="https://github.com/xiaoxian521/vue-pure-admin/graphs/contributors"><img src="https://contrib.rocks/image?repo=xiaoxian521/vue-pure-admin" /></a>

View File

@@ -1,6 +0,0 @@
const productPlugins = [];
process.env.NODE_ENV === "production" &&
productPlugins.push("transform-remove-console");
module.exports = {
plugins: [...productPlugins]
};

View File

@@ -1,5 +1,14 @@
// 处理环境变量
const warpperEnv = (envConf: Recordable): ViteEnv => {
const ret: any = {};
// 此处为默认值,无需修改
const ret: ViteEnv = {
VITE_PORT: 8848,
VITE_PUBLIC_PATH: "",
VITE_PROXY_DOMAIN: "",
VITE_PROXY_DOMAIN_REAL: "",
VITE_ROUTER_HISTORY: "",
VITE_LEGACY: false
};
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, "\n");
@@ -9,13 +18,6 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
if (envName === "VITE_PORT") {
realName = Number(realName);
}
if (envName === "VITE_PROXY" && realName) {
try {
realName = JSON.parse(realName.replace(/'/g, '"'));
} catch (error) {
realName = "";
}
}
ret[envName] = realName;
if (typeof realName === "string") {
process.env[envName] = realName;
@@ -25,8 +27,15 @@ const warpperEnv = (envConf: Recordable): ViteEnv => {
}
return ret;
};
// 跨域代理重写
const regExps = (value: string, reg: string): string => {
return value.replace(new RegExp(reg, "g"), "");
};
// 环境变量
const loadEnv = (): ViteEnv => {
return import.meta.env;
};
export { loadEnv, warpperEnv };
export { warpperEnv, regExps, loadEnv };

View File

@@ -1,19 +0,0 @@
type ProxyItem = [string, string];
type ProxyList = ProxyItem[];
const regExps = (value: string, reg: string): string => {
return value.replace(new RegExp(reg, "g"), "");
};
export function createProxy(list: ProxyList = []) {
const ret: any = {};
for (const [prefix, target] of list) {
ret[prefix] = {
target: target,
changeOrigin: true,
rewrite: (path: string) => regExps(path, prefix)
};
}
return ret;
}

View File

@@ -5,7 +5,7 @@
<link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/iconfont.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>后台管理系统</title>
<title>vue-pure-admin</title>
<script src="/sortable.min.js"></script>
<script>
window.process = {};
@@ -27,94 +27,78 @@
display: flex;
justify-content: center;
align-items: center;
background: #000;
overflow: hidden;
font-family: "Reggae One", cursive;
}
p {
font-size: 8vw;
overflow: hidden;
-webkit-text-stroke: 3px #7272a5;
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 2.5em;
height: 2.5em;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation: loadAnimation 1.8s infinite ease-in-out;
animation: loadAnimation 1.8s infinite ease-in-out;
}
span {
display: block;
font-size: 20px;
overflow: hidden;
color: green;
text-align: center;
.loader {
color: #406eeb;
font-size: 10px;
margin: 80px auto;
position: relative;
text-indent: -9999em;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
p::before {
.loader:before,
.loader:after {
content: "";
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-image: linear-gradient(45deg, #ff269b, #2ab5f5, #ffbf00);
mix-blend-mode: multiply;
}
p::after {
content: "";
background: radial-gradient(circle, #fff, #000 50%);
background-size: 25% 25%;
position: absolute;
top: -100%;
left: -100%;
right: 0;
bottom: 0;
mix-blend-mode: color-dodge;
animation: mix 2s linear infinite;
.loader:before {
left: -3.5em;
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
@keyframes mix {
to {
transform: translate(50%, 50%);
.loader:after {
left: 3.5em;
}
@-webkit-keyframes loadAnimation {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
@keyframes loadAnimation {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
</style>
<div class="g-container">
<p>Pure-Admin</p>
<span class="_develop"></span>
<div class="loader">Loading...</div>
</div>
</div>
<script>
// 此代码仅用于开发环境的友好提示项目打包前请去掉这段js代码 This code is only used as a friendly reminder of the development environment, please remove this js code before packaging the project
window.onload = function () {
(function () {
const ua = navigator.userAgent.toLowerCase();
const re = /(msie|firefox|chrome|opera|version).*?([\d.]+)/;
const m = ua.match(re);
const Sys = {
browser: m[1].replace(/version/, "'safari"),
version: m[2]
};
const browser = Array.of("chrome", "firefox").includes(Sys.browser);
const version = parseFloat(Sys.version);
const el = document.querySelector("._develop");
if (el) {
if (browser && version >= 90) {
let success =
document.createTextNode("当前浏览器版本很适合开发!!! 😃");
el.appendChild(success);
} else {
let warn = document.createTextNode(
"当前浏览器版本不适合开发,建议使用最新版本的谷歌或者火狐浏览器!!!😯"
);
el.appendChild(warn);
el.style.color = "red";
}
}
return Sys;
})();
};
</script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -5,28 +5,32 @@ import { MockMethod } from "vite-plugin-mock";
const systemRouter = {
path: "/system",
name: "system",
redirect: "/system/user",
redirect: "/system/user/index",
meta: {
icon: "el-icon-setting",
title: "message.hssysManagement",
icon: "setting",
title: "menus.hssysManagement",
i18n: true,
showLink: true,
rank: 6
},
children: [
{
path: "/system/user",
path: "/system/user/index",
name: "user",
meta: {
title: "message.hsBaseinfo",
title: "menus.hsBaseinfo",
i18n: true,
showLink: true
}
},
{
path: "/system/dict",
path: "/system/dict/index",
name: "dict",
meta: {
title: "message.hsDict",
showLink: true
title: "menus.hsDict",
i18n: true,
showLink: true,
keepAlive: true
}
}
]
@@ -35,27 +39,30 @@ const systemRouter = {
const permissionRouter = {
path: "/permission",
name: "permission",
redirect: "/permission/page",
redirect: "/permission/page/index",
meta: {
title: "message.permission",
icon: "el-icon-lollipop",
title: "menus.permission",
icon: "lollipop",
i18n: true,
showLink: true,
rank: 3
},
children: [
{
path: "/permission/page",
path: "/permission/page/index",
name: "permissionPage",
meta: {
title: "message.permissionPage",
title: "menus.permissionPage",
i18n: true,
showLink: true
}
},
{
path: "/permission/button",
path: "/permission/button/index",
name: "permissionButton",
meta: {
title: "message.permissionButton",
title: "menus.permissionButton",
i18n: true,
showLink: true,
authority: []
}
@@ -63,6 +70,41 @@ const permissionRouter = {
]
};
const tabsRouter = {
path: "/tabs",
name: "reTabs",
redirect: "/tabs/index",
meta: {
icon: "IF-team-icontabs",
title: "menus.hstabs",
i18n: true,
showLink: true,
rank: 8
},
children: [
{
path: "/tabs/index",
name: "reTabs",
meta: {
title: "menus.hstabs",
showLink: true,
i18n: true
}
},
{
path: "/tabs/detail",
name: "tabDetail",
meta: {
title: "",
showLink: false,
i18n: false,
dynamicLevel: 3,
refreshRedirect: "/tabs/index"
}
}
]
};
// 添加不同按钮权限到/permission/button页面中
function setDifAuthority(authority, routes) {
routes.children[1].meta.authority = [authority];
@@ -77,12 +119,16 @@ export default [
if (query.name === "admin") {
return {
code: 0,
info: [systemRouter, setDifAuthority("v-admin", permissionRouter)]
info: [
tabsRouter,
systemRouter,
setDifAuthority("v-admin", permissionRouter)
]
};
} else {
return {
code: 0,
info: [setDifAuthority("v-test", permissionRouter)]
info: [tabsRouter, setDifAuthority("v-test", permissionRouter)]
};
}
}

View File

@@ -1,8 +1,8 @@
import { MockMethod } from "vite-plugin-mock";
// http://mockjs.com/examples.html#Object
const echartsList = (): any => {
const result: any[] = [];
const echartsList = () => {
const result = [];
for (let index = 0; index < 200; index++) {
result.push(["@date", Math.floor(Math.random() * 300)]);
}

View File

@@ -1,8 +1,16 @@
import { MockMethod } from "vite-plugin-mock";
type mapType = {
plateNumber: string;
driver: string;
"orientation|1-360": number;
"lng|113-114.1-10": number;
"lat|34-35.1-10": number;
};
// http://mockjs.com/examples.html#Object
const mapList = (): any => {
const result: any[] = [];
const mapList = (): Array<mapType> => {
const result: Array<mapType> = [];
for (let index = 0; index < 200; index++) {
result.push({
plateNumber: "豫A@natural(11111, 99999)@character('upper')",

View File

@@ -1,102 +1,125 @@
{
"name": "vue-pure-admin",
"version": "2.1.0",
"version": "2.8.5",
"private": true,
"engines": {
"node": ">= 16",
"pnpm": ">= 6"
},
"scripts": {
"dev": "cross-env --max_old_space_size=4096 vite",
"serve": "yarn dev",
"serve": "pnpm dev",
"build": "rimraf dist && cross-env vite build",
"preview": "vite preview",
"preview:build": "yarn build && vite preview",
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && yarn cache clean && yarn",
"preview:build": "pnpm build && vite preview",
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged",
"lint": "yarn lint:eslint && yarn lint:prettier && yarn lint:stylelint && yarn lint:pretty",
"prepare": "husky install"
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
"prepare": "husky install",
"preinstall": "npx only-allow pnpm"
},
"browserslist": [
"> 1%",
"not ie 11",
"not op_mini all"
],
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@logicflow/core": "^0.4.6",
"@logicflow/extension": "^0.4.6",
"@vueuse/core": "^6.5.3",
"@ctrl/tinycolor": "^3.4.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/vue-fontawesome": "^3.0.0-5",
"@logicflow/core": "0.7.1",
"@logicflow/extension": "0.7.1",
"@vueuse/core": "^7.5.3",
"@vueuse/motion": "^2.0.0-beta.9",
"@vueuse/shared": "^7.5.3",
"animate.css": "^4.1.1",
"await-to-js": "^3.0.0",
"axios": "^0.21.1",
"axios": "^0.25.0",
"cropperjs": "^1.5.11",
"css-color-function": "^1.3.3",
"dayjs": "^1.10.7",
"driver.js": "^0.9.8",
"echarts": "^5.2.1",
"element-plus": "1.1.0-beta.20",
"element-plus": "1.3.0-beta.1",
"element-resize-detector": "^1.2.3",
"font-awesome": "^4.7.0",
"js-cookie": "^3.0.1",
"lodash-es": "^4.17.21",
"lowdb": "^3.0.0",
"mitt": "^3.0.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"path-to-regexp": "^6.2.0",
"pinia": "2.0.0-rc.10",
"pinia": "^2.0.9",
"qs": "^6.10.1",
"remixicon": "^2.5.0",
"resize-observer-polyfill": "^1.5.1",
"responsive-storage": "^1.0.11",
"sortablejs": "1.13.0",
"typescript-cookie": "^1.0.0",
"v-contextmenu": "^3.0.0",
"vue": "^3.2.20",
"vue-i18n": "^9.2.0-beta.3",
"rgb-hex": "^4.0.0",
"v-contextmenu": "3.0.0",
"vue": "^3.2.27",
"vue-i18n": "^9.2.0-beta.26",
"vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.11",
"vue-types": "^4.1.0",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.0.27",
"wangeditor": "^4.7.7",
"xe-ajax": "^4.0.5",
"xe-utils": "^3.3.1",
"xgplayer": "^2.28.0"
"vue-router": "^4.0.12",
"vue-types": "^4.1.1",
"vuedraggable": "4.1.0",
"vxe-table": "^4.1.18",
"wangeditor": "^4.7.9",
"xe-utils": "^3.5.2",
"xgplayer": "2.28.0"
},
"devDependencies": {
"@commitlint/cli": "^13.1.0",
"@commitlint/config-conventional": "^13.1.0",
"@types/element-resize-detector": "^1.1.3",
"@types/mockjs": "^1.0.3",
"@types/node": "^14.14.14",
"@types/nprogress": "^0.2.0",
"@typescript-eslint/eslint-plugin": "^4.31.0",
"@typescript-eslint/parser": "^4.31.0",
"@vitejs/plugin-vue": "^1.6.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "^3.2.20",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.4",
"babel-plugin-transform-remove-console": "^6.9.4",
"chalk": "^2.4.2",
"cross-env": "^7.0.3",
"eslint": "^7.30.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.17.0",
"husky": "^7.0.2",
"lint-staged": "^11.1.2",
"postcss": "^8.2.6",
"postcss-import": "^14.0.0",
"prettier": "^2.3.2",
"pretty-quick": "^3.1.1",
"rimraf": "^3.0.2",
"sass": "^1.38.0",
"sass-loader": "^12.1.0",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^22.0.0",
"stylelint-order": "^4.1.0",
"typescript": "^4.4.2",
"unplugin-element-plus": "^0.1.0",
"vite": "^2.6.7",
"@commitlint/cli": "13.1.0",
"@commitlint/config-conventional": "13.1.0",
"@iconify-icons/ep": "^1.1.3",
"@iconify/vue": "^3.1.2",
"@types/element-resize-detector": "1.1.3",
"@types/js-cookie": "^3.0.1",
"@types/mockjs": "1.0.3",
"@types/node": "14.14.14",
"@types/nprogress": "0.2.0",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "4.31.0",
"@typescript-eslint/parser": "4.31.0",
"@vitejs/plugin-legacy": "^1.6.4",
"@vitejs/plugin-vue": "^2.0.1",
"@vitejs/plugin-vue-jsx": "^1.3.3",
"@vue/eslint-config-prettier": "6.0.0",
"@vue/eslint-config-typescript": "7.0.0",
"@zougt/vite-plugin-theme-preprocessor": "^1.4.4",
"autoprefixer": "10.2.4",
"cross-env": "7.0.3",
"eslint": "7.30.0",
"eslint-plugin-prettier": "3.4.0",
"eslint-plugin-vue": "7.17.0",
"husky": "7.0.2",
"lint-staged": "11.1.2",
"postcss": "8.2.6",
"postcss-import": "14.0.0",
"prettier": "2.3.2",
"pretty-quick": "3.1.1",
"rimraf": "3.0.2",
"sass": "^1.45.0",
"sass-loader": "^12.3.0",
"stylelint": "13.13.1",
"stylelint-config-prettier": "8.0.2",
"stylelint-config-standard": "22.0.0",
"stylelint-order": "4.1.0",
"typescript": "^4.5.5",
"unplugin-element-plus": "^0.2.0",
"vite": "^2.7.13",
"vite-plugin-live-reload": "^2.1.0",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.2.1",
"vite-svg-loader": "^2.2.0",
"vue-eslint-parser": "^7.10.0"
"vite-plugin-remove-console": "^0.0.6",
"vite-plugin-style-import": "^1.4.1",
"vite-plugin-windicss": "^1.6.1",
"vite-svg-loader": "2.2.0",
"vue-eslint-parser": "7.10.0",
"windicss": "^3.4.3"
},
"repository": "git@github.com:xiaoxian521/vue-pure-admin.git",
"author": "xiaoxian521",

7968
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,11 +1,23 @@
{
"Version": "2.0.0",
"Version": "2.8.5",
"Title": "PureAdmin",
"FixedHeader": true,
"HiddenSideBar": false,
"MultiTagsCache": false,
"KeepAlive": true,
"Locale": "zh",
"Layout": "vertical-dark",
"Layout": "vertical",
"Theme": "default",
"DarkMode": false,
"Grey": false,
"Weak": false,
"HideTabs": false,
"SidebarStatus": true,
"EpThemeColor": "#409EFF",
"ShowLogo": true,
"ShowModel": "smart",
"MapConfigure": {
"amapKey": "97b3248d1553172e81f168cf94ea667e",
"baiduKey": "wTHbkkEweiFqZLKunMIjcrb2RcqNXkhc",
"options": {
"resizeEnable": true,
"center": [113.6401, 34.72468],

View File

@@ -5,24 +5,19 @@
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
export default {
export default defineComponent({
name: "app",
components: {
[ElConfigProvider.name]: ElConfigProvider
},
computed: {
// eslint-disable-next-line vue/return-in-computed-property
currentLocale() {
switch (this.$storage.locale?.locale) {
case "zh":
return zhCn;
case "en":
return en;
return this.$storage.locale?.locale === "zh" ? zhCn : en;
}
}
}
};
});
</script>

View File

@@ -1,11 +1,11 @@
import { http } from "../utils/http";
// 地图数据
export const mapJson = (data?: object) => {
return http.request("get", "/getMapInfo", data);
export const mapJson = (params?: object) => {
return http.request("get", "/getMapInfo", { params });
};
// echarts数据
export const echartsJson = (data?: object) => {
return http.request("get", "/getEchartsInfo", data);
export const echartsJson = (params?: object) => {
return http.request("get", "/getEchartsInfo", { params });
};

View File

@@ -1,5 +1,5 @@
import { http } from "../utils/http";
export const getAsyncRoutes = (data?: object) => {
return http.request("get", "/getAsyncRoutes", data);
export const getAsyncRoutes = (params?: object) => {
return http.request("get", "/getAsyncRoutes", { params });
};

View File

@@ -1,16 +1,26 @@
import { http } from "../utils/http";
interface userType extends Promise<any> {
svg?: string;
code?: number;
info?: object;
}
// 获取验证码
export const getVerify = () => {
export const getVerify = (): userType => {
return http.request("get", "/captcha");
};
// 登录
export const getLogin = (data: object) => {
return http.request("post", "/login", data);
return http.request("post", "/login", { data });
};
// 注册
export const getRegist = (data: object) => {
return http.request("post", "/register", data);
// 刷新token
export const refreshToken = (data: object) => {
return http.request("post", "/refreshToken", { data });
};
// export const searchVague = (data: object) => {
// return http.request("post", "/searchVague", { data });
// };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 680 KiB

BIN
src/assets/avatars.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2208059 */
src: url("iconfont.woff2?t=1634092870259") format("woff2"),
url("iconfont.woff?t=1634092870259") format("woff"),
url("iconfont.ttf?t=1634092870259") format("truetype");
src: url("iconfont.woff2?t=1638023560828") format("woff2"),
url("iconfont.woff?t=1638023560828") format("woff"),
url("iconfont.ttf?t=1638023560828") format("truetype");
}
.iconfont {
@@ -13,8 +13,12 @@
-moz-osx-font-smoothing: grayscale;
}
.team-iconzuixinlianzai::before {
content: "\e6da";
.team-icontabs::before {
content: "\e63e";
}
.team-iconlogo::before {
content: "\e620";
}
.team-iconxinpin::before {
@@ -25,22 +29,6 @@
content: "\e615";
}
.team-iconinternationality::before {
content: "\e67a";
}
.team-iconshanchu::before {
content: "\e617";
}
.team-iconshow-main-container::before {
content: "\e878";
}
.team-iconhidden-main-container::before {
content: "\e881";
}
.team-iconexit-fullscreen::before {
content: "\e62a";
}

File diff suppressed because one or more lines are too long

View File

@@ -6,11 +6,18 @@
"description": "pure-admin",
"glyphs": [
{
"icon_id": "2508809",
"name": "最新连载",
"font_class": "zuixinlianzai",
"unicode": "e6da",
"unicode_decimal": 59098
"icon_id": "20594647",
"name": "标签页",
"font_class": "tabs",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "22129506",
"name": "水能",
"font_class": "logo",
"unicode": "e620",
"unicode_decimal": 58912
},
{
"icon_id": "7795613",
@@ -26,34 +33,6 @@
"unicode": "e615",
"unicode_decimal": 58901
},
{
"icon_id": "18367956",
"name": "中英文2 中文",
"font_class": "internationality",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "6184565",
"name": "删除",
"font_class": "shanchu",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "9626913",
"name": "全屏",
"font_class": "show-main-container",
"unicode": "e878",
"unicode_decimal": 59512
},
{
"icon_id": "9626952",
"name": "退出全屏",
"font_class": "hidden-main-container",
"unicode": "e881",
"unicode_decimal": 59521
},
{
"icon_id": "5698509",
"name": "全屏缩小",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -0,0 +1 @@
<svg t="1636193306629" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1847" width="32" height="32"><path d="M410.558481 0.10861C410.558481 211.083075 109.682285 361.860579 109.682285 633.656511c0 174.943176 134.703259 316.787527 300.876196 316.787527s300.876197-141.817198 300.876197-316.787527C711.407525 361.751969 410.558481 210.974465 410.558481 0.10861z" fill="#386BF3" p-id="1848"></path><path d="M613.468671 73.664572c0 211.055922-300.876197 361.914883-300.876196 633.547901 0 174.943176 134.703259 316.787527 300.876196 316.787527s300.876197-141.817198 300.876197-316.787527c-0.054305-271.633018-300.876197-422.491979-300.876197-633.547901z" fill="#C3D2FB" p-id="1849"></path><path d="M312.592475 707.212473c0-183.713414 137.635722-312.171612 226.72288-441.390078 81.701694 106.111739 172.119322 218.740063 172.119323 367.725506a309.755045 309.755045 0 0 1-291.074166 316.516003 323.114046 323.114046 0 0 1-107.768037-242.851431z" fill="#303F5B" p-id="1850"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
src/assets/login/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" width="500" height="380" viewBox="0 0 896 529.1129" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M832.06729,623.22778s-26.37759,9.89441-38.806,32.94348S787.06,706.69574,787.06,706.69574s26.37759-9.89447,38.806-32.94348S832.06729,623.22778,832.06729,623.22778Z" transform="translate(-158 -185.8871)" fill="#3f3d56"/><path d="M867.5,657.59637s-8.64182,26.814-31.0802,40.31373-50.17651,8.57293-50.17651,8.57293,8.64175-26.81408,31.08017-40.31378S867.5,657.59637,867.5,657.59637Z" transform="translate(-158 -185.8871)" fill="#5392f0"/><rect y="527.1129" width="896" height="2" fill="#2f2e41"/><path d="M519.87238,620.97461a95.44448,95.44448,0,0,1-35.748-14.44629L485.306,604.915a93.36283,93.36283,0,0,0,34.999,14.10547c18.93164,3.40137,47.26075,1.73144,74.707-25.52735,53.41358-53.04785,104.39307-58.39062,104.90186-58.43847l.18652,1.99219c-.50146.04687-50.76806,5.31738-103.67822,57.86621-21.61328,21.46386-43.792,27.40234-61.71777,27.40234A83.49962,83.49962,0,0,1,519.87238,620.97461Z" transform="translate(-158 -185.8871)" fill="#2f2e41"/><circle cx="515.15271" cy="381.1129" r="12" fill="#2f2e41"/><circle cx="430.15271" cy="437.1129" r="12" fill="#2f2e41"/><path d="M841.5,714s-17.46191-5.41315-52.26129-10.84192L790,692.5c6-60-34-150-34-150a401.561,401.561,0,0,1,21.4693,139.0246C772.13214,672.2124,761.82056,662.16638,742,656c0,0,25.77765,22.106,33.15918,45.10175a997.84042,997.84042,0,0,0-102.02258-8.21589L682,672.5l-17,17s-7-51-22-53l11,50s-13-10-16-9l7.39746,14.79486c-49.819-.51654-109.08453,1.7356-177.76581,8.95227L476,682l-17,17s-7-51-22-53l11,50s-13-10-16-9l8.64288,17.28583Q406.9763,708.2897,370.5,714Z" transform="translate(-158 -185.8871)" fill="#3f3d56"/><path d="M565.64813,230.37817c-10.89964,11.74783,17.59745,40.25959,17.59745,40.25959s-57.70662,9.73051-53.12783,9.14083,2.20622-49.13151,2.20622-49.13151S576.54777,218.63035,565.64813,230.37817Z" transform="translate(-158 -185.8871)" fill="#a0616a"/><path d="M605.81236,356.10945l-50.139,25.6141-27.22969,15.6059s-32.09862,40.43116-38.08709,64.39234,25.92963,68.247,29.54371,72.82286a54.36088,54.36088,0,0,1,4.98908,7.42355c1.24727,1.85589,12.02944-.541,23.80342-3.06554S547.13,518.93875,547.13,518.93875s-15.02732-38.39505-16.14686-39.25912c-1.04554-.807-4.60093-7.44631-2.04309-10.35234a25.94993,25.94993,0,0,0,5.44489-8.89825,30.09064,30.09064,0,0,1,4.18709-7.94151s45.361-36.83645,59.52776-49.37835,51.82952-4.65839,51.82952-4.65839-17.78167,68.20027-22.22979,72.80616-4.929,8.70085-2.91535,16.50759,28.28157.39078,28.28157.39078L662.766,461.6996s15.74879-34.2925,24.29946-69.67451c4.27533-17.691-3.88828-28.23462-13.12073-34.35549a41.39094,41.39094,0,0,0-30.02983-5.97766l-46.34848,8.1308,32.14706-13.84923Z" transform="translate(-158 -185.8871)" fill="#2f2e41"/><path d="M420.87777,290.19133,361.02366,271.685s-24.179-31.16689-12.78824-36.6669,25.65172,26.94419,25.65172,26.94419l41.686,2.69751Z" transform="translate(-158 -185.8871)" fill="#a0616a"/><path d="M672.49431,257.78673l53.2121-33.06768s15.49333-36.27612,3.0807-38.71059-17.98787,32.56435-17.98787,32.56435l-39.64232,13.17143Z" transform="translate(-158 -185.8871)" fill="#a0616a"/><path d="M682.45318,220.40023l1.01427,39.19147-89.68779,16.025c13.19231,28.22441,9.84118,60.34675,43.04725,74.4259L524.9027,404.78717c4.9871-43.03806-15.81748-75.456-35.263-115.75876-23.68547-8.58589-51.19594-2.29078-80.33649,10.34619l-5.237-40.66416,123.87841-8.896,20.34848,7.77932,21.81842-9.17677C602.17891,238.88953,648.22076,220.77584,682.45318,220.40023Z" transform="translate(-158 -185.8871)" fill="#5392f0"/><path d="M626.64006,486.51727c-2.72,2.36681-5.25213,21.84984-5.34982,28.92023s9.21178,8.89624,14.29855,9.2494,4.47816,3.45631,7.83678,6.04854,14.39625,2.179,28.89019-2.71238-9.75274-20.92568-11.86409-21.662-11-22.78156-11-22.78156S629.36,484.15046,626.64006,486.51727Z" transform="translate(-158 -185.8871)" fill="#2f2e41"/><path d="M547.368,531.00717c3.23089,1.60043,10.61681,19.80614,12.50274,26.62107s-6.65716,10.93994-11.48848,12.5704-3.45631,4.47816-6.04855,7.83678-13.3744,5.75546-28.63472,4.696,4.13258-22.71391,5.98847-23.96118,4.86893-24.82526,4.86893-24.82526S544.13715,529.40674,547.368,531.00717Z" transform="translate(-158 -185.8871)" fill="#2f2e41"/><circle cx="389.47074" cy="35.42904" r="23.99585" fill="#a0616a"/><path d="M519.73448,218.90923a22.82668,22.82668,0,0,1-.83378-18.59281c2.35891-5.8153,7.59174-11.65569,18.87309-13.4,24.61387-3.80572,37.71267,13.43543,37.02452,19.07449s-3.99294,19.27051-3.99294,19.27051,1.47587-12.90619-4.85883-13.362-30.90178-2.37835-37.12217,4.145a14.23268,14.23268,0,0,0-3.71042,13.82977Z" transform="translate(-158 -185.8871)" fill="#2f2e41"/></svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2.88 18.054a35.897 35.897 0 0 1 8.531-16.32.8.8 0 0 1 1.178 0c.166.18.304.332.413.455a35.897 35.897 0 0 1 8.118 15.865c-2.141.451-4.34.747-6.584.874l-2.089 4.178a.5.5 0 0 1-.894 0l-2.089-4.178a44.019 44.019 0 0 1-6.584-.874zm6.698-1.123l1.157.066L12 19.527l1.265-2.53 1.157-.066a42.137 42.137 0 0 0 4.227-.454A33.913 33.913 0 0 0 12 4.09a33.913 33.913 0 0 0-6.649 12.387c1.395.222 2.805.374 4.227.454zM12 15a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg>

After

Width:  |  Height:  |  Size: 608 B

1
src/assets/svg/dark.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.38 2.019a7.5 7.5 0 1 0 10.6 10.6C21.662 17.854 17.316 22 12.001 22 6.477 22 2 17.523 2 12c0-5.315 4.146-9.661 9.38-9.981z"/></svg>

After

Width:  |  Height:  |  Size: 263 B

1
src/assets/svg/day.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" class="re-screen" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="currentColor"><path d="M3.5 4H1V3h2V1h1v2.5l-.5.5zM13 3V1h-1v2.5l.5.5H15V3h-2zm-1 9.5V15h1v-2h2v-1h-2.5l-.5.5zM1 12v1h2v2h1v-2.5l-.5-.5H1zm11-1.5l-.5.5h-7l-.5-.5v-5l.5-.5h7l.5.5v5zM10 7H6v2h4V7z"></path></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" class="re-screen" color="#00000073" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="currentColor"><path d="M3.5 4H1V3h2V1h1v2.5l-.5.5zM13 3V1h-1v2.5l.5.5H15V3h-2zm-1 9.5V15h1v-2h2v-1h-2.5l-.5.5zM1 12v1h2v2h1v-2.5l-.5-.5H1zm11-1.5l-.5.5h-7l-.5-.5v-5l.5-.5h7l.5.5v5zM10 7H6v2h4V7z"></path></g></svg>

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 452 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" class="re-screen" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="currentColor"><path d="M3 12h10V4H3v8zm2-6h6v4H5V6zM2 6H1V2.5l.5-.5H5v1H2v3zm13-3.5V6h-1V3h-3V2h3.5l.5.5zM14 10h1v3.5l-.5.5H11v-1h3v-3zM2 13h3v1H1.5l-.5-.5V10h1v3z"></path></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" class="re-screen" color="#00000073" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="currentColor"><path d="M3 12h10V4H3v8zm2-6h6v4H5V6zM2 6H1V2.5l.5-.5H5v1H2v3zm13-3.5V6h-1V3h-3V2h3.5l.5.5zM14 10h1v3.5l-.5.5H11v-1h3v-3zM2 13h3v1H1.5l-.5-.5V10h1v3z"></path></g></svg>

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 421 B

View File

@@ -12,8 +12,15 @@ import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
let echartInstance: ECharts;
const props = defineProps({
index: {
type: Number,
default: 0
}
});
function initechartInstance() {
const echartDom = document.querySelector(".bar");
const echartDom = document.querySelector(".bar" + props.index);
if (!echartDom) return;
// @ts-ignore
echartInstance = echarts.init(echartDom);
@@ -85,12 +92,5 @@ tryOnUnmounted(() => {
</script>
<template>
<div class="bar"></div>
<div :class="'bar' + props.index" style="width: 100%; height: 35vh"></div>
</template>
<style scoped>
.bar {
width: 100%;
height: 35vh;
}
</style>

View File

@@ -10,52 +10,48 @@ const lists = ref([
</script>
<template>
<el-descriptions
class="margin-top"
direction="vertical"
:column="3"
size="medium"
border
>
<el-descriptions class="margin-top" direction="vertical" :column="3" border>
<el-descriptions-item>
<template #label>
<i class="el-icon-user"></i>
<el-icon>
<IconifyIconOffline icon="user" />
</el-icon>
用户名
</template>
xiaoxian
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<i class="el-icon-mobile-phone"></i>
<el-icon>
<IconifyIconOffline icon="iphone" />
</el-icon>
手机号
</template>
123456789
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<i class="el-icon-location-outline"></i>
<el-icon>
<IconifyIconOffline icon="location" />
</el-icon>
居住地
</template>
上海
</el-descriptions-item>
</el-descriptions>
<el-descriptions
class="margin-top"
direction="vertical"
:column="2"
size="medium"
border
>
<el-descriptions class="margin-top" direction="vertical" :column="2" border>
<el-descriptions-item>
<template #label>
<i class="el-icon-tickets"></i>
<el-icon>
<IconifyIconOffline icon="tickets" />
</el-icon>
标签
</template>
<el-tag
v-for="item in lists"
:key="item.label"
:type="item.type"
size="mini"
size="small"
effect="dark"
>
{{ item.label }}
@@ -63,22 +59,20 @@ const lists = ref([
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<i class="el-icon-office-building"></i>
<el-icon>
<IconifyIconOffline icon="office-building" />
</el-icon>
联系地址
</template>
上海市徐汇区
</el-descriptions-item>
</el-descriptions>
<el-descriptions
class="margin-top"
direction="vertical"
:column="1"
size="medium"
border
>
<el-descriptions class="margin-top" direction="vertical" :column="1" border>
<el-descriptions-item>
<template #label>
<i class="el-icon-notebook-1"></i>
<el-icon>
<IconifyIconOffline icon="notebook" />
</el-icon>
留言
</template>
好好学习天天向上
@@ -87,7 +81,7 @@ const lists = ref([
</template>
<style scoped>
.el-tag--mini {
.el-tag {
margin-right: 10px !important;
}
</style>

View File

@@ -111,7 +111,7 @@ let classOption = reactive({
.warp {
width: 95%;
height: 230px;
height: 215px;
margin: 0 auto;
overflow: hidden;

View File

@@ -12,8 +12,15 @@ import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
let echartInstance: ECharts;
const props = defineProps({
index: {
type: Number,
default: 0
}
});
function initechartInstance() {
const echartDom = document.querySelector(".line");
const echartDom = document.querySelector(".line" + props.index);
if (!echartDom) return;
// @ts-ignore
echartInstance = echarts.init(echartDom);
@@ -73,12 +80,5 @@ tryOnUnmounted(() => {
</script>
<template>
<div class="line"></div>
<div :class="'line' + props.index" style="width: 100%; height: 35vh"></div>
</template>
<style scoped>
.line {
width: 100%;
height: 35vh;
}
</style>

View File

@@ -12,8 +12,15 @@ import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
let echartInstance: ECharts;
const props = defineProps({
index: {
type: Number,
default: 0
}
});
function initechartInstance() {
const echartDom = document.querySelector(".pie");
const echartDom = document.querySelector(".pie" + props.index);
if (!echartDom) return;
// @ts-ignore
echartInstance = echarts.init(echartDom);
@@ -76,12 +83,5 @@ tryOnUnmounted(() => {
</script>
<template>
<div class="pie"></div>
<div :class="'pie' + props.index" style="width: 100%; height: 35vh"></div>
</template>
<style scoped>
.pie {
width: 100%;
height: 35vh;
}
</style>

View File

@@ -2,9 +2,15 @@
import { ref, unref } from "vue";
import { LogicFlow } from "@logicflow/core";
type nodeListType = {
text: string;
class: string;
type: string;
};
interface Props {
lf: LogicFlow;
nodeList: ForDataType<undefined>;
nodeList: Array<nodeListType>;
}
const props = withDefaults(defineProps<Props>(), {

View File

@@ -1,5 +1,91 @@
import { App } from "vue";
import { App, defineComponent } from "vue";
import icon from "./src/Icon.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import iconifyIconOffline from "./src/iconifyIconOffline";
import iconifyIconOnline from "./src/iconifyIconOnline";
/**
* find icon component
* @param icon icon图标
* @returns component
*/
export function findIconReg(icon: string) {
// fontawesome4
const fa4Reg = /^fa-/;
// fontawesome5+
const fa5Reg = /^FA-/;
// iconfont
const iFReg = /^IF-/;
// remixicon
const riReg = /^RI-/;
// typeof icon === "function" 属于SVG
if (fa5Reg.test(icon)) {
const text = icon.split(fa5Reg)[1];
return findIcon(
text.slice(0, text.indexOf(" ") == -1 ? text.length : text.indexOf(" ")),
"FA",
text.slice(text.indexOf(" ") + 1, text.length)
);
} else if (fa4Reg.test(icon)) {
return findIcon(icon.split(fa4Reg)[1], "fa");
} else if (iFReg.test(icon)) {
return findIcon(icon.split(iFReg)[1], "IF");
} else if (typeof icon === "function") {
return findIcon(icon, "SVG");
} else if (riReg.test(icon)) {
return findIcon(icon.split(riReg)[1], "RI");
} else {
return findIcon(icon, "EL");
}
}
// 支持fontawesome、iconfont、remixicon、element-plus/icons、自定义svg
export function findIcon(icon: String, type = "EL", property?: string) {
if (type === "FA") {
return defineComponent({
name: "FaIcon",
setup() {
return { icon, property };
},
components: { FontAwesomeIcon },
template: `<font-awesome-icon :icon="icon" v-bind:[property]="true" />`
});
} else if (type === "fa") {
return defineComponent({
name: "faIcon",
data() {
return { icon: `fa ${icon}` };
},
template: `<i :class="icon" />`
});
} else if (type === "IF") {
return defineComponent({
name: "IfIcon",
data() {
return { icon: `iconfont ${icon}` };
},
template: `<i :class="icon" />`
});
} else if (type === "RI") {
return defineComponent({
name: "RiIcon",
data() {
return { icon: `ri-${icon}` };
},
template: `<i :class="icon" />`
});
} else if (type === "EL") {
return defineComponent({
name: "ElIcon",
data() {
return { icon };
},
template: `<IconifyIconOffline :icon="icon" />`
});
} else if (type === "SVG") {
return icon;
}
}
export const Icon = Object.assign(icon, {
install(app: App) {
@@ -7,6 +93,11 @@ export const Icon = Object.assign(icon, {
}
});
export const IconifyIconOffline = iconifyIconOffline;
export const IconifyIconOnline = iconifyIconOnline;
export default {
Icon
Icon,
IconifyIconOffline,
IconifyIconOnline
};

View File

@@ -0,0 +1,70 @@
import { h, defineComponent } from "vue";
import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline";
import Check from "@iconify-icons/ep/check";
import Menu from "@iconify-icons/ep/menu";
import HomeFilled from "@iconify-icons/ep/home-filled";
import SetUp from "@iconify-icons/ep/set-up";
import Edit from "@iconify-icons/ep/edit";
import Setting from "@iconify-icons/ep/setting";
import Lollipop from "@iconify-icons/ep/lollipop";
import Link from "@iconify-icons/ep/link";
import Position from "@iconify-icons/ep/position";
import Histogram from "@iconify-icons/ep/histogram";
import RefreshRight from "@iconify-icons/ep/refresh-right";
import ArrowDown from "@iconify-icons/ep/arrow-down";
import Close from "@iconify-icons/ep/close";
import CloseBold from "@iconify-icons/ep/close-bold";
import Bell from "@iconify-icons/ep/bell";
import Guide from "@iconify-icons/ep/guide";
import User from "@iconify-icons/ep/user";
import Iphone from "@iconify-icons/ep/iphone";
import Location from "@iconify-icons/ep/location";
import Tickets from "@iconify-icons/ep/tickets";
import OfficeBuilding from "@iconify-icons/ep/office-building";
import Notebook from "@iconify-icons/ep/notebook";
addIcon("check", Check);
addIcon("menu", Menu);
addIcon("home-filled", HomeFilled);
addIcon("set-up", SetUp);
addIcon("edit", Edit);
addIcon("setting", Setting);
addIcon("lollipop", Lollipop);
addIcon("link", Link);
addIcon("position", Position);
addIcon("histogram", Histogram);
addIcon("refresh-right", RefreshRight);
addIcon("arrow-down", ArrowDown);
addIcon("close", Close);
addIcon("close-bold", CloseBold);
addIcon("bell", Bell);
addIcon("guide", Guide);
addIcon("user", User);
addIcon("iphone", Iphone);
addIcon("location", Location);
addIcon("tickets", Tickets);
addIcon("office-building", OfficeBuilding);
addIcon("notebook", Notebook);
// Iconify Icon在Vue里离线使用用于内网环境
// https://docs.iconify.design/icon-components/vue/offline.html
export default defineComponent({
name: "IconifyIcon",
components: { IconifyIcon },
props: {
icon: {
type: String,
default: ""
}
},
render() {
return h(
IconifyIcon,
{
icon: `${this.icon}`
},
{
default: () => []
}
);
}
});

View File

@@ -0,0 +1,30 @@
import { h, defineComponent } from "vue";
import { Icon as IconifyIcon } from "@iconify/vue";
// Iconify Icon在Vue里在线使用用于外网环境
// https://docs.iconify.design/icon-components/vue/offline.html
export default defineComponent({
name: "IconifyIcon",
components: { IconifyIcon },
props: {
icon: {
type: String,
default: ""
},
type: {
type: String,
default: "ep:"
}
},
render() {
return h(
IconifyIcon,
{
icon: `${this.type}${this.icon}`
},
{
default: () => []
}
);
}
});

View File

@@ -1,195 +0,0 @@
<script setup lang="ts">
import { ref, PropType, getCurrentInstance, watch, nextTick, toRef } from "vue";
import { useRouter, useRoute } from "vue-router";
import { initRouter } from "/@/router";
import { storageSession } from "/@/utils/storage";
export interface ContextProps {
userName: string;
passWord: string;
verify: number | null;
svg: any;
telephone?: number;
dynamicText?: string;
}
const props = defineProps({
ruleForm: {
type: Object as PropType<ContextProps>
}
});
const emit = defineEmits<{
(e: "onBehavior", evt: Object): void;
(e: "refreshVerify"): void;
}>();
const instance = getCurrentInstance();
const model = toRef(props, "ruleForm");
let tips = ref<string>("注册");
let tipsFalse = ref<string>("登录");
const route = useRoute();
const router = useRouter();
watch(
route,
async ({ path }): Promise<void> => {
await nextTick();
path.includes("register")
? (tips.value = "登录") && (tipsFalse.value = "注册")
: (tips.value = "注册") && (tipsFalse.value = "登录");
},
{ immediate: true }
);
const rules: Object = ref({
userName: [{ required: true, message: "请输入用户名", trigger: "blur" }],
passWord: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, message: "密码长度必须不小于6位", trigger: "blur" }
],
verify: [
{ required: true, message: "请输入验证码", trigger: "blur" },
{ type: "number", message: "验证码必须是数字类型", trigger: "blur" }
]
});
// 点击登录或注册
const onBehavior = (evt: Object): void => {
// @ts-expect-error
instance.refs.ruleForm.validate((valid: boolean) => {
if (valid) {
emit("onBehavior", evt);
} else {
return false;
}
});
};
// 刷新验证码
const refreshVerify = (): void => {
emit("refreshVerify");
};
// 表单重置
const resetForm = (): void => {
// @ts-expect-error
instance.refs.ruleForm.resetFields();
};
// 登录、注册页面切换
const changPage = (): void => {
tips.value === "注册" ? router.push("/register") : router.push("/login");
};
const noSecret = (): void => {
storageSession.setItem("info", {
username: "admin",
accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
});
initRouter("admin").then(() => {});
router.push("/");
};
</script>
<template>
<div class="info">
<el-form :model="model" :rules="rules" ref="ruleForm" class="rule-form">
<el-form-item prop="userName">
<el-input
clearable
v-model="model.userName"
placeholder="请输入用户名"
prefix-icon="el-icon-user"
></el-input>
</el-form-item>
<el-form-item prop="passWord">
<el-input
clearable
type="password"
show-password
v-model="model.passWord"
placeholder="请输入密码"
prefix-icon="el-icon-lock"
></el-input>
</el-form-item>
<el-form-item prop="verify">
<el-input
maxlength="2"
onkeyup="this.value=this.value.replace(/[^\d.]/g,'');"
v-model.number="model.verify"
placeholder="请输入验证码"
></el-input>
<span
class="verify"
title="刷新"
v-html="model.svg"
@click.prevent="refreshVerify"
></span>
</el-form-item>
<el-form-item>
<el-button type="primary" @click.prevent="onBehavior">{{
tipsFalse
}}</el-button>
<el-button @click="resetForm">重置</el-button>
<span class="tips" @click="changPage">{{ tips }}</span>
</el-form-item>
<span title="测试用户 直接登录" class="secret" @click="noSecret"
>免密登录</span
>
</el-form>
</div>
</template>
<style lang="scss" scoped>
.info {
width: 30vw;
height: 48vh;
background: url("../../assets/login.png") no-repeat center;
background-size: cover;
position: absolute;
border-radius: 20px;
right: 100px;
top: 30vh;
display: flex;
justify-content: center;
align-items: center;
@media screen and (max-width: 750px) {
width: 88vw;
right: 25px;
top: 22vh;
}
.rule-form {
width: 80%;
.verify {
position: absolute;
margin: -10px 0 0 -120px;
&:hover {
cursor: pointer;
}
}
.tips {
color: #409eff;
float: right;
&:hover {
cursor: pointer;
}
}
}
.secret {
color: #409eff;
&:hover {
cursor: pointer;
}
}
}
</style>

View File

@@ -3,7 +3,7 @@ import AMapLoader from "@amap/amap-jsapi-loader";
import { reactive, getCurrentInstance, onBeforeMount, onUnmounted } from "vue";
import { mapJson } from "/@/api/mock";
import { deviceDetection } from "/@/utils/deviceDetection";
import greenCar from "/@/assets/green.png";
import car from "/@/assets/car.png";
export interface MapConfigureInter {
on: Fn;
@@ -15,6 +15,10 @@ export interface MapConfigureInter {
plugin?: Fn;
}
type resultType = {
info: Array<undefined>;
};
export interface mapInter {
loading: boolean;
}
@@ -24,7 +28,7 @@ let map: MapConfigureInter;
const instance = getCurrentInstance();
const mapSet: mapInter = reactive({
const mapSet = reactive({
loading: deviceDetection() ? false : true
});
@@ -72,7 +76,7 @@ onBeforeMount(() => {
var { driver, plateNumber, orientation } = data[0];
var content = `<img style="transform: scale(1) rotate(${
360 - Number(orientation)
}deg);" src='${greenCar}' />`;
}deg);" src='${car}' />`;
marker.setContent(content);
marker.setLabel({
direction: "bottom",
@@ -92,7 +96,7 @@ onBeforeMount(() => {
// 获取模拟车辆信息
mapJson()
.then(res => {
.then((res: resultType) => {
let points: object = res.info.map((v: any) => {
return {
lnglat: [v.lng, v.lat],
@@ -122,19 +126,12 @@ onUnmounted(() => {
</script>
<template>
<div
id="mapview"
ref="mapview"
v-loading="mapSet.loading"
element-loading-text="地图加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
></div>
<div id="mapview" ref="mapview" v-loading="mapSet.loading"></div>
</template>
<style lang="scss" scoped>
#mapview {
height: 100%;
height: calc(100vh - 86px);
}
:deep(.amap-marker-label) {

View File

@@ -1,12 +1,15 @@
import { App } from "vue";
import axios from "axios";
import { loadEnv } from "@build/index";
let config: object = {};
const { VITE_PUBLIC_PATH } = loadEnv();
const setConfig = (cfg?: unknown) => {
config = Object.assign(config, cfg);
};
const getConfig = (key?: string) => {
const getConfig = (key?: string): ServerConfigs => {
if (typeof key === "string") {
const arr = key.split(".");
if (arr && arr.length) {
@@ -30,10 +33,7 @@ export const getServerConfig = async (app: App): Promise<undefined> => {
return axios({
baseURL: "",
method: "get",
url:
process.env.NODE_ENV === "production"
? "/manages/serverConfig.json"
: "/serverConfig.json"
url: `${VITE_PUBLIC_PATH}serverConfig.json`
})
.then(({ data: config }) => {
let $config = app.config.globalProperties.$config;

View File

@@ -9,7 +9,7 @@ export const auth: Directive = {
const authRoles = value;
const hasAuth = usePermissionStoreHook().buttonAuth.includes(authRoles);
if (!hasAuth) {
el.style.display = "none";
el.parentNode.removeChild(el);
}
} else {
throw new Error("need roles! Like v-auth=\"['admin','test']\"");

View File

@@ -1,48 +1,134 @@
<script setup lang="ts">
import { ref, computed, getCurrentInstance } from "vue";
import {
h,
ref,
computed,
Transition,
defineComponent,
getCurrentInstance
} from "vue";
import { RouterView } from "vue-router";
import backTop from "/@/assets/svg/back_top.svg?component";
import { usePermissionStoreHook } from "/@/store/modules/permission";
const props = defineProps({
fixedHeader: Boolean
});
const keepAlive: Boolean = ref(
getCurrentInstance().appContext.config.globalProperties.$config?.KeepAlive
);
const instance =
getCurrentInstance().appContext.app.config.globalProperties.$storage;
const transition = computed(() => {
const transitions = computed(() => {
return route => {
return route.meta.transition;
};
});
const hideTabs = computed(() => {
return instance?.configure.hideTabs;
});
const layout = computed(() => {
return instance?.layout.layout === "vertical";
});
const getSectionStyle = computed(() => {
return [
hideTabs.value && layout ? "padding-top: 48px;" : "",
!hideTabs.value && layout ? "padding-top: 85px;" : "",
hideTabs.value && !layout.value ? "padding-top: 48px" : "",
!hideTabs.value && !layout.value ? "padding-top: 85px;" : "",
props.fixedHeader ? "" : "padding-top: 0;"
];
});
const transitionMain = defineComponent({
render() {
return h(
Transition,
{
name:
transitions.value(this.route) &&
this.route.meta.transition.enterTransition
? "pure-classes-transition"
: (transitions.value(this.route) &&
this.route.meta.transition.name) ||
"fade-transform",
enterActiveClass:
transitions.value(this.route) &&
`animate__animated ${this.route.meta.transition.enterTransition}`,
leaveActiveClass:
transitions.value(this.route) &&
`animate__animated ${this.route.meta.transition.leaveTransition}`,
mode: "out-in",
appear: true
},
{
default: () => [this.$slots.default()]
}
);
},
props: {
route: {
type: undefined,
required: true
}
}
});
</script>
<template>
<section class="app-main">
<section
:class="[props.fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
:style="getSectionStyle"
>
<router-view>
<template #default="{ Component, route }">
<transition
:name="
transition(route) && route.meta.transition.enterTransition
? 'pure-classes-transition'
: (transition(route) && route.meta.transition.name) ||
'fade-transform'
"
:enter-active-class="
transition(route) &&
`animate__animated ${route.meta.transition.enterTransition}`
"
:leave-active-class="
transition(route) &&
`animate__animated ${route.meta.transition.leaveTransition}`
"
mode="out-in"
appear
>
<el-scrollbar v-if="props.fixedHeader">
<el-backtop title="回到顶部" target=".app-main .el-scrollbar__wrap">
<backTop />
</el-backtop>
<transitionMain :route="route">
<keep-alive
v-if="keepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component :is="Component" :key="route.fullPath" />
<component
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</keep-alive>
<component v-else :is="Component" :key="route.fullPath" />
</transition>
<component
v-else
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</transitionMain>
</el-scrollbar>
<div v-else>
<transitionMain :route="route">
<keep-alive
v-if="keepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</keep-alive>
<component
v-else
:is="Component"
:key="route.fullPath"
class="main-content"
/>
</transitionMain>
</div>
</template>
</router-view>
</section>
@@ -50,22 +136,19 @@ const transition = computed(() => {
<style scoped>
.app-main {
min-height: calc(100vh - 70px);
width: 100%;
height: 90vh;
height: 100vh;
position: relative;
overflow-x: hidden;
}
.fixed-header + .app-main {
padding-top: 50px;
.app-main-nofixed-header {
width: 100%;
min-height: 100vh;
position: relative;
}
</style>
<style lang="scss">
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
.main-content {
margin: 24px;
}
</style>

View File

@@ -1,6 +1,10 @@
<script setup lang="ts">
import { computed } from "vue";
import { useI18n } from "vue-i18n";
import { emitter } from "/@/utils/mitt";
import Notice from "./notice/index.vue";
import avatars from "/@/assets/avatars.jpg";
import { transformI18n } from "/@/plugins/i18n";
import Hamburger from "./sidebar/hamBurger.vue";
import { useRouter, useRoute } from "vue-router";
import { storageSession } from "/@/utils/storage";
@@ -9,7 +13,8 @@ import { useAppStoreHook } from "/@/store/modules/app";
import { unref, watch, getCurrentInstance } from "vue";
import { deviceDetection } from "/@/utils/deviceDetection";
import screenfull from "../components/screenfull/index.vue";
import globalization from "/@/assets/svg/globalization.svg";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import globalization from "/@/assets/svg/globalization.svg?component";
const instance =
getCurrentInstance().appContext.config.globalProperties.$storage;
@@ -17,13 +22,26 @@ const pureApp = useAppStoreHook();
const router = useRouter();
const route = useRoute();
let usename = storageSession.getItem("info")?.username;
const { locale, t } = useI18n();
const { locale } = useI18n();
const getDropdownItemStyle = computed(() => {
return t => {
return {
background: locale.value === t ? useEpThemeStoreHook().epThemeColor : "",
color: locale.value === t ? "#f4f4f5" : "#000"
};
};
});
watch(
() => locale.value,
() => {
//@ts-ignore
document.title = t(unref(route.meta.title)); // 动态title
document.title = transformI18n(
//@ts-ignore
unref(route.meta.title),
unref(route.meta.i18n)
); // 动态title
}
);
@@ -65,27 +83,29 @@ function translationEn() {
<Breadcrumb class="breadcrumb-container" />
<div class="vertical-header-right">
<!-- 通知 -->
<Notice id="header-notice" />
<!-- 全屏 -->
<screenfull v-show="!deviceDetection()" />
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown trigger="click">
<el-dropdown id="header-translation" trigger="click">
<globalization />
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="{
background: locale === 'zh' ? '#1b2a47' : '',
color: locale === 'zh' ? '#f4f4f5' : '#000'
}"
:style="getDropdownItemStyle('zh')"
@click="translationCh"
>简体中文</el-dropdown-item
><IconifyIconOffline
class="check-zh"
v-show="locale === 'zh'"
icon="check"
/>简体中文</el-dropdown-item
>
<el-dropdown-item
:style="{
background: locale === 'en' ? '#1b2a47' : '',
color: locale === 'en' ? '#f4f4f5' : '#000'
}"
:style="getDropdownItemStyle('en')"
@click="translationEn"
><el-icon class="check-en" v-show="locale === 'en'"
><IconifyIconOffline icon="check" /></el-icon
>English</el-dropdown-item
>
</el-dropdown-menu>
@@ -94,24 +114,25 @@ function translationEn() {
<!-- 退出登陆 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
/>
<img :src="avatars" />
<p>{{ usename }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
<el-dropdown-item icon="el-icon-switch-button" @click="logout">{{
$t("message.hsLoginOut")
}}</el-dropdown-item>
<el-dropdown-item @click="logout">
<i class="ri-logout-circle-r-line"></i
>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<i
<el-icon
class="el-icon-setting"
:title="$t('message.hssystemSet')"
:title="$t('buttons.hssystemSet')"
@click="onPanel"
></i>
>
<IconifyIconOffline icon="setting" />
</el-icon>
</div>
</div>
</template>
@@ -131,10 +152,6 @@ function translationEn() {
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.vertical-header-right {
@@ -145,6 +162,12 @@ function translationEn() {
color: #000000d9;
justify-content: flex-end;
:deep(.dropdown-badge) {
&:hover {
background: #f6f6f6;
}
}
.screen-full {
cursor: pointer;
@@ -191,8 +214,8 @@ function translationEn() {
.el-icon-setting {
height: 48px;
width: 40px;
padding: 11px;
width: 38px;
padding: 12px;
display: flex;
cursor: pointer;
align-items: center;
@@ -210,7 +233,7 @@ function translationEn() {
.translation {
.el-dropdown-menu__item {
padding: 0 40px !important;
padding: 5px 40px !important;
}
.el-dropdown-menu__item:focus,
@@ -218,11 +241,25 @@ function translationEn() {
color: #606266;
background: #f0f0f0;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
.logout {
max-width: 120px;
.el-dropdown-menu__item {
padding: 0 18px !important;
min-width: 100%;
display: inline-flex;
flex-wrap: wrap;
}
.el-dropdown-menu__item:focus,

View File

@@ -0,0 +1,146 @@
export interface ListItem {
avatar: string;
title: string;
datetime: string;
type: string;
description: string;
status?: "" | "success" | "warning" | "info" | "danger";
extra?: string;
}
export interface TabItem {
key: string;
name: string;
list: ListItem[];
}
export const noticesData: TabItem[] = [
{
key: "1",
name: "通知",
list: [
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png",
title: "你收到了 12 份新周报",
datetime: "一年前",
description: "",
type: "1"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png",
title: "你推荐的 前端高手 已通过第三轮面试",
datetime: "一年前",
description: "",
type: "1"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png",
title: "这种模板可以区分多种通知类型",
datetime: "一年前",
description: "",
type: "1"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
title:
"展示标题内容超过一行后的处理方式如果内容超过1行将自动截断并支持tooltip显示完整标题。",
datetime: "一年前",
description: "",
type: "1"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
title: "左侧图标用于区分不同的类型",
datetime: "一年前",
description: "",
type: "1"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png",
title: "左侧图标用于区分不同的类型",
datetime: "一年前",
description: "",
type: "1"
}
]
},
{
key: "2",
name: "消息",
list: [
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
title: "李白 评论了你",
description: "长风破浪会有时,直挂云帆济沧海",
datetime: "一年前",
type: "2"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
title: "李白 回复了你",
description: "行路难,行路难,多歧路,今安在。",
datetime: "一年前",
type: "2"
},
{
avatar:
"https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg",
title: "标题",
description:
"请将鼠标移动到此处以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2超过2行的描述内容将被省略并且可以通过tooltip查看完整内容",
datetime: "一年前",
type: "2"
}
]
},
{
key: "3",
name: "代办",
list: [
{
avatar: "",
title: "任务名称",
description: "任务需要在 2021-11-16 20:00 前启动",
datetime: "",
extra: "未开始",
status: "info",
type: "3"
},
{
avatar: "",
title: "第三方紧急代码变更",
description:
"一拳提交于 2021-11-16需在 2021-11-18 前完成代码变更任务",
datetime: "",
extra: "马上到期",
status: "danger",
type: "3"
},
{
avatar: "",
title: "信息安全考试",
description: "指派小仙于 2021-12-12 前完成更新并发布",
datetime: "",
extra: "已耗时 8 天",
status: "warning",
type: "3"
},
{
avatar: "",
title: "vue-pure-admin 版本发布",
description: "vue-pure-admin 版本发布",
datetime: "",
extra: "进行中",
type: "3"
}
]
}
];

View File

@@ -0,0 +1,82 @@
<script setup lang="ts">
import { ref } from "vue";
import NoticeList from "./noticeList.vue";
import { noticesData } from "./data";
const activeName = ref(noticesData[0].name);
const notices = ref(noticesData);
let noticesNum = ref(0);
notices.value.forEach(notice => {
noticesNum.value += notice.list.length;
});
</script>
<template>
<el-dropdown trigger="click" placement="bottom-end">
<span class="dropdown-badge">
<el-badge :value="noticesNum" :max="99">
<el-icon class="header-notice-icon"
><IconifyIconOffline icon="bell"
/></el-icon>
</el-badge>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-tabs v-model="activeName" class="dropdown-tabs">
<template v-for="item in notices" :key="item.key">
<el-tab-pane
:label="`${item.name}(${item.list.length})`"
:name="item.name"
>
<el-scrollbar max-height="330px">
<div class="noticeList-container">
<NoticeList :list="item.list" />
</div>
</el-scrollbar>
</el-tab-pane>
</template>
</el-tabs>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<style lang="scss" scoped>
.dropdown-badge {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
width: 60px;
cursor: pointer;
.header-notice-icon {
font-size: 18px;
}
}
.dropdown-tabs {
width: 336px;
background-color: #fff;
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
border-radius: 4px;
:deep(.el-tabs__header) {
margin: 0;
}
:deep(.el-tabs__nav-scroll) {
display: flex;
justify-content: center;
}
:deep(.el-tabs__nav-wrap)::after {
height: 1px;
}
:deep(.noticeList-container) {
padding: 15px 24px 0 24px;
}
}
</style>

View File

@@ -0,0 +1,168 @@
<script setup lang="ts">
import { ListItem } from "./data";
import { ref, PropType, nextTick } from "vue";
const props = defineProps({
noticeItem: {
type: Object as PropType<ListItem>,
default: () => {}
}
});
const titleRef = ref(null);
const descriptionRef = ref(null);
const titleTooltip = ref(false);
const descriptionTooltip = ref(false);
function hoverTitle() {
nextTick(() => {
titleRef.value?.scrollWidth > titleRef.value?.clientWidth
? (titleTooltip.value = true)
: (titleTooltip.value = false);
});
}
function hoverDescription(event, description) {
// currentWidth 为文本在页面中所占的宽度创建标签加入到页面获取currentWidth ,最后在移除
let tempTag = document.createElement("span");
tempTag.innerText = description;
tempTag.className = "getDescriptionWidth";
document.querySelector("body").appendChild(tempTag);
let currentWidth = (
document.querySelector(".getDescriptionWidth") as HTMLSpanElement
).offsetWidth;
document.querySelector(".getDescriptionWidth").remove();
// cellWidth为容器的宽度
const cellWidth = event.target.offsetWidth;
// 当文本宽度大于容器宽度两倍时,代表文本显示超过两行
currentWidth > 2 * cellWidth
? (descriptionTooltip.value = true)
: (descriptionTooltip.value = false);
}
</script>
<template>
<div class="notice-container">
<el-avatar
v-if="props.noticeItem.avatar"
:size="30"
:src="props.noticeItem.avatar"
class="notice-container-avatar"
></el-avatar>
<div class="notice-container-text">
<div class="notice-text-title">
<el-tooltip
popper-class="notice-title-popper"
:disabled="!titleTooltip"
:content="props.noticeItem.title"
placement="top-start"
>
<div
ref="titleRef"
class="notice-title-content"
@mouseover="hoverTitle"
>
{{ props.noticeItem.title }}
</div>
</el-tooltip>
<el-tag
v-if="props.noticeItem?.extra"
:type="props.noticeItem?.status"
size="small"
class="notice-title-extra"
>{{ props.noticeItem?.extra }}
</el-tag>
</div>
<el-tooltip
popper-class="notice-title-popper"
:disabled="!descriptionTooltip"
:content="props.noticeItem.description"
placement="top-start"
>
<div
ref="descriptionRef"
class="notice-text-description"
@mouseover="hoverDescription($event, props.noticeItem.description)"
>
{{ props.noticeItem.description }}
</div>
</el-tooltip>
<div class="notice-text-datetime">
{{ props.noticeItem.datetime }}
</div>
</div>
</div>
</template>
<style>
.notice-title-popper {
max-width: 238px;
}
</style>
<style scoped lang="scss">
.notice-container {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
.notice-container-avatar {
margin-right: 16px;
background: #fff;
}
.notice-container-text {
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
.notice-text-title {
display: flex;
margin-bottom: 8px;
font-weight: 400;
font-size: 14px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.85);
cursor: pointer;
.notice-title-content {
flex: 1;
width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.notice-title-extra {
float: right;
margin-top: -1.5px;
font-weight: 400;
}
}
.notice-text-description,
.notice-text-datetime {
font-size: 12px;
line-height: 1.5715;
color: rgba(0, 0, 0, 0.45);
}
.notice-text-description {
display: -webkit-box;
text-overflow: ellipsis;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.notice-text-datetime {
margin-top: 4px;
}
}
}
</style>

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import { PropType } from "vue";
import NoticeItem from "./noticeItem.vue";
import { ListItem } from "./data";
const props = defineProps({
list: {
type: Array as PropType<Array<ListItem>>,
default: () => []
}
});
</script>
<template>
<div v-if="props.list.length">
<NoticeItem
v-for="(item, index) in props.list"
:noticeItem="item"
:key="index"
></NoticeItem>
</div>
<el-empty v-else description="暂无数据"></el-empty>
</template>

View File

@@ -1,33 +1,18 @@
<script setup lang="ts">
import { ref } from "vue";
import { useEventListener, onClickOutside } from "@vueuse/core";
import { onClickOutside } from "@vueuse/core";
import { emitter } from "/@/utils/mitt";
let show = ref<Boolean>(false);
const target = ref(null);
onClickOutside(target, () => {
onClickOutside(target, event => {
if (event.clientX > target.value.offsetLeft) return;
show.value = false;
});
const addEventClick = (): void => {
useEventListener("click", closeSidebar);
};
const closeSidebar = (evt: any): void => {
const parent = evt.target.closest(".right-panel");
if (!parent) {
show.value = false;
window.removeEventListener("click", closeSidebar);
}
};
emitter.on("openPanel", () => {
show.value = true;
});
defineExpose({
addEventClick
});
</script>
<template>
@@ -37,7 +22,9 @@ defineExpose({
<div class="right-panel-items">
<div class="project-configuration">
<h3>项目配置</h3>
<i class="el-icon-close" @click="show = !show"></i>
<el-icon title="关闭配置" class="el-icon-close" @click="show = !show">
<IconifyIconOffline icon="close" />
</el-icon>
</div>
<div style="border-bottom: 1px solid #dcdfe6"></div>
<slot />

View File

@@ -8,8 +8,8 @@ const { isFullscreen, toggle } = useFullscreen();
<i
:title="
isFullscreen
? $t('message.hsexitfullscreen')
: $t('message.hsfullscreen')
? $t('buttons.hsexitfullscreen')
: $t('buttons.hsfullscreen')
"
:class="
isFullscreen
@@ -23,7 +23,7 @@ const { isFullscreen, toggle } = useFullscreen();
<style lang="scss" scoped>
.screen-full {
width: 36px;
height: 62px;
height: 48px;
display: flex;
align-items: center;
justify-content: space-around;

View File

@@ -1,51 +1,111 @@
<script setup lang="ts">
import { split } from "lodash-es";
import panel from "../panel/index.vue";
import { useRouter } from "vue-router";
import { emitter } from "/@/utils/mitt";
import { templateRef } from "@vueuse/core";
import { debounce } from "/@/utils/debounce";
import { useAppStoreHook } from "/@/store/modules/app";
import { storageLocal, storageSession } from "/@/utils/storage";
import {
reactive,
ref,
unref,
watch,
computed,
nextTick,
useCssModule,
getCurrentInstance
} from "vue";
import rgbHex from "rgb-hex";
import { find } from "lodash-es";
import { getConfig } from "/@/config";
import { useRouter } from "vue-router";
import panel from "../panel/index.vue";
import { emitter } from "/@/utils/mitt";
import { templateRef } from "@vueuse/core";
import { debounce } from "/@/utils/debounce";
import { themeColorsType } from "../../types";
import { useAppStoreHook } from "/@/store/modules/app";
import { shadeBgColor } from "../../theme/element-plus";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
import { storageLocal, storageSession } from "/@/utils/storage";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { createNewStyle, writeNewStyle } from "../../theme/element-plus";
import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils";
import dayIcon from "/@/assets/svg/day.svg?component";
import darkIcon from "/@/assets/svg/dark.svg?component";
const router = useRouter();
const { isSelect } = useCssModule();
const body = document.documentElement as HTMLElement;
const instance =
getCurrentInstance().appContext.app.config.globalProperties.$storage;
// 默认灵动模式
const markValue = ref(storageLocal.getItem("showModel") || "smart");
const instanceConfig =
getCurrentInstance().appContext.app.config.globalProperties.$config;
const logoVal = ref(storageLocal.getItem("logoVal") || "1");
let themeColors = ref<Array<themeColorsType>>([
// 道奇蓝(默认)
{ rgb: "27, 42, 71", themeColor: "default" },
// 亮白色
{ rgb: "255, 255, 255", themeColor: "light" },
// 猩红色
{ rgb: "245, 34, 45", themeColor: "dusk" },
// 橙红色
{ rgb: "250, 84, 28", themeColor: "volcano" },
// 金色
{ rgb: "250, 219, 20", themeColor: "yellow" },
// 绿宝石
{ rgb: "19, 194, 194", themeColor: "mingQing" },
// 酸橙绿
{ rgb: "82, 196, 26", themeColor: "auroraGreen" },
// 深粉色
{ rgb: "235, 47, 150", themeColor: "pink" },
// 深紫罗兰色
{ rgb: "114, 46, 209", themeColor: "saucePurple" }
]);
const localOperate = (key: string, value?: any, model?: string): any => {
model && model === "set"
? storageLocal.setItem(key, value)
: storageLocal.getItem(key);
};
const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
const settings = reactive({
greyVal: storageLocal.getItem("greyVal"),
weekVal: storageLocal.getItem("weekVal"),
tagsVal: storageLocal.getItem("tagsVal")
let layoutTheme =
ref(storageLocal.getItem("responsive-layout")) ||
ref({
layout: instanceConfig?.Layout ?? "vertical",
theme: instanceConfig?.Theme ?? "default"
});
settings.greyVal === null
? localOperate("greyVal", false, "set")
: document.querySelector("html")?.setAttribute("class", "html-grey");
// body添加layout属性作用于src/style/sidebar.scss
if (unref(layoutTheme)) {
let layout = unref(layoutTheme).layout;
let theme = unref(layoutTheme).theme;
toggleTheme({
scopeName: `layout-theme-${theme}`
});
setLayoutModel(layout);
}
settings.weekVal === null
? localOperate("weekVal", false, "set")
: document.querySelector("html")?.setAttribute("class", "html-weakness");
// 默认灵动模式
const markValue = ref(instance.configure?.showModel ?? "smart");
const logoVal = ref(instance.configure?.showLogo ?? true);
const epThemeColor = ref(useEpThemeStoreHook().getEpThemeColor);
const settings = reactive({
greyVal: instance.configure.grey,
weakVal: instance.configure.weak,
tabsVal: instance.configure.hideTabs,
showLogo: instance.configure.showLogo,
showModel: instance.configure.showModel,
multiTagsCache: instance.configure.multiTagsCache
});
const getThemeColorStyle = computed(() => {
return rgb => {
return { background: `rgb(${rgb})` };
};
});
function changeStorageConfigure(key, val) {
const storageConfigure = instance.configure;
storageConfigure[key] = val;
instance.configure = storageConfigure;
}
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
const targetEl = target || document.body;
@@ -55,81 +115,70 @@ function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
}
// 灰色模式设置
const greyChange = ({ value }): void => {
const greyChange = (value): void => {
toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
value
? localOperate("greyVal", true, "set")
: localOperate("greyVal", false, "set");
changeStorageConfigure("grey", value);
};
// 色弱模式设置
const weekChange = ({ value }): void => {
const weekChange = (value): void => {
toggleClass(
settings.weekVal,
settings.weakVal,
"html-weakness",
document.querySelector("html")
);
value
? localOperate("weekVal", true, "set")
: localOperate("weekVal", false, "set");
changeStorageConfigure("weak", value);
};
const tagsChange = () => {
let showVal = settings.tagsVal;
showVal
? storageLocal.setItem("tagsVal", true)
: storageLocal.setItem("tagsVal", false);
let showVal = settings.tabsVal;
changeStorageConfigure("hideTabs", showVal);
emitter.emit("tagViewsChange", showVal);
};
const multiTagsCacheChange = () => {
let multiTagsCache = settings.multiTagsCache;
changeStorageConfigure("multiTagsCache", multiTagsCache);
useMultiTagsStoreHook().multiTagsCacheChange(multiTagsCache);
};
// 清空缓存并返回登录页
function onReset() {
toggleClass(getConfig().Grey, "html-grey", document.querySelector("html"));
toggleClass(
getConfig().Weak,
"html-weakness",
document.querySelector("html")
);
useMultiTagsStoreHook().handleTags("equal", [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "menus.hshome",
icon: "home-filled",
i18n: true,
showLink: true
}
}
]);
useMultiTagsStoreHook().multiTagsCacheChange(getConfig().MultiTagsCache);
useEpThemeStoreHook().setEpThemeColor(getConfig().EpThemeColor);
storageLocal.clear();
storageSession.clear();
router.push("/login");
}
function onChange({ label }) {
storageLocal.setItem("showModel", label);
function onChange(label) {
changeStorageConfigure("showModel", label);
emitter.emit("tagViewsShowModel", label);
}
const verticalDarkDom = templateRef<HTMLElement | null>(
"verticalDarkDom",
null
);
const verticalLightDom = templateRef<HTMLElement | null>(
"verticalLightDom",
null
);
const horizontalDarkDom = templateRef<HTMLElement | null>(
"horizontalDarkDom",
null
);
const horizontalLightDom = templateRef<HTMLElement | null>(
"horizontalLightDom",
null
);
let dataTheme =
ref(storageLocal.getItem("responsive-layout")) ||
ref({
layout: "horizontal-dark"
});
if (unref(dataTheme)) {
// 设置主题
let theme = split(unref(dataTheme).layout, "-")[1];
window.document.body.setAttribute("data-theme", theme);
// 设置导航模式
let layout = split(unref(dataTheme).layout, "-")[0];
window.document.body.setAttribute("data-layout", layout);
}
// 侧边栏Logo
function logoChange() {
unref(logoVal) === "1"
? storageLocal.setItem("logoVal", "1")
: storageLocal.setItem("logoVal", "-1");
unref(logoVal)
? changeStorageConfigure("showLogo", true)
: changeStorageConfigure("showLogo", false);
emitter.emit("logoChange", unref(logoVal));
}
@@ -141,181 +190,262 @@ function setFalse(Doms): any {
watch(instance, ({ layout }) => {
switch (layout["layout"]) {
case "vertical-dark":
toggleClass(true, isSelect, unref(verticalDarkDom));
debounce(
setFalse([verticalLightDom, horizontalDarkDom, horizontalLightDom]),
50
);
case "vertical":
toggleClass(true, isSelect, unref(verticalRef));
debounce(setFalse([horizontalRef]), 50);
break;
case "vertical-light":
toggleClass(true, isSelect, unref(verticalLightDom));
debounce(
setFalse([verticalDarkDom, horizontalDarkDom, horizontalLightDom]),
50
);
break;
case "horizontal-dark":
toggleClass(true, isSelect, unref(horizontalDarkDom));
debounce(
setFalse([verticalDarkDom, verticalLightDom, horizontalLightDom]),
50
);
break;
case "horizontal-light":
toggleClass(true, isSelect, unref(horizontalLightDom));
debounce(
setFalse([verticalDarkDom, verticalLightDom, horizontalDarkDom]),
50
);
case "horizontal":
toggleClass(true, isSelect, unref(horizontalRef));
debounce(setFalse([verticalRef]), 50);
break;
}
});
function setTheme(layout: string, theme: string) {
dataTheme.value.layout = `${layout}-${theme}`;
window.document.body.setAttribute("data-layout", layout);
window.document.body.setAttribute("data-theme", theme);
instance.layout = { layout: `${layout}-${theme}` };
// 主题色 激活选择项
const getThemeColor = computed(() => {
return current => {
if (
current === layoutTheme.value.theme &&
layoutTheme.value.theme !== "light"
) {
return "#fff";
} else if (
current === layoutTheme.value.theme &&
layoutTheme.value.theme === "light"
) {
return "#1d2b45";
} else {
return "transparent";
}
};
});
// 设置导航模式
function setLayoutModel(layout: string) {
layoutTheme.value.layout = layout;
window.document.body.setAttribute("layout", layout);
instance.layout = {
layout,
theme: layoutTheme.value.theme,
darkMode: instance.layout.darkMode,
sidebarStatus: instance.layout.sidebarStatus,
epThemeColor: instance.layout.epThemeColor
};
useAppStoreHook().setLayout(layout);
}
// 存放夜间主题切换前的导航主题色
let tempLayoutThemeColor;
// 设置导航主题色
function setLayoutThemeColor(theme: string) {
tempLayoutThemeColor = instance.layout.theme;
layoutTheme.value.theme = theme;
toggleTheme({
scopeName: `layout-theme-${theme}`
});
instance.layout = {
layout: useAppStoreHook().layout,
theme,
darkMode: dataTheme.value,
sidebarStatus: instance.layout.sidebarStatus,
epThemeColor: instance.layout.epThemeColor
};
if (theme === "default" || theme === "light") {
setEpThemeColor(getConfig().EpThemeColor);
} else {
const colors = find(themeColors.value, { themeColor: theme });
const color = "#" + rgbHex(colors.rgb);
setEpThemeColor(color);
}
}
// 设置ep主题色
const setEpThemeColor = (color: string) => {
writeNewStyle(createNewStyle(color));
useEpThemeStoreHook().setEpThemeColor(color);
body.style.setProperty("--el-color-primary-active", shadeBgColor(color));
};
let dataTheme = ref<boolean>(instance.layout.darkMode);
// 日间、夜间主题切换
function dataThemeChange() {
if (dataTheme.value) {
body.setAttribute("data-theme", "dark");
setLayoutThemeColor("light");
} else {
body.setAttribute("data-theme", "");
tempLayoutThemeColor && setLayoutThemeColor(tempLayoutThemeColor);
instance.layout = {
layout: useAppStoreHook().layout,
theme: instance.layout.theme,
darkMode: dataTheme.value,
sidebarStatus: instance.layout.sidebarStatus,
epThemeColor: instance.layout.epThemeColor
};
}
}
//初始化项目配置
nextTick(() => {
settings.greyVal &&
document.querySelector("html")?.setAttribute("class", "html-grey");
settings.weakVal &&
document.querySelector("html")?.setAttribute("class", "html-weakness");
settings.tabsVal && tagsChange();
writeNewStyle(createNewStyle(epThemeColor.value));
dataThemeChange();
});
</script>
<template>
<panel>
<el-divider>主题风格</el-divider>
<ul class="theme-stley">
<el-tooltip
class="item"
effect="dark"
content="左侧菜单暗色模式"
placement="bottom"
<el-divider>主题</el-divider>
<el-switch
v-model="dataTheme"
inline-prompt
class="pure-datatheme"
:active-icon="dayIcon"
:inactive-icon="darkIcon"
@change="dataThemeChange"
>
</el-switch>
<el-divider>导航栏模式</el-divider>
<ul class="pure-theme">
<el-tooltip class="item" content="左侧菜单模式" placement="bottom">
<li
:class="dataTheme.layout === 'vertical-dark' ? $style.isSelect : ''"
ref="verticalDarkDom"
@click="setTheme('vertical', 'dark')"
:class="layoutTheme.layout === 'vertical' ? $style.isSelect : ''"
ref="verticalRef"
@click="setLayoutModel('vertical')"
>
<div></div>
<div></div>
</li>
</el-tooltip>
<el-tooltip
class="item"
effect="dark"
content="左侧菜单亮色模式"
placement="bottom"
>
<el-tooltip class="item" content="顶部菜单模式" placement="bottom">
<li
:class="dataTheme.layout === 'vertical-light' ? $style.isSelect : ''"
ref="verticalLightDom"
@click="setTheme('vertical', 'light')"
:class="layoutTheme.layout === 'horizontal' ? $style.isSelect : ''"
ref="horizontalRef"
@click="setLayoutModel('horizontal')"
>
<div></div>
<div></div>
</li>
</el-tooltip>
</ul>
<el-tooltip
class="item"
effect="dark"
content="顶部菜单暗色模式"
placement="bottom"
>
<el-divider v-show="!dataTheme">主题色</el-divider>
<ul class="theme-color" v-show="!dataTheme">
<li
:class="dataTheme.layout === 'horizontal-dark' ? $style.isSelect : ''"
ref="horizontalDarkDom"
@click="setTheme('horizontal', 'dark')"
v-for="(item, index) in themeColors"
:key="index"
:style="getThemeColorStyle(item.rgb)"
@click="setLayoutThemeColor(item.themeColor)"
>
<div></div>
<div></div>
<el-icon
style="margin: 0.1em 0.1em 0 0"
:size="17"
:color="getThemeColor(item.themeColor)"
>
<IconifyIconOffline icon="check" />
</el-icon>
</li>
</el-tooltip>
<el-tooltip
class="item"
effect="dark"
content="顶部菜单亮色模式"
placement="bottom"
>
<li
:class="
dataTheme.layout === 'horizontal-light' ? $style.isSelect : ''
"
ref="horizontalLightDom"
@click="setTheme('horizontal', 'light')"
>
<div></div>
<div></div>
</li>
</el-tooltip>
</ul>
<el-divider>界面显示</el-divider>
<ul class="setting">
<li>
<li v-show="!dataTheme">
<span>灰色模式</span>
<vxe-switch
<el-switch
v-model="settings.greyVal"
open-label=""
close-label=""
inline-prompt
inactive-color="#a6a6a6"
active-text=""
inactive-text=""
@change="greyChange"
></vxe-switch>
>
</el-switch>
</li>
<li>
<li v-show="!dataTheme">
<span>色弱模式</span>
<vxe-switch
v-model="settings.weekVal"
open-label=""
close-label=""
<el-switch
v-model="settings.weakVal"
inline-prompt
inactive-color="#a6a6a6"
active-text=""
inactive-text=""
@change="weekChange"
></vxe-switch>
>
</el-switch>
</li>
<li>
<span>隐藏标签页</span>
<vxe-switch
v-model="settings.tagsVal"
open-label=""
close-label=""
<el-switch
v-model="settings.tabsVal"
inline-prompt
inactive-color="#a6a6a6"
active-text=""
inactive-text=""
@change="tagsChange"
></vxe-switch>
>
</el-switch>
</li>
<li>
<span>侧边栏Logo</span>
<vxe-switch
<el-switch
v-model="logoVal"
open-value="1"
close-value="-1"
open-label=""
close-label=""
inline-prompt
:active-value="true"
:inactive-value="false"
inactive-color="#a6a6a6"
active-text=""
inactive-text=""
@change="logoChange"
></vxe-switch>
>
</el-switch>
</li>
<li>
<span>标签页持久化</span>
<el-switch
v-model="settings.multiTagsCache"
inline-prompt
inactive-color="#a6a6a6"
active-text=""
inactive-text=""
@change="multiTagsCacheChange"
>
</el-switch>
</li>
<li>
<span>标签风格</span>
<vxe-radio-group v-model="markValue" @change="onChange">
<vxe-radio label="card" content="卡片"></vxe-radio>
<vxe-radio label="smart" content="灵动"></vxe-radio>
</vxe-radio-group>
<el-radio-group v-model="markValue" size="small" @change="onChange">
<el-radio label="card">卡片</el-radio>
<el-radio label="smart">灵动</el-radio>
</el-radio-group>
</li>
</ul>
<el-divider />
<vxe-button
status="danger"
<el-button
type="danger"
style="width: 90%; margin: 24px 15px"
content="清空缓存并返回登录页"
icon="fa fa-sign-out"
@click="onReset"
></vxe-button>
>
<i class="fa fa-sign-out"></i>
清空缓存并返回登录页</el-button
>
</panel>
</template>
<style scoped module>
.isSelect {
border: 2px solid #0960bd;
border: 2px solid var(--el-color-primary);
}
</style>
@@ -336,10 +466,18 @@ function setTheme(layout: string, theme: string) {
font-weight: 700;
}
.theme-stley {
.pure-datatheme {
width: 100%;
height: 50px;
text-align: center;
display: block;
padding-top: 25px;
}
.pure-theme {
margin-top: 25px;
width: 100%;
height: 180px;
height: 100px;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
@@ -376,28 +514,6 @@ function setTheme(layout: string, theme: string) {
}
&:nth-child(2) {
div {
&:nth-child(1) {
width: 30%;
height: 100%;
box-shadow: 0 0 1px #888;
background: #fff;
border-radius: 4px 0 0 4px;
}
&:nth-child(2) {
width: 70%;
height: 30%;
top: 0;
right: 0;
background: #fff;
box-shadow: 0 0 1px #888;
position: absolute;
}
}
}
&:nth-child(3) {
div {
&:nth-child(1) {
width: 100%;
@@ -407,16 +523,29 @@ function setTheme(layout: string, theme: string) {
}
}
}
}
}
&:nth-child(4) {
div {
&:nth-child(1) {
.theme-color {
width: 100%;
height: 30%;
background: #fff;
box-shadow: 0 0 1px #888;
}
}
height: 40px;
margin-top: 20px;
display: flex;
justify-content: center;
li {
float: left;
width: 20px;
height: 20px;
margin-top: 8px;
margin-right: 8px;
font-weight: 700;
text-align: center;
border-radius: 2px;
cursor: pointer;
&:nth-child(2) {
border: 1px solid #ddd;
}
}
}

View File

@@ -1,10 +1,16 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import { isEqual } from "lodash-es";
import { transformI18n } from "/@/plugins/i18n";
import { getParentPaths, findRouteByPath } from "/@/router/utils";
import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
import { useRoute, useRouter, RouteLocationMatched } from "vue-router";
const levelList = ref([]);
const route = useRoute();
const levelList = ref([]);
const router = useRouter();
const routes = router.options.routes;
const multiTags = useMultiTagsStoreHook().multiTags;
const isDashboard = (route: RouteLocationMatched): boolean | string => {
const name = route && (route.name as string);
@@ -15,19 +21,57 @@ const isDashboard = (route: RouteLocationMatched): boolean | string => {
};
const getBreadcrumb = (): void => {
let matched = route.matched.filter(item => item.meta && item.meta.title);
// 当前路由信息
let currentRoute;
if (Object.keys(route.query).length > 0) {
multiTags.forEach(item => {
if (isEqual(route.query, item?.query)) {
currentRoute = item;
}
});
} else {
currentRoute = findRouteByPath(router.currentRoute.value.path, multiTags);
}
// 当前路由的父级路径组成的数组
const parentRoutes = getParentPaths(router.currentRoute.value.path, routes);
// 存放组成面包屑的数组
let matched = [];
// 获取每个父级路径对应的路由信息
parentRoutes.forEach(path => {
if (path !== "/") {
matched.push(findRouteByPath(path, routes));
}
});
if (router.currentRoute.value.meta?.refreshRedirect) {
matched.unshift(
findRouteByPath(
router.currentRoute.value.meta.refreshRedirect as string,
routes
)
);
} else {
// 过滤与子级相同标题的父级路由
matched = matched.filter(item => {
return !item.redirect || (item.redirect && item.children.length !== 1);
});
}
if (currentRoute?.path !== "/welcome") {
matched.push(currentRoute);
}
const first = matched[0];
if (!isDashboard(first)) {
matched = [
{
path: "/welcome",
parentPath: "/",
meta: { title: "message.hshome" }
meta: { title: "menus.hshome", i18n: true }
} as unknown as RouteLocationMatched
].concat(matched);
}
levelList.value = matched.filter(
item => item.meta && item.meta.title && item.meta.breadcrumb !== false
item => item?.meta && item?.meta.title !== false
);
};
@@ -38,6 +82,11 @@ watch(
() => getBreadcrumb()
);
watch(
() => route.query,
() => getBreadcrumb()
);
const handleLink = (item: RouteLocationMatched): any => {
const { redirect, path } = item;
if (redirect) {
@@ -55,10 +104,10 @@ const handleLink = (item: RouteLocationMatched): any => {
<span
v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
class="no-redirect"
>{{ $t(item.meta.title) }}</span
>{{ transformI18n(item.meta.title, item.meta.i18n) }}</span
>
<a v-else @click.prevent="handleLink(item)">
{{ $t(item.meta.title) }}
{{ transformI18n(item.meta.title, item.meta.i18n) }}
</a>
</el-breadcrumb-item>
</transition-group>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import { ref } from "vue";
import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
export interface Props {
isActive: boolean;
}
@@ -7,6 +9,8 @@ const props = withDefaults(defineProps<Props>(), {
isActive: false
});
const fillColor = ref<string>("");
const emit = defineEmits<{
(e: "toggleClick"): void;
}>();
@@ -17,8 +21,15 @@ const toggleClick = () => {
</script>
<template>
<div :class="classes.container" @click="toggleClick">
<div
:class="classes.container"
:title="props.isActive ? '点击折叠' : '点击展开'"
@click="toggleClick"
@mouseenter="fillColor = useEpThemeStoreHook().epThemeColor"
@mouseleave="fillColor = ''"
>
<svg
:fill="fillColor"
:class="['hamburger', props.isActive ? 'is-active' : '']"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"

View File

@@ -8,28 +8,42 @@ import {
getCurrentInstance
} from "vue";
import { useI18n } from "vue-i18n";
import settings from "/@/settings";
import { emitter } from "/@/utils/mitt";
import Notice from "../notice/index.vue";
import { templateRef } from "@vueuse/core";
import SidebarItem from "./sidebarItem.vue";
import avatars from "/@/assets/avatars.jpg";
import { algorithm } from "/@/utils/algorithm";
import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage";
import Icon from "/@/components/ReIcon/src/Icon.vue";
import { deviceDetection } from "/@/utils/deviceDetection";
import globalization from "/@/assets/svg/globalization.svg";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component";
const instance =
getCurrentInstance().appContext.config.globalProperties.$storage;
const title =
getCurrentInstance().appContext.config.globalProperties.$config?.Title;
const menuRef = templateRef<ElRef | null>("menu", null);
const routeStore = usePermissionStoreHook();
const route = useRoute();
const router = useRouter();
const routers = useRouter().options.routes;
let usename = storageSession.getItem("info")?.username;
const { locale, t } = useI18n();
const getDropdownItemStyle = computed(() => {
return t => {
return {
background: locale.value === t ? "#1b2a47" : "",
color: locale.value === t ? "#f4f4f5" : "#000"
};
};
});
watch(
() => locale.value,
() => {
@@ -49,9 +63,10 @@ function onPanel() {
emitter.emit("openPanel");
}
const activeMenu = computed(() => {
const activeMenu = computed((): string => {
const { meta, path } = route;
if (meta.activeMenu) {
// @ts-ignore
return meta.activeMenu;
}
return path;
@@ -113,8 +128,8 @@ onMounted(() => {
<template>
<div class="horizontal-header">
<div class="horizontal-header-left" @click="backHome">
<i class="fa fa-optin-monster"></i>
<h4>{{ settings.title }}</h4>
<Icon svg :width="35" :height="35" content="team-iconlogo" />
<h4>{{ title }}</h4>
</div>
<el-menu
ref="menu"
@@ -126,34 +141,34 @@ onMounted(() => {
@select="menuSelect"
>
<sidebar-item
v-for="route in routeStore.wholeRoutes"
v-for="route in usePermissionStoreHook().wholeMenus"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
<div class="horizontal-header-right">
<!-- 通知 -->
<Notice id="header-notice" />
<!-- 全屏 -->
<screenfull v-show="!deviceDetection()" />
<screenfull id="header-screenfull" v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown trigger="click">
<el-dropdown id="header-translation" trigger="click">
<globalization />
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="{
background: locale === 'zh' ? '#1b2a47' : '',
color: locale === 'zh' ? '#f4f4f5' : '#000'
}"
:style="getDropdownItemStyle('zh')"
@click="translationCh"
><el-icon class="check-zh" v-show="locale === 'zh'"
><IconifyIconOffline icon="check" /></el-icon
>简体中文</el-dropdown-item
>
<el-dropdown-item
:style="{
background: locale === 'en' ? '#1b2a47' : '',
color: locale === 'en' ? '#f4f4f5' : '#000'
}"
:style="getDropdownItemStyle('en')"
@click="translationEn"
><el-icon class="check-en" v-show="locale === 'en'"
><IconifyIconOffline icon="check" /></el-icon
>English</el-dropdown-item
>
</el-dropdown-menu>
@@ -162,24 +177,25 @@ onMounted(() => {
<!-- 退出登陆 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
/>
<img :src="avatars" />
<p>{{ usename }}</p>
</span>
<template #dropdown>
<el-dropdown-menu class="logout">
<el-dropdown-item icon="el-icon-switch-button" @click="logout">{{
$t("message.hsLoginOut")
}}</el-dropdown-item>
<el-dropdown-item @click="logout">
<i class="ri-logout-circle-r-line"></i
>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<i
<el-icon
class="el-icon-setting"
:title="$t('message.hssystemSet')"
:title="$t('buttons.hssystemSet')"
@click="onPanel"
></i>
>
<IconifyIconOffline icon="setting" />
</el-icon>
</div>
</div>
</template>
@@ -187,7 +203,7 @@ onMounted(() => {
<style lang="scss" scoped>
.translation {
.el-dropdown-menu__item {
padding: 0 40px !important;
padding: 5px 40px !important;
}
.el-dropdown-menu__item:focus,
@@ -195,11 +211,25 @@ onMounted(() => {
color: #606266;
background: #f0f0f0;
}
.check-zh {
position: absolute;
left: 20px;
}
.check-en {
position: absolute;
left: 20px;
}
}
.logout {
max-width: 120px;
.el-dropdown-menu__item {
padding: 0 18px !important;
min-width: 100%;
display: inline-flex;
flex-wrap: wrap;
}
.el-dropdown-menu__item:focus,

View File

@@ -1,9 +1,12 @@
<script setup lang="ts">
import settings from "/@/settings";
import { getCurrentInstance } from "vue";
import Icon from "/@/components/ReIcon/src/Icon.vue";
const props = defineProps({
collapse: Boolean
});
const title =
getCurrentInstance().appContext.config.globalProperties.$config?.Title;
</script>
<template>
@@ -12,22 +15,22 @@ const props = defineProps({
<router-link
v-if="props.collapse"
key="props.collapse"
:title="settings.title"
:title="title"
class="sidebar-logo-link"
to="/"
>
<i class="fa fa-optin-monster"></i>
<h1 class="sidebar-title">{{ settings.title }}</h1>
<Icon svg :width="35" :height="35" content="team-iconlogo" />
<span class="sidebar-title">{{ title }}</span>
</router-link>
<router-link
v-else
key="expand"
:title="settings.title"
:title="title"
class="sidebar-logo-link"
to="/"
>
<i class="fa fa-optin-monster"></i>
<h1 class="sidebar-title">{{ settings.title }}</h1>
<Icon svg :width="35" :height="35" content="team-iconlogo" />
<span class="sidebar-title">{{ title }}</span>
</router-link>
</transition>
</div>
@@ -37,28 +40,24 @@ const props = defineProps({
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
height: 48px;
text-align: center;
overflow: hidden;
.sidebar-logo-link {
height: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-top: 5px;
.sidebar-title {
display: inline-block;
margin: 0;
color: #1890ff;
font-weight: 600;
font-size: 20px;
margin-top: 16px;
margin-top: 10px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
}
.fa-optin-monster {
font-size: 30px;
color: #1890ff;
margin-top: 5px;
}
}
.collapse {

View File

@@ -1,12 +1,26 @@
<script setup lang="ts">
import {
ref,
PropType,
nextTick,
computed,
CSSProperties,
getCurrentInstance
} from "vue";
import path from "path";
import { PropType, ref } from "vue";
import { childrenType } from "../../types";
import { transformI18n } from "/@/plugins/i18n";
import { findIconReg } from "/@/components/ReIcon";
import Icon from "/@/components/ReIcon/src/Icon.vue";
import { RouteRecordRaw } from "vue-router";
import { useAppStoreHook } from "/@/store/modules/app";
const instance = getCurrentInstance().appContext.app.config.globalProperties;
const menuMode = instance.$storage.layout?.layout === "vertical";
const pureApp = useAppStoreHook();
const props = defineProps({
item: {
type: Object as PropType<RouteRecordRaw>
type: Object as PropType<childrenType>
},
isNest: {
type: Boolean,
@@ -18,21 +32,75 @@ const props = defineProps({
}
});
type childrenType = {
path?: string;
noShowingChildren?: boolean;
children?: RouteRecordRaw[];
meta?: {
icon?: string;
title?: string;
};
const getNoDropdownStyle = computed((): CSSProperties => {
return {
display: "flex",
alignItems: "center"
};
});
const onlyOneChild = ref<RouteRecordRaw | childrenType>({} as any);
const getDivStyle = computed((): CSSProperties => {
return {
width: pureApp.sidebar.opened ? "" : "100%",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
overflow: "hidden"
};
});
const getMenuTextStyle = computed((): CSSProperties => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
overflow: "hidden",
textOverflow: "ellipsis",
outline: "none"
};
});
const getSubTextStyle = computed((): CSSProperties => {
return {
width: pureApp.sidebar.opened ? "125px" : "",
display: "inline-block",
overflow: "hidden",
textOverflow: "ellipsis"
};
});
const getSpanStyle = computed((): CSSProperties => {
return {
overflow: "hidden",
textOverflow: "ellipsis"
};
});
const onlyOneChild: childrenType = ref(null);
// 存放菜单是否存在showTooltip属性标识
const hoverMenuMap = new WeakMap();
// 存储菜单文本dom元素
const menuTextRef = ref(null);
function hoverMenu(key) {
// 如果当前菜单showTooltip属性已存在退出计算
if (hoverMenuMap.get(key)) return;
nextTick(() => {
// 如果文本内容的整体宽度大于其可视宽度,则文本溢出
menuTextRef.value?.scrollWidth > menuTextRef.value?.clientWidth
? Object.assign(key, {
showTooltip: true
})
: Object.assign(key, {
showTooltip: false
});
hoverMenuMap.set(key, true);
});
}
function hasOneShowingChild(
children: RouteRecordRaw[] = [],
parent: RouteRecordRaw
children: childrenType[] = [],
parent: childrenType
) {
const showingChildren = children.filter((item: any) => {
onlyOneChild.value = item;
@@ -51,34 +119,69 @@ function hasOneShowingChild(
}
function resolvePath(routePath) {
const httpReg = /^http(s?):\/\//;
if (httpReg.test(routePath)) {
return props.basePath + "/" + routePath;
} else {
return path.resolve(props.basePath, routePath);
}
}
</script>
<template>
<template
v-if="
hasOneShowingChild(props.item.children, props.item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
!props.item.alwaysShow
(!onlyOneChild.children || onlyOneChild.noShowingChildren)
"
>
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
:style="getNoDropdownStyle"
>
<i
:class="
onlyOneChild.meta.icon || (props.item.meta && props.item.meta.icon)
<el-icon v-show="props.item.meta.icon">
<component
:is="
findIconReg(
onlyOneChild.meta.icon ||
(props.item.meta && props.item.meta.icon)
)
"
/>
></component>
</el-icon>
<template #title>
<span>{{ $t(onlyOneChild.meta.title) }}</span>
<div :style="getDivStyle">
<span v-if="!menuMode">{{
transformI18n(onlyOneChild.meta.title, onlyOneChild.meta.i18n)
}}</span>
<el-tooltip
v-else
placement="top"
:offset="-10"
:disabled="!onlyOneChild.showTooltip"
>
<template #content>
{{
transformI18n(onlyOneChild.meta.title, onlyOneChild.meta.i18n)
}}
</template>
<span
ref="menuTextRef"
:style="getMenuTextStyle"
@mouseover="hoverMenu(onlyOneChild)"
>
{{
transformI18n(onlyOneChild.meta.title, onlyOneChild.meta.i18n)
}}
</span>
</el-tooltip>
<Icon
v-if="onlyOneChild.meta.extraIcon"
:svg="onlyOneChild.meta.extraIcon.svg ? true : false"
:content="`${onlyOneChild.meta.extraIcon.name}`"
/>
</div>
</template>
</el-menu-item>
</template>
@@ -90,8 +193,33 @@ function resolvePath(routePath) {
popper-append-to-body
>
<template #title>
<i :class="props.item.meta.icon"></i>
<span>{{ $t(props.item.meta.title) }}</span>
<el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon">
<component
:is="findIconReg(props.item.meta && props.item.meta.icon)"
></component>
</el-icon>
<span v-if="!menuMode">{{
transformI18n(props.item.meta.title, props.item.meta.i18n)
}}</span>
<el-tooltip
v-else
placement="top"
:offset="-10"
:disabled="!pureApp.sidebar.opened || !props.item.showTooltip"
>
<template #content>
{{ transformI18n(props.item.meta.title, props.item.meta.i18n) }}
</template>
<div
ref="menuTextRef"
:style="getSubTextStyle"
@mouseover="hoverMenu(props.item)"
>
<span :style="getSpanStyle">
{{ transformI18n(props.item.meta.title, props.item.meta.i18n) }}
</span>
</div>
</el-tooltip>
<Icon
v-if="props.item.meta.extraIcon"
:svg="props.item.meta.extraIcon.svg ? true : false"

View File

@@ -12,14 +12,16 @@ import { usePermissionStoreHook } from "/@/store/modules/permission";
const route = useRoute();
const pureApp = useAppStoreHook();
const router = useRouter().options.routes;
const routeStore = usePermissionStoreHook();
const showLogo = ref(storageLocal.getItem("logoVal") || "1");
const showLogo = ref(
storageLocal.getItem("responsive-configure")?.showLogo ?? true
);
const isCollapse = computed(() => {
return !pureApp.getSidebarStatus;
});
const activeMenu = computed(() => {
const activeMenu = computed((): string => {
const { meta, path } = route;
if (meta.activeMenu) {
// @ts-ignore
return meta.activeMenu;
}
return path;
@@ -58,7 +60,7 @@ onBeforeMount(() => {
<template>
<div :class="['sidebar-container', showLogo ? 'has-logo' : '']">
<Logo v-if="showLogo === '1'" :collapse="isCollapse" />
<Logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
@@ -67,12 +69,14 @@ onBeforeMount(() => {
router
:collapse-transition="false"
mode="vertical"
class="outer-most"
@select="menuSelect"
>
<sidebar-item
v-for="route in routeStore.wholeRoutes"
v-for="route in usePermissionStoreHook().wholeMenus"
:key="route.path"
:item="route"
class="outer-most"
:base-path="route.path"
/>
</el-menu>

View File

@@ -0,0 +1,342 @@
@keyframes scheduleInWidth {
from {
width: 0;
}
to {
width: 100%;
}
}
@keyframes scheduleOutWidth {
from {
width: 100%;
}
to {
width: 0;
}
}
@-webkit-keyframes rotate {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@-moz-keyframes rotate {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(360deg);
}
}
@-o-keyframes rotate {
from {
-o-transform: rotate(0deg);
}
to {
-o-transform: rotate(360deg);
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes close {
from {
transform: translate(-50%, -50%);
}
to {
transform: translate(0, -50%);
}
}
.tags-view {
width: 100%;
font-size: 14px;
display: flex;
align-items: center;
color: var(--el-text-color-regular);
background: #fff;
position: relative;
box-shadow: 0 0 1px #888;
.scroll-item {
border-radius: 3px 3px 0 0;
padding: 0 6px 0 6px;
box-shadow: 0 0 1px #888;
position: relative;
margin-right: 4px;
height: 28px;
display: inline-block;
line-height: 28px;
transition: all 0.4s;
cursor: pointer;
.el-icon-close {
font-size: 10px;
color: #1890ff;
cursor: pointer;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: font-size 0.2s;
&:hover {
border-radius: 50%;
color: #fff;
background: #b4bccc;
font-size: 13px;
}
}
&.is-closable:not(:first-child) {
&:hover {
padding-right: 18px;
&:not(.is-active) {
.el-icon-close {
animation: close 200ms ease-in forwards;
}
}
}
}
}
a {
text-decoration: none;
color: #666;
padding: 0 4px 0 4px;
}
.scroll-container {
flex: 1;
overflow: hidden;
padding: 5px 0;
white-space: nowrap;
position: relative;
.tab {
position: relative;
float: left;
list-style: none;
overflow: visible;
white-space: nowrap;
transition: transform 0.5s ease-in-out;
.scroll-item {
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
&:nth-child(1) {
margin-left: 5px;
}
}
}
}
.right-button {
display: flex;
font-size: 16px;
li {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 38px;
border-right: 1px solid #ccc;
cursor: pointer;
}
}
/* 右键菜单 */
.contextmenu {
margin: 0;
background: #fff;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
color: #000000d9;
font-weight: normal;
font-size: 13px;
white-space: nowrap;
outline: 0;
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
li {
width: 100%;
margin: 0;
padding: 7px 12px;
cursor: pointer;
display: flex;
align-items: center;
&:hover {
background: #eee;
}
svg {
display: block;
margin-right: 0.5em;
}
}
}
}
.el-dropdown-menu {
padding: 0;
li {
width: 100%;
margin: 0;
cursor: pointer;
display: flex;
align-items: center;
svg {
display: block;
margin-right: 0.5em;
}
}
}
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
}
:deep(.el-dropdown-menu__item) i {
margin-right: 10px;
}
.el-dropdown-menu__item--divided::before {
margin: 0;
}
.el-dropdown-menu__item.is-disabled {
cursor: not-allowed;
}
.scroll-item.is-active {
background-color: #eaf4fe;
position: relative;
color: #fff;
&:not(:first-child) {
padding-right: 18px;
}
.el-icon-close {
transform: translate(0, -50%);
}
a {
color: #1890ff;
}
}
.ri-arrow-left-s-line {
width: 40px;
height: 38px;
line-height: 38px;
text-align: center;
font-size: 20px;
color: #00000073;
box-shadow: 5px 0 5px -6px #ccc;
&:hover {
cursor: w-resize;
}
}
.ri-arrow-right-s-line {
width: 40px;
height: 38px;
line-height: 38px;
text-align: center;
font-size: 20px;
border-right: 1px solid #ccc;
color: #00000073;
box-shadow: -5px 0 5px -6px #ccc;
&:hover {
cursor: e-resize;
}
}
/* 卡片模式下鼠标移入显示蓝色边框 */
.card-in {
color: #1890ff;
a {
color: #1890ff;
}
}
/* 卡片模式下鼠标移出隐藏蓝色边框 */
.card-out {
border: none;
color: #666;
a {
color: #666;
}
}
/* 灵动模式 */
.schedule-active {
width: 100%;
height: 2px;
position: absolute;
left: 0;
bottom: 0;
background: #1890ff;
}
/* 灵动模式下鼠标移入显示蓝色进度条 */
.schedule-in {
width: 100%;
height: 2px;
position: absolute;
left: 0;
bottom: 0;
background: #1890ff;
animation: scheduleInWidth 400ms ease-in;
}
/* 灵动模式下鼠标移出隐藏蓝色进度条 */
.schedule-out {
width: 0;
height: 2px;
position: absolute;
left: 0;
bottom: 0;
background: #1890ff;
animation: scheduleOutWidth 400ms ease-in;
}
/* 刷新按钮动画效果 */
.refresh-button {
-webkit-animation: rotate 600ms linear infinite;
-moz-animation: rotate 600ms linear infinite;
-o-animation: rotate 600ms linear infinite;
animation: rotate 600ms linear infinite;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,25 @@
<script lang="ts">
import { routerArrays } from "./types";
export default {
computed: {
layout() {
if (!this.$storage.layout) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.$storage.layout = { layout: "vertical-dark" };
}
if (
!this.$storage.routesInStorage ||
this.$storage.routesInStorage.length === 0
) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.$storage.routesInStorage = routerArrays;
}
if (!this.$storage.locale) {
// eslint-disable-next-line
this.$storage.locale = { locale: "zh" };
useI18n().locale.value = "zh";
}
return this.$storage?.layout.layout;
}
}
};
</script>
<script setup lang="ts">
import {
ref,
unref,
h,
reactive,
computed,
onMounted,
watchEffect,
useCssModule,
onBeforeMount,
defineComponent,
getCurrentInstance
} from "vue";
import { setType } from "./types";
import options from "/@/settings";
import { useI18n } from "vue-i18n";
import { routerArrays } from "./types";
import { emitter } from "/@/utils/mitt";
import { toggleClass } from "/@/utils/operate";
import { useEventListener } from "@vueuse/core";
import { storageLocal } from "/@/utils/storage";
import { useAppStoreHook } from "/@/store/modules/app";
import fullScreen from "/@/assets/svg/full_screen.svg";
import exitScreen from "/@/assets/svg/exit_screen.svg";
import { deviceDetection } from "/@/utils/deviceDetection";
import { useMultiTagsStore } from "/@/store/modules/multiTags";
import { useSettingStoreHook } from "/@/store/modules/settings";
import backTop from "/@/assets/svg/back_top.svg?component";
import fullScreen from "/@/assets/svg/full_screen.svg?component";
import exitScreen from "/@/assets/svg/exit_screen.svg?component";
import navbar from "./components/navbar.vue";
import tag from "./components/tag/index.vue";
import appMain from "./components/appMain.vue";
@@ -56,13 +27,51 @@ import setting from "./components/setting/index.vue";
import Vertical from "./components/sidebar/vertical.vue";
import Horizontal from "./components/sidebar/horizontal.vue";
const isMobile = deviceDetection();
const pureSetting = useSettingStoreHook();
const { hiddenMainContainer } = useCssModule();
const instance = getCurrentInstance().appContext.app.config.globalProperties;
const instance =
getCurrentInstance().appContext.app.config.globalProperties.$storage;
let containerHiddenSideBar = ref(options.hiddenSideBar);
// 清空缓存后从serverConfig.json读取默认配置并赋值到storage中
const layout = computed(() => {
// 路由
if (
useMultiTagsStore().multiTagsCache &&
(!instance.$storage.tags || instance.$storage.tags.length === 0)
) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
instance.$storage.tags = routerArrays;
}
// 国际化
if (!instance.$storage.locale) {
// eslint-disable-next-line
instance.$storage.locale = { locale: instance.$config?.Locale ?? "zh" };
useI18n().locale.value = instance.$config?.Locale ?? "zh";
}
// 导航
if (!instance.$storage.layout) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
instance.$storage.layout = {
layout: instance.$config?.Layout ?? "vertical",
theme: instance.$config?.Theme ?? "default",
darkMode: instance.$config?.DarkMode ?? false,
sidebarStatus: instance.$config?.SidebarStatus ?? true,
epThemeColor: instance.$config?.EpThemeColor ?? "#409EFF"
};
}
// 灰色模式、色弱模式、隐藏标签页
if (!instance.$storage.configure) {
// eslint-disable-next-line
instance.$storage.configure = {
grey: instance.$config?.Grey ?? false,
weak: instance.$config?.Weak ?? false,
hideTabs: instance.$config?.HideTabs ?? false,
showLogo: instance.$config?.ShowLogo ?? true,
showModel: instance.$config?.ShowModel ?? "smart",
multiTagsCache: instance.$config?.MultiTagsCache ?? false
};
}
return instance.$storage?.layout.layout;
});
const set: setType = reactive({
sidebar: computed(() => {
@@ -84,81 +93,111 @@ const set: setType = reactive({
withoutAnimation: set.sidebar.withoutAnimation,
mobile: set.device === "mobile"
};
}),
hideTabs: computed(() => {
return instance.$storage?.configure.hideTabs;
})
});
const handleClickOutside = (params: boolean) => {
useAppStoreHook().closeSideBar({ withoutAnimation: params });
};
function setTheme(layoutModel: string) {
let { layout } = storageLocal.getItem("responsive-layout");
let theme = layout.match(/-(.*)/)[1];
window.document.body.setAttribute("data-layout", layoutModel);
window.document.body.setAttribute("data-theme", theme);
instance.layout = { layout: `${layoutModel}-${theme}` };
window.document.body.setAttribute("layout", layoutModel);
instance.$storage.layout = {
layout: `${layoutModel}`,
theme: instance.$storage.layout?.theme,
darkMode: instance.$storage.layout?.darkMode,
sidebarStatus: instance.$storage.layout?.sidebarStatus,
epThemeColor: instance.$storage.layout?.epThemeColor
};
}
function toggle(device: string, bool: boolean) {
useAppStoreHook().toggleDevice(device);
useAppStoreHook().toggleSideBar(bool, "resize");
}
// 判断是否可自动关闭菜单栏
let isAutoCloseSidebar = true;
// 监听容器
emitter.on("resize", ({ detail }) => {
if (isMobile) return;
let { width } = detail;
width <= 670 ? setTheme("vertical") : setTheme(useAppStoreHook().layout);
});
watchEffect(() => {
if (set.device === "mobile" && !set.sidebar.opened) {
handleClickOutside(false);
/** width app-wrapper类容器宽度
* 0 < width <= 760 隐藏侧边栏
* 760 < width <= 990 折叠侧边栏
* width > 990 展开侧边栏
*/
if (width > 0 && width <= 760) {
toggle("mobile", false);
isAutoCloseSidebar = true;
} else if (width > 760 && width <= 990) {
if (isAutoCloseSidebar) {
toggle("desktop", false);
isAutoCloseSidebar = false;
}
} else if (width > 990) {
if (!set.sidebar.isClickHamburger) {
toggle("desktop", true);
isAutoCloseSidebar = true;
}
}
});
const $_isMobile = () => {
const rect = document.body.getBoundingClientRect();
return rect.width - 1 < 992;
};
const $_resizeHandler = () => {
if (!document.hidden) {
const isMobile = $_isMobile();
useAppStoreHook().toggleDevice(isMobile ? "mobile" : "desktop");
if (isMobile) {
handleClickOutside(true);
}
}
};
function onFullScreen() {
if (unref(containerHiddenSideBar)) {
containerHiddenSideBar.value = false;
toggleClass(
false,
hiddenMainContainer,
document.querySelector(".main-container")
);
} else {
containerHiddenSideBar.value = true;
toggleClass(
true,
hiddenMainContainer,
document.querySelector(".main-container")
);
}
}
onMounted(() => {
const isMobile = $_isMobile();
if (isMobile) {
useAppStoreHook().toggleDevice("mobile");
handleClickOutside(true);
toggle("mobile", false);
}
toggleClass(
unref(containerHiddenSideBar),
hiddenMainContainer,
document.querySelector(".main-container")
);
});
onBeforeMount(() => {
useEventListener("resize", $_resizeHandler);
function onFullScreen() {
pureSetting.hiddenSideBar
? pureSetting.changeSetting({ key: "hiddenSideBar", value: false })
: pureSetting.changeSetting({ key: "hiddenSideBar", value: true });
}
const layoutHeader = defineComponent({
render() {
return h(
"div",
{
class: { "fixed-header": set.fixedHeader },
style: [
set.hideTabs && layout.value.includes("horizontal")
? "box-shadow: 0 1px 4px rgb(0 21 41 / 8%);"
: ""
]
},
{
default: () => [
!pureSetting.hiddenSideBar && layout.value.includes("vertical")
? h(navbar)
: h("div"),
!pureSetting.hiddenSideBar && layout.value.includes("horizontal")
? h(Horizontal)
: h("div"),
h(
tag,
{},
{
default: () => [
h(
"span",
{ onClick: onFullScreen },
{
default: () => [
!pureSetting.hiddenSideBar ? h(fullScreen) : h(exitScreen)
]
}
)
]
}
)
]
}
);
}
});
</script>
@@ -170,41 +209,39 @@ onBeforeMount(() => {
set.sidebar.opened &&
layout.includes('vertical')
"
class="drawer-bg"
@click="handleClickOutside(false)"
class="app-mask"
@click="useAppStoreHook().toggleSideBar()"
/>
<Vertical v-show="!containerHiddenSideBar && layout.includes('vertical')" />
<div class="main-container">
<div :class="{ 'fixed-header': set.fixedHeader }">
<!-- 顶部导航栏 -->
<navbar
v-show="!containerHiddenSideBar && layout.includes('vertical')"
<Vertical
v-show="!pureSetting.hiddenSideBar && layout.includes('vertical')"
/>
<!-- tabs标签页 -->
<Horizontal
v-show="!containerHiddenSideBar && layout.includes('horizontal')"
/>
<tag>
<span @click="onFullScreen">
<fullScreen v-if="!containerHiddenSideBar" />
<exitScreen v-else />
</span>
</tag>
</div>
<div
:class="[
'main-container',
pureSetting.hiddenSideBar ? 'main-hidden' : ''
]"
>
<div v-if="set.fixedHeader">
<layout-header />
<!-- 主体内容 -->
<app-main />
<app-main :fixed-header="set.fixedHeader" />
</div>
<el-scrollbar v-else>
<el-backtop
title="回到顶部"
target=".main-container .el-scrollbar__wrap"
><backTop />
</el-backtop>
<layout-header />
<!-- 主体内容 -->
<app-main :fixed-header="set.fixedHeader" />
</el-scrollbar>
</div>
<!-- 系统设置 -->
<setting />
</div>
</template>
<style scoped module>
.hiddenMainContainer {
margin-left: 0 !important;
}
</style>
<style lang="scss" scoped>
@mixin clearfix {
&::after {
@@ -227,7 +264,11 @@ onBeforeMount(() => {
}
}
.drawer-bg {
.main-hidden {
margin-left: 0 !important;
}
.app-mask {
background: #000;
opacity: 0.3;
width: 100%;
@@ -237,19 +278,6 @@ onBeforeMount(() => {
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - 210px);
transition: width 0.28s;
}
.mobile .fixed-header {
width: 100%;
}
.re-screen {
margin-top: 12px;
}

View File

@@ -0,0 +1,15 @@
<template>
<router-view>
<template #default="{ Component, route }">
<transition appear name="fade-transform" mode="out-in">
<component :is="Component" :key="route.fullPath" />
</transition>
</template>
</router-view>
</template>
<script lang="ts">
export default {
name: "layoutParentView"
};
</script>

View File

@@ -0,0 +1,11 @@
/* 酸橙绿 */
$subMenuActiveText: #fff;
$menuBg: #0b1e15;
$menuHover: #60ac80;
$subMenuBg: #000;
$subMenuActiveBg: #60ac80;
$navTextColor: #7a80b4;
$menuText: #7a80b4;
$sidebarLogo: #112f21;
$menuTitleHover: #fff;
$menuActiveBefore: #60ac80;

View File

@@ -0,0 +1,29 @@
/**
* 道奇蓝(默认)
* 此scss变量文件作为multipleScopeVars去编译时会自动移除!default以达到变量提升
* 同时此scss变量文件作为默认主题变量文件被其他.scss通过 @import 时,必需 !default
*/
/* 菜单选中后字体样式 */
$subMenuActiveText: #fff !default;
/* 菜单背景 */
$menuBg: #001529 !default;
/* 鼠标覆盖到菜单时的背景 */
$menuHover: #4091f7 !default;
/* 子菜单背景 */
$subMenuBg: #0f0303 !default;
/* 有无子集的激活菜单背景 */
$subMenuActiveBg: #4091f7 !default;
$navTextColor: #fff !default;
$menuText: rgba(254, 254, 254, 0.65) !default;
/* logo背景颜色 */
$sidebarLogo: #002140 !default;
/* 鼠标覆盖到菜单时的字体颜色 */
$menuTitleHover: #fff !default;
$menuActiveBefore: #4091f7 !default;

View File

@@ -0,0 +1,11 @@
/* 猩红色 */
$subMenuActiveText: #fff;
$menuBg: #2a0608;
$menuHover: #e13c39;
$subMenuBg: #000;
$subMenuActiveBg: #e13c39;
$navTextColor: red;
$menuText: rgba(254, 254, 254, 0.651);
$sidebarLogo: #42090c;
$menuTitleHover: #fff;
$menuActiveBefore: #e13c39;

View File

@@ -0,0 +1,80 @@
/* 动态改变element-plus主题色 */
import rgbHex from "rgb-hex";
import color from "css-color-function";
import { TinyColor } from "@ctrl/tinycolor";
import epCss from "element-plus/dist/index.css";
// 色值表
const formula = {
"shade-1": "color(primary shade(10%))",
"light-1": "color(primary tint(10%))",
"light-2": "color(primary tint(20%))",
"light-3": "color(primary tint(30%))",
"light-4": "color(primary tint(40%))",
"light-5": "color(primary tint(50%))",
"light-6": "color(primary tint(60%))",
"light-7": "color(primary tint(70%))",
"light-8": "color(primary tint(80%))",
"light-9": "color(primary tint(90%))"
};
// 把生成的样式表写入到style中
export const writeNewStyle = (newStyle: string): void => {
const style = window.document.createElement("style");
style.innerText = newStyle;
window.document.head.appendChild(style);
};
// 根据主题色,生成最新的样式表
export const createNewStyle = (primaryStyle: string): string => {
// 根据主色生成色值表
const colors = createColors(primaryStyle);
// 在当前ep的默认样式表中标记需要替换的色值
let cssText = getStyleTemplate(epCss);
// 遍历生成的色值表,在 默认样式表 进行全局替换
Object.keys(colors).forEach(key => {
cssText = cssText.replace(
new RegExp("(:|\\s+)" + key, "g"),
"$1" + colors[key]
);
});
return cssText;
};
export const createColors = (primary: string) => {
if (!primary) return;
const colors = {
primary
};
Object.keys(formula).forEach(key => {
const value = formula[key].replace(/primary/, primary);
colors[key] = "#" + rgbHex(color.convert(value));
});
return colors;
};
const getStyleTemplate = (data: string): string => {
const colorMap = {
"#3a8ee6": "shade-1",
"#409eff": "primary",
"#53a8ff": "light-1",
"#66b1ff": "light-2",
"#79bbff": "light-3",
"#8cc5ff": "light-4",
"#a0cfff": "light-5",
"#b3d8ff": "light-6",
"#c6e2ff": "light-7",
"#d9ecff": "light-8",
"#ecf5ff": "light-9"
};
Object.keys(colorMap).forEach(key => {
const value = colorMap[key];
data = data.replace(new RegExp(key, "ig"), value);
});
return data;
};
// 自动计算hover和active颜色 https://element-plus.gitee.io/zh-CN/component/button.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%9C%E8%89%B2-%E6%B5%8B%E8%AF%95%E7%89%88
export const shadeBgColor = (color: string): string => {
return new TinyColor(color).shade(10).toString();
};

View File

@@ -0,0 +1,11 @@
/* 亮白色 */
$subMenuActiveText: #409eff;
$menuBg: #fff;
$menuHover: #e0ebf6;
$subMenuBg: #fff;
$subMenuActiveBg: #e0ebf6;
$navTextColor: #7a80b4;
$menuText: #7a80b4;
$sidebarLogo: #fff;
$menuTitleHover: #000;
$menuActiveBefore: #4091f7;

View File

@@ -0,0 +1,11 @@
/* 绿宝石 */
$subMenuActiveText: #fff;
$menuBg: #032121;
$menuHover: #59bfc1;
$subMenuBg: #000;
$subMenuActiveBg: #59bfc1;
$navTextColor: #7a80b4;
$menuText: #7a80b4;
$sidebarLogo: #053434;
$menuTitleHover: #fff;
$menuActiveBefore: #59bfc1;

View File

@@ -0,0 +1,11 @@
/* 深粉色 */
$subMenuActiveText: #fff;
$menuBg: #28081a;
$menuHover: #d84493;
$subMenuBg: #000;
$subMenuActiveBg: #d84493;
$navTextColor: #7a80b4;
$menuText: #7a80b4;
$sidebarLogo: #3f0d29;
$menuTitleHover: #fff;
$menuActiveBefore: #d84493;

View File

@@ -0,0 +1,11 @@
/* 深紫罗兰色 */
$subMenuActiveText: #fff;
$menuBg: #130824;
$menuHover: #693ac9;
$subMenuBg: #000;
$subMenuActiveBg: #693ac9;
$navTextColor: #7a80b4;
$menuText: #7a80b4;
$sidebarLogo: #1f0c38;
$menuTitleHover: #fff;
$menuActiveBefore: #693ac9;

View File

@@ -0,0 +1,11 @@
/* 橙红色 */
$subMenuActiveText: #fff;
$menuBg: #2b0e05;
$menuHover: #e85f33;
$subMenuBg: #0f0603;
$subMenuActiveBg: #e85f33;
$navTextColor: #fff;
$menuText: rgba(254, 254, 254, 0.65);
$sidebarLogo: #441708;
$menuTitleHover: #fff;
$menuActiveBefore: #e85f33;

View File

@@ -0,0 +1,11 @@
/* 金色 */
$subMenuActiveText: #d25f00;
$menuBg: #2b2503;
$menuHover: #f6da4d;
$subMenuBg: #0f0603;
$subMenuActiveBg: #f6da4d;
$navTextColor: #fff;
$menuText: rgba(254, 254, 254, 0.65);
$sidebarLogo: #443b05;
$menuTitleHover: #fff;
$menuActiveBefore: #f6da4d;

View File

@@ -1,36 +1,50 @@
import { Component } from "vue";
export const routerArrays: Array<RouteConfigs> = [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "menus.hshome",
i18n: true,
icon: "home-filled",
showLink: true
}
}
];
export type RouteConfigs = {
path?: string;
parentPath?: string;
query?: object;
meta?: {
title?: string;
i18n?: boolean;
icon?: string;
showLink?: boolean;
savedPosition?: boolean;
authority?: Array<string>;
};
children?: RouteConfigs[];
name?: string;
};
export type relativeStorageType = {
routesInStorage: Array<RouteConfigs>;
export type multiTagsType = {
tags: Array<RouteConfigs>;
};
export type tagsViewsType = {
icon: string;
icon: Component;
text: string;
divided: {
valueOf: () => boolean;
};
disabled: {
valueOf: () => boolean;
};
show: {
valueOf: () => boolean;
};
divided: boolean;
disabled: boolean;
show: boolean;
};
export interface setType {
sidebar: {
opened: boolean;
withoutAnimation: boolean;
isClickHamburger: boolean;
};
device: string;
fixedHeader: boolean;
@@ -40,16 +54,33 @@ export interface setType {
withoutAnimation: boolean;
mobile: boolean;
};
hideTabs: boolean;
}
export const routerArrays: Array<RouteConfigs> = [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "message.hshome",
icon: "el-icon-s-home",
showLink: true
export type childrenType = {
path?: string;
noShowingChildren?: boolean;
children?: childrenType[];
value: unknown;
meta?: {
icon?: string;
title?: string;
i18n?: boolean;
extraIcon?: {
svg?: boolean;
name?: string;
};
};
showTooltip?: boolean;
};
export type themeColorsType = {
rgb: string;
themeColor: string;
};
export interface scrollbarDomType extends HTMLElement {
wrap?: {
offsetWidth: number;
};
}
}
];

Some files were not shown because too many files have changed in this diff Show More