feat: add horizontal nav (#45)

* feat: add horizontal nav

* workflow: update linter.yml

* fix: update

* fix: update

* fix: update

* Rename Link.vue to link.vue

* Rename SidebarItem.vue to sidebarItem.vue

* Rename Logo.vue to logo.vue

* Rename AppMain.vue to appMain.vue

* Rename Navbar.vue to navbar.vue

* fix: update

* fix: update

* fix: update

* workflow: update linter.yml

* fix: update

* chore: update

* workflow: update

* fix: update

* fix: update

* fix: update

* perf: 外链功能实现方式改变

* style: update nav style

* perf: 优化国际化

* fix: update

* fix: update
This commit is contained in:
啝裳 2021-09-29 01:55:56 +08:00 committed by GitHub
parent e86757e30e
commit fd8de45bff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1314 additions and 682 deletions

View File

@ -29,7 +29,7 @@
"dayjs": "^1.10.6",
"dotenv": "^8.2.0",
"echarts": "^5.1.2",
"element-plus": "^1.1.0-beta.12",
"element-plus": "^1.1.0-beta.16",
"element-resize-detector": "^1.2.3",
"font-awesome": "^4.7.0",
"lodash-es": "^4.17.21",
@ -40,10 +40,10 @@
"path-to-regexp": "^6.2.0",
"pinia": "^2.0.0-rc.6",
"resize-observer-polyfill": "^1.5.1",
"responsive-storage": "^1.0.9",
"responsive-storage": "^1.0.10",
"sortablejs": "1.13.0",
"v-contextmenu": "^3.0.0",
"vue": "3.2.11",
"vue": "^3.2.19",
"vue-i18n": "^9.2.0-beta.3",
"vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.11",
@ -66,7 +66,7 @@
"@typescript-eslint/parser": "^4.31.0",
"@vitejs/plugin-vue": "^1.6.0",
"@vitejs/plugin-vue-jsx": "^1.1.7",
"@vue/compiler-sfc": "3.2.11",
"@vue/compiler-sfc": "^3.2.19",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.4",
@ -91,7 +91,7 @@
"stylelint-order": "^4.1.0",
"typescript": "^4.4.2",
"unplugin-element-plus": "^0.0.1",
"vite": "^2.5.7",
"vite": "^2.5.10",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-style-import": "^1.2.1",
"vite-svg-loader": "^2.2.0",

View File

@ -1,14 +1,8 @@
@font-face {
font-family: "iconfont";
src: url("iconfont.eot?t=1619360751585"); /* IE9 */
src: url("iconfont.eot?t=1619360751585#iefix") format("embedded-opentype"),
/* IE6-IE8 */
url("data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARMAAsAAAAACbwAAAP9AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDQAqGEIRiATYCJAMYCw4ABCAFhG0Hfhs2CMgOJS2d2ECiAwlgBN+vlf0+zE5mg6wAXeJZIjpmuSejwkZFpjyxij57rCLU/p9b+c8NWt6VZsJElIM/LOtvdta6uELEuI1RpSiTq877eC1W5aXc/38/V+f5b2lrettv68Xkvj8zA0+cJTJJQyKSxKSSKBWPlNixsM5M+mTE89a4m0BnrRop+8ZmViBbIQ4KxE1DVyC7cisjwtDamp4zi3ihatOz9BfAc//xMQNNkU1SM3Hk4cujGgyMi5MjaYPhCecti35/94OKjG1AIR72hm9Li+Vt0nSLYro9YHl8K0nj4vjWyaffTiaTMMEW0xUVO53ZUn8t//CqJBMNgbPB31+pjC/TNMH4FprC+FaayuRTmsTkiFuGvdnj1KXAOIiV4K+OJFWaiyg0Ta9XlNpZFnNMMU87Fu6JpEd7eVb2opxYflpfv3a6POca5EdfirMurHNGCE8kd+I1Aga56YZpli8QTd2pkM13zTZ3LWH/yp07FYsroO6K+8wWApapQmIJS/sos3zFfAfHn7h7YNkyBXLpDpx4e1dclrGWJZBjHTZlH7GTZu5+x+JBl122Uu7Dnneswsb7GzdAYdAeAQNsuPCgpUXf26No0Vtakrt6EdLv73FsGfVc+stJczdJknB3izcB36+MxPaRNRuxkhDbHm3uWlgXdtH0nPRZONzVMmLbhDTJuGaPNCfq0vWC2f87RVXNo+ZKmG1whgeqbK2MNlctwFnlMtis7d3MsMNhGBuNtnQt7IjdW4k7NbE3+trR+Ch7WcWwpjkOHUkI4nbFjG3xcHdz1HEIabtS38eCpsmEOO2WrO1tMUMd5tprJzKSyJyclDN2xNNTI/96bFx+DY/OZ1M/Agzf5q9pwwDDd2mR2fk3+hv//gtHjxX1/Gv7BYy+e/TXTxieKPKA/wJB1v9p9MQFZWkUnqbM59f7CDSOyHhvg3RyEX+W+EJf98UsIXcTWksyJD1rIGutYxf+Nqj6dmQarevsprPVOM7vW4RJE2UWtjjLIMz3BpK5PkA23x678L9AtdRvaMyPNOicjLIr9m0II3eYocJRk1bjkqEG/FT5eG7oXUI97FVYafRSgixk5KTGuoZmbRz9yPZxTCiiN3FOJcoCPmmM3Q+93oAUZAE3qrzOxXmwq76e9r1SnRrwQa69GKTgkEayKk5iUAX4Ubs0l9t6/yVIF+alYCPzLlQJxIQYG5c0qtNAYI+jnzTvuWwfEqFrwnF0th/FBPhIxhBEXlkOkAT7d3NDKq6Oa4tiUJd6Po5Sse74jO9VXgcdcdUmUuQoUaOJnt4Dl+JXXeEyPxSI1voUw1/7MCwcm0NW4TI0Df09vyvCmMFradjrDakM0Z+bXAAAAAA=")
format("woff2"),
url("iconfont.woff?t=1619360751585") format("woff"),
url("iconfont.ttf?t=1619360751585") format("truetype"),
/* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url("iconfont.svg?t=1619360751585#iconfont") format("svg"); /* iOS 4.1- */
font-family: "iconfont"; /* Project id 2208059 */
src: url("iconfont.woff2?t=1632557807050") format("woff2"),
url("iconfont.woff?t=1632557807050") format("woff"),
url("iconfont.ttf?t=1632557807050") format("truetype");
}
.iconfont {
@ -19,6 +13,10 @@
-moz-osx-font-smoothing: grayscale;
}
.team-iconinternationality::before {
content: "\e67a";
}
.team-iconshanchu::before {
content: "\e617";
}

Binary file not shown.

View File

@ -4,13 +4,15 @@
l,
n,
o,
i,
a =
'<svg><symbol id="team-iconshanchu" viewBox="0 0 1024 1024"><path d="M200.0896 166.675692l657.250462 657.218954-33.429662 33.429662-657.250462-657.250462z" ></path><path d="M166.675692 823.9104l657.218954-657.250462 33.429662 33.429662-657.250462 657.250462z" ></path></symbol><symbol id="team-iconshow-main-container" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m409.6 921.6H102.4v-307.2h102.4v204.8h204.8zM409.6 204.8H204.8v204.8H102.4V102.4h307.2z m512 614.4v102.4h-307.2v-102.4h204.8v-204.8h102.4z m0-614.4v204.8h-102.4V204.8h-204.8V102.4h307.2z" ></path></symbol><symbol id="team-iconhidden-main-container" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m409.6 716.8v204.8H307.2v-204.8H102.4v-102.4h307.2z m0-409.6v102.4H102.4V307.2h204.8V102.4h102.4z m512 409.6h-204.8v204.8h-102.4v-307.2h307.2z m0-307.2h-307.2V102.4h102.4v204.8h204.8z" ></path></symbol><symbol id="team-iconexit-fullscreen" viewBox="0 0 1024 1024"><path d="M366.2 181.8c-1-8-10.8-11.4-16.5-5.7l-53.1 53.1L134.2 67c-3.8-3.8-10-3.8-13.7 0L69 118.3c-3.8 3.8-3.8 10 0 13.7l162.4 162.4-53.3 53.3c-5.7 5.7-2.3 15.5 5.7 16.5l194.6 23c6.2 0.7 11.5-4.5 10.8-10.8l-23-194.6z m12.3 453.3l-194.7 23c-8 1-11.4 10.8-5.7 16.5l53.3 53.3L69 890.1c-3.8 3.8-3.8 10 0 13.7l51.5 51.4c3.8 3.8 10 3.8 13.7 0l162.4-162.3 53.1 53.1c5.7 5.7 15.5 2.3 16.5-5.7l23-194.4c0.7-6.3-4.5-11.5-10.7-10.8z m269.4-248l194.7-23c8-1 11.4-10.8 5.7-16.5L795 294.4l162.4-162.3c3.8-3.8 3.8-10 0-13.7L905.9 67c-3.8-3.8-10-3.8-13.7 0L729.7 229.2l-53.1-53.1c-5.7-5.7-15.6-2.3-16.5 5.7l-23 194.5c-0.6 6.3 4.6 11.5 10.8 10.8zM795 727.8l53.3-53.3c5.7-5.7 2.3-15.5-5.7-16.5L648 635c-6.2-0.7-11.5 4.5-10.8 10.8l23 194.6c1 8 10.8 11.4 16.5 5.7l53.1-53.1 162.4 162.3c3.8 3.8 10 3.8 13.7 0l51.5-51.4c3.8-3.8 3.8-10 0-13.7L795 727.8z m0 0" fill="#515151" ></path></symbol><symbol id="team-iconfullscreen" viewBox="0 0 1024 1024"><path d="M229.8 163l55.7-55.7c6-6 2.4-16.2-6-17.2l-203.2-24c-6.5-0.8-12 4.7-11.3 11.3l24 203.2c1 8.4 11.3 11.9 17.2 6l55.4-55.4 169.6 169.4c3.9 3.9 10.4 3.9 14.3 0l53.8-53.6c3.9-3.9 3.9-10.4 0-14.3L229.8 163z m447.3 237.6c3.9 3.9 10.4 3.9 14.3 0L861 231.1l55.4 55.4c6 6 16.2 2.4 17.2-6l24-203c0.8-6.5-4.7-12-11.3-11.3l-203.2 24c-8.4 1-11.9 11.3-6 17.2l55.7 55.7-169.5 169.4c-3.9 3.9-3.9 10.4 0 14.3l53.8 53.8z m256.6 343.9c-1-8.4-11.3-11.9-17.2-6L861 794 691.4 624.5c-3.9-3.9-10.4-3.9-14.3 0l-53.8 53.6c-3.9 3.9-3.9 10.4 0 14.3L792.9 862l-55.7 55.7c-6 6-2.4 16.2 6 17.2l203.2 24c6.5 0.8 12-4.7 11.3-11.3l-24-203.1z m-588.1-120c-3.9-3.9-10.4-3.9-14.3 0L161.7 794l-55.4-55.4c-6-6-16.2-2.4-17.2 6l-24 203c-0.8 6.5 4.7 12.1 11.3 11.3l203.2-24c8.4-1 11.9-11.3 6-17.2l-55.7-55.5 169.6-169.4c3.9-3.9 3.9-10.4 0-14.3l-53.9-54z m0 0" fill="#515151" ></path></symbol></svg>',
d = (d = document.getElementsByTagName("script"))[
d.length - 1
].getAttribute("data-injectcss");
if (d && !e.__iconfont__svg__cssinject__) {
i =
'<svg><symbol id="team-iconinternationality" viewBox="0 0 1024 1024"><path d="M219.4 363.4c11.8 35 31.4 65.4 58.7 92.2 23.2-25.2 40.7-56.2 52-92.2H219.4z m722.2-207.1H508.9L484.2 23.9H82.4C38.1 23.9 2 60 2 104.3v683.1c0 44.3 36.1 80.4 80.4 80.4h366.3l-29.4 132.4h522.4c44.3 0 80.4-36.1 80.4-80.4V236.7c-0.1-44.4-36.2-80.4-80.5-80.4zM396.1 562.2c-47.4-17.5-86.5-39.7-118-65.4-33 29.4-74.2 51-122.1 64.4l-16.5-27.3c46.9-12.4 86-30.9 116.9-57.2-31.9-32.5-54.1-70.1-66.5-112.8h-44.8V333H262c-7.2-13.4-16.5-26.3-27.3-38.6l30.9-11.3c10.8 13.9 20.6 30.4 29.4 49.5h111.8v30.9H362c-14.4 44.3-35 81.4-62.3 111.3 30.4 24.2 68.5 44.3 113.3 60.8l-16.9 26.6z m585.7 357c0 22.2-18 40.2-40.2 40.2H469.8l20.1-92.2h150.9l-86-479.6-0.5 2.6-3.6-19.1 1 0.5-31.4-175.2h421.9c22.2 0 40.2 18 40.2 40.2v682.6h-0.6zM655.2 540.1H766v-29.4H655.2V452h118v-29.4H620.7v211.2h157.1v-29.4H655.2v-64.3z m231.3-63.4c-9.3 0-17.5 1.5-25.2 5.7-7.2 3.6-14.4 9.3-20.1 16.5v-18h-33.5v153h33.5v-92.2c1-12.4 5.2-21.6 12.4-28.3 6.2-5.7 13.4-8.8 21.6-8.8 23.2 0 34.5 12.4 34.5 37.6v91.2h33.5V539c1-41.7-18.6-62.3-56.7-62.3z" ></path></symbol><symbol id="team-iconshanchu" viewBox="0 0 1024 1024"><path d="M200.0896 166.675692l657.250462 657.218954-33.429662 33.429662-657.250462-657.250462z" ></path><path d="M166.675692 823.9104l657.218954-657.250462 33.429662 33.429662-657.250462 657.250462z" ></path></symbol><symbol id="team-iconshow-main-container" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m409.6 921.6H102.4v-307.2h102.4v204.8h204.8zM409.6 204.8H204.8v204.8H102.4V102.4h307.2z m512 614.4v102.4h-307.2v-102.4h204.8v-204.8h102.4z m0-614.4v204.8h-102.4V204.8h-204.8V102.4h307.2z" ></path></symbol><symbol id="team-iconhidden-main-container" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m409.6 716.8v204.8H307.2v-204.8H102.4v-102.4h307.2z m0-409.6v102.4H102.4V307.2h204.8V102.4h102.4z m512 409.6h-204.8v204.8h-102.4v-307.2h307.2z m0-307.2h-307.2V102.4h102.4v204.8h204.8z" ></path></symbol><symbol id="team-iconexit-fullscreen" viewBox="0 0 1024 1024"><path d="M366.2 181.8c-1-8-10.8-11.4-16.5-5.7l-53.1 53.1L134.2 67c-3.8-3.8-10-3.8-13.7 0L69 118.3c-3.8 3.8-3.8 10 0 13.7l162.4 162.4-53.3 53.3c-5.7 5.7-2.3 15.5 5.7 16.5l194.6 23c6.2 0.7 11.5-4.5 10.8-10.8l-23-194.6z m12.3 453.3l-194.7 23c-8 1-11.4 10.8-5.7 16.5l53.3 53.3L69 890.1c-3.8 3.8-3.8 10 0 13.7l51.5 51.4c3.8 3.8 10 3.8 13.7 0l162.4-162.3 53.1 53.1c5.7 5.7 15.5 2.3 16.5-5.7l23-194.4c0.7-6.3-4.5-11.5-10.7-10.8z m269.4-248l194.7-23c8-1 11.4-10.8 5.7-16.5L795 294.4l162.4-162.3c3.8-3.8 3.8-10 0-13.7L905.9 67c-3.8-3.8-10-3.8-13.7 0L729.7 229.2l-53.1-53.1c-5.7-5.7-15.6-2.3-16.5 5.7l-23 194.5c-0.6 6.3 4.6 11.5 10.8 10.8zM795 727.8l53.3-53.3c5.7-5.7 2.3-15.5-5.7-16.5L648 635c-6.2-0.7-11.5 4.5-10.8 10.8l23 194.6c1 8 10.8 11.4 16.5 5.7l53.1-53.1 162.4 162.3c3.8 3.8 10 3.8 13.7 0l51.5-51.4c3.8-3.8 3.8-10 0-13.7L795 727.8z m0 0" fill="#515151" ></path></symbol><symbol id="team-iconfullscreen" viewBox="0 0 1024 1024"><path d="M229.8 163l55.7-55.7c6-6 2.4-16.2-6-17.2l-203.2-24c-6.5-0.8-12 4.7-11.3 11.3l24 203.2c1 8.4 11.3 11.9 17.2 6l55.4-55.4 169.6 169.4c3.9 3.9 10.4 3.9 14.3 0l53.8-53.6c3.9-3.9 3.9-10.4 0-14.3L229.8 163z m447.3 237.6c3.9 3.9 10.4 3.9 14.3 0L861 231.1l55.4 55.4c6 6 16.2 2.4 17.2-6l24-203c0.8-6.5-4.7-12-11.3-11.3l-203.2 24c-8.4 1-11.9 11.3-6 17.2l55.7 55.7-169.5 169.4c-3.9 3.9-3.9 10.4 0 14.3l53.8 53.8z m256.6 343.9c-1-8.4-11.3-11.9-17.2-6L861 794 691.4 624.5c-3.9-3.9-10.4-3.9-14.3 0l-53.8 53.6c-3.9 3.9-3.9 10.4 0 14.3L792.9 862l-55.7 55.7c-6 6-2.4 16.2 6 17.2l203.2 24c6.5 0.8 12-4.7 11.3-11.3l-24-203.1z m-588.1-120c-3.9-3.9-10.4-3.9-14.3 0L161.7 794l-55.4-55.4c-6-6-16.2-2.4-17.2 6l-24 203c-0.8 6.5 4.7 12.1 11.3 11.3l203.2-24c8.4-1 11.9-11.3 6-17.2l-55.7-55.5 169.6-169.4c3.9-3.9 3.9-10.4 0-14.3l-53.9-54z m0 0" fill="#515151" ></path></symbol></svg>',
h = (h = document.getElementsByTagName("script"))[
h.length - 1
].getAttribute("data-injectcss"),
a = function (e, t) {
t.parentNode.insertBefore(e, t);
};
if (h && !e.__iconfont__svg__cssinject__) {
e.__iconfont__svg__cssinject__ = !0;
try {
document.write(
@ -23,20 +25,26 @@
function m() {
o || ((o = !0), l());
}
function d() {
try {
n.documentElement.doScroll("left");
} catch (e) {
return void setTimeout(d, 50);
}
m();
}
(t = function () {
var e, t, c, l;
((l = document.createElement("div")).innerHTML = a),
(a = null),
(c = l.getElementsByTagName("svg")[0]) &&
(c.setAttribute("aria-hidden", "true"),
(c.style.position = "absolute"),
(c.style.width = 0),
(c.style.height = 0),
(c.style.overflow = "hidden"),
(e = c),
(t = document.body).firstChild
? ((l = e), (c = t.firstChild).parentNode.insertBefore(l, c))
: t.appendChild(e));
var e, t;
((t = document.createElement("div")).innerHTML = i),
(i = null),
(e = t.getElementsByTagName("svg")[0]) &&
(e.setAttribute("aria-hidden", "true"),
(e.style.position = "absolute"),
(e.style.width = 0),
(e.style.height = 0),
(e.style.overflow = "hidden"),
(t = e),
(e = document.body).firstChild ? a(t, e.firstChild) : e.appendChild(t));
}),
document.addEventListener
? ~["complete", "loaded", "interactive"].indexOf(document.readyState)
@ -49,14 +57,7 @@
((l = t),
(n = e.document),
(o = !1),
(i = function () {
try {
n.documentElement.doScroll("left");
} catch (e) {
return void setTimeout(i, 50);
}
m();
})(),
d(),
(n.onreadystatechange = function () {
"complete" == n.readyState && ((n.onreadystatechange = null), m());
}));

View File

@ -1,10 +1,17 @@
{
"id": "2208059",
"name": "CURD-TS",
"name": "pure-admin",
"font_family": "iconfont",
"css_prefix_text": "team-icon",
"description": "增删查改xi't",
"description": "pure-admin",
"glyphs": [
{
"icon_id": "18367956",
"name": "中英文2 中文",
"font_class": "internationality",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "6184565",
"name": "删除",

View File

@ -1,41 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="shanchu" unicode="&#58903;" d="M200.0896 729.324308l657.250462-657.218954-33.429662-33.429662-657.250462 657.250462zM166.675692 72.0896l657.218954 657.250462 33.429662-33.429662-657.250462-657.250462z" horiz-adv-x="1024" />
<glyph glyph-name="show-main-container" unicode="&#59512;" d="M0 896v-1024h1024V896z m409.6-921.6H102.4v307.2h102.4v-204.8h204.8zM409.6 691.2H204.8v-204.8H102.4V793.6h307.2z m512-614.4v-102.4h-307.2v102.4h204.8v204.8h102.4z m0 614.4v-204.8h-102.4V691.2h-204.8V793.6h307.2z" horiz-adv-x="1024" />
<glyph glyph-name="hidden-main-container" unicode="&#59521;" d="M0 896v-1024h1024V896z m409.6-716.8v-204.8H307.2v204.8H102.4v102.4h307.2z m0 409.6v-102.4H102.4V588.8h204.8V793.6h102.4z m512-409.6h-204.8v-204.8h-102.4v307.2h307.2z m0 307.2h-307.2V793.6h102.4v-204.8h204.8z" horiz-adv-x="1024" />
<glyph glyph-name="exit-fullscreen" unicode="&#58922;" d="M366.2 714.2c-1 8-10.8 11.4-16.5 5.7l-53.1-53.1L134.2 829c-3.8 3.8-10 3.8-13.7 0L69 777.7c-3.8-3.8-3.8-10 0-13.7l162.4-162.4-53.3-53.3c-5.7-5.7-2.3-15.5 5.7-16.5l194.6-23c6.2-0.7 11.5 4.5 10.8 10.8l-23 194.6z m12.3-453.3l-194.7-23c-8-1-11.4-10.8-5.7-16.5l53.3-53.3L69 5.899999999999977c-3.8-3.8-3.8-10 0-13.7l51.5-51.4c3.8-3.8 10-3.8 13.7 0l162.4 162.3 53.1-53.1c5.7-5.7 15.5-2.3 16.5 5.7l23 194.4c0.7 6.3-4.5 11.5-10.7 10.8z m269.4 248l194.7 23c8 1 11.4 10.8 5.7 16.5L795 601.6l162.4 162.3c3.8 3.8 3.8 10 0 13.7L905.9 829c-3.8 3.8-10 3.8-13.7 0L729.7 666.8l-53.1 53.1c-5.7 5.7-15.6 2.3-16.5-5.7l-23-194.5c-0.6-6.3 4.6-11.5 10.8-10.8zM795 168.20000000000005l53.3 53.3c5.7 5.7 2.3 15.5-5.7 16.5L648 261c-6.2 0.7-11.5-4.5-10.8-10.8l23-194.6c1-8 10.8-11.4 16.5-5.7l53.1 53.1 162.4-162.3c3.8-3.8 10-3.8 13.7 0l51.5 51.4c3.8 3.8 3.8 10 0 13.7L795 168.20000000000005z m0 0" horiz-adv-x="1024" />
<glyph glyph-name="fullscreen" unicode="&#58923;" d="M229.8 733l55.7 55.7c6 6 2.4 16.2-6 17.2l-203.2 24c-6.5 0.8-12-4.7-11.3-11.3l24-203.2c1-8.4 11.3-11.9 17.2-6l55.4 55.4 169.6-169.4c3.9-3.9 10.4-3.9 14.3 0l53.8 53.6c3.9 3.9 3.9 10.4 0 14.3L229.8 733z m447.3-237.6c3.9-3.9 10.4-3.9 14.3 0L861 664.9l55.4-55.4c6-6 16.2-2.4 17.2 6l24 203c0.8 6.5-4.7 12-11.3 11.3l-203.2-24c-8.4-1-11.9-11.3-6-17.2l55.7-55.7-169.5-169.4c-3.9-3.9-3.9-10.4 0-14.3l53.8-53.8z m256.6-343.9c-1 8.4-11.3 11.9-17.2 6L861 102 691.4 271.5c-3.9 3.9-10.4 3.9-14.3 0l-53.8-53.6c-3.9-3.9-3.9-10.4 0-14.3L792.9 34l-55.7-55.7c-6-6-2.4-16.2 6-17.2l203.2-24c6.5-0.8 12 4.7 11.3 11.3l-24 203.1z m-588.1 120c-3.9 3.9-10.4 3.9-14.3 0L161.7 102l-55.4 55.4c-6 6-16.2 2.4-17.2-6l-24-203c-0.8-6.5 4.7-12.1 11.3-11.3l203.2 24c8.4 1 11.9 11.3 6 17.2l-55.7 55.5 169.6 169.4c3.9 3.9 3.9 10.4 0 14.3l-53.9 54z m0 0" horiz-adv-x="1024" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconinternationality" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z" fill="currentColor"></path><path d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z" fill="currentColor"></path></svg>

After

Width:  |  Height:  |  Size: 972 B

View File

@ -1,3 +1,5 @@
import { App } from "vue";
import axios from "axios";
let config: object = {};
const setConfig = (cfg?: unknown) => {
@ -22,4 +24,33 @@ const getConfig = (key?: string) => {
return config;
};
// 获取项目动态全局配置
export const getServerConfig = async (app: App): Promise<undefined> => {
app.config.globalProperties.$config = getConfig();
return axios({
baseURL: "",
method: "get",
url:
process.env.NODE_ENV === "production"
? "/manages/serverConfig.json"
: "/serverConfig.json"
})
.then(({ data: config }) => {
let $config = app.config.globalProperties.$config;
// 自动注入项目配置
if (app && $config && typeof config === "object") {
$config = Object.assign($config, config);
app.config.globalProperties.$config = $config;
// 设置全局配置
setConfig($config);
}
// 设置全局baseURL
app.config.globalProperties.$baseUrl = $config.baseURL;
return $config;
})
.catch(() => {
throw "请在public文件夹下添加serverConfig.json配置文件";
});
};
export { getConfig, setConfig };

View File

@ -1,5 +0,0 @@
export { default as Navbar } from "./Navbar.vue";
export { default as Sidebar } from "./sidebar/index.vue";
export { default as AppMain } from "./AppMain.vue";
export { default as setting } from "./setting/index.vue";
export { default as tag } from "./tag/index.vue";

View File

@ -8,98 +8,84 @@
<Breadcrumb class="breadcrumb-container" />
<div class="right-menu">
<div class="vertical-header-right">
<!-- 全屏 -->
<screenfull v-show="!deviceDetection()" />
<!-- 国际化 -->
<div
v-show="!deviceDetection()"
class="inter"
:title="currentLocale ? '中文' : 'English'"
@click="toggleLang"
>
<img :src="currentLocale ? ch : en" />
</div>
<i
class="el-icon-setting hsset"
:title="$t('message.hssystemSet')"
@click="onPanel"
></i>
<el-dropdown trigger="click">
<iconinternationality />
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="{
background: locale === 'zh' ? '#1b2a47' : '',
color: locale === 'zh' ? '#f4f4f5' : '#000'
}"
@click="translationCh"
>简体中文</el-dropdown-item
>
<el-dropdown-item
:style="{
background: locale === 'en' ? '#1b2a47' : '',
color: locale === 'en' ? '#f4f4f5' : '#000'
}"
@click="translationEn"
>English</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 退出登陆 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<img :src="favicon" />
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
/>
<p>{{ usename }}</p>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-menu class="logout">
<el-dropdown-item icon="el-icon-switch-button" @click="logout">{{
$t("message.hsLoginOut")
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<i
class="el-icon-setting"
:title="$t('message.hssystemSet')"
@click="onPanel"
></i>
</div>
</div>
</template>
<script lang="ts">
import {
defineComponent,
onMounted,
unref,
watch,
getCurrentInstance
} from "vue";
import { defineComponent, unref, watch, getCurrentInstance } from "vue";
import Breadcrumb from "/@/components/ReBreadCrumb";
import Hamburger from "/@/components/ReHamBurger";
import screenfull from "../components/screenfull/index.vue";
import { useRouter, useRoute } from "vue-router";
import { useAppStoreHook } from "/@/store/modules/app";
import { storageSession } from "/@/utils/storage";
import ch from "/@/assets/ch.png";
import en from "/@/assets/en.png";
import favicon from "/favicon.ico";
import { emitter } from "/@/utils/mitt";
import { deviceDetection } from "/@/utils/deviceDetection";
import { useI18n } from "vue-i18n";
import iconinternationality from "/@/assets/svg/iconinternationality.svg";
let routerArrays: Array<object> = [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "message.hshome",
icon: "el-icon-s-home",
showLink: true,
savedPosition: false
}
}
];
export default defineComponent({
name: "Navbar",
components: {
Breadcrumb,
Hamburger,
screenfull
screenfull,
iconinternationality
},
// @ts-ignore
computed: {
// eslint-disable-next-line vue/return-in-computed-property
currentLocale() {
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";
}
switch (this.$storage.locale?.locale) {
case "zh":
return true;
@ -114,25 +100,9 @@ export default defineComponent({
const pureApp = useAppStoreHook();
const router = useRouter();
const route = useRoute();
let usename = storageSession.getItem("info")?.username;
const { locale, t } = useI18n();
//
const toggleLang = (): void => {
switch (instance.locale.locale) {
case "zh":
instance.locale = { locale: "en" };
locale.value = "en";
break;
case "en":
instance.locale = { locale: "zh" };
locale.value = "zh";
break;
}
};
watch(
() => locale.value,
() => {
@ -155,28 +125,31 @@ export default defineComponent({
pureApp.toggleSideBar();
}
onMounted(() => {
document
.querySelector(".el-dropdown__popper")
?.setAttribute("class", "resetTop");
document
.querySelector(".el-popper__arrow")
?.setAttribute("class", "hidden");
});
//
function translationCh() {
instance.locale = { locale: "zh" };
locale.value = "zh";
window.location.reload();
}
// English
function translationEn() {
instance.locale = { locale: "en" };
locale.value = "en";
window.location.reload();
}
return {
pureApp,
toggleSideBar,
usename,
toggleLang,
logout,
ch,
en,
favicon,
onPanel,
deviceDetection,
locale,
t
usename,
pureApp,
favicon,
logout,
onPanel,
translationCh,
translationEn,
toggleSideBar,
deviceDetection
};
}
});
@ -185,13 +158,13 @@ export default defineComponent({
<style lang="scss" scoped>
.navbar {
width: 100%;
height: 50px;
height: 48px;
overflow: hidden;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 46px;
line-height: 48px;
height: 100%;
float: left;
cursor: pointer;
@ -203,56 +176,46 @@ export default defineComponent({
}
}
.breadcrumb-container {
float: left;
}
.right-menu {
position: absolute;
right: 0;
.vertical-header-right {
display: flex;
align-items: center;
min-width: 280px;
height: 48px;
line-height: 48px;
align-items: center;
color: #000000d9;
justify-content: flex-end;
.inter {
width: 40px;
height: 48px;
display: flex;
align-items: center;
justify-content: space-around;
.screen-full {
cursor: pointer;
&:hover {
cursor: pointer;
background: #f0f0f0;
}
img {
width: 25px;
background: #f6f6f6;
}
}
.hsset {
width: 40px;
.iconinternationality {
height: 48px;
display: flex;
align-items: center;
justify-content: space-around;
margin-right: 5px;
width: 40px;
padding: 11px;
cursor: pointer;
&:hover {
cursor: pointer;
background: #f0f0f0;
background: #f6f6f6;
}
}
.el-dropdown-link {
width: 70px;
width: 100px;
height: 48px;
padding: 10px;
display: flex;
align-items: center;
justify-content: space-around;
margin-right: 10px;
cursor: pointer;
color: #000000d9;
&:hover {
background: #f6f6f6;
}
p {
font-size: 14px;
@ -261,22 +224,50 @@ export default defineComponent({
img {
width: 22px;
height: 22px;
border-radius: 50%;
}
}
.el-icon-setting {
height: 48px;
width: 40px;
padding: 11px;
display: flex;
cursor: pointer;
align-items: center;
&:hover {
background: #f6f6f6;
}
}
}
}
// single element-plus reset
.el-dropdown-menu__item {
padding: 0 10px;
.breadcrumb-container {
float: left;
}
}
.el-dropdown-menu {
padding: 6px 0;
.translation {
.el-dropdown-menu__item {
padding: 0 40px !important;
}
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
}
}
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
.logout {
.el-dropdown-menu__item {
padding: 0 18px !important;
}
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
}
}
</style>

View File

@ -3,7 +3,7 @@ import { ref } from "vue";
import { useEventListener, onClickOutside } from "@vueuse/core";
import { emitter } from "/@/utils/mitt";
let show = ref(false);
let show = ref<Boolean>(false);
const target = ref(null);
onClickOutside(target, () => {
show.value = false;

View File

@ -1,6 +1,5 @@
<script setup lang="ts">
import { useFullscreen } from "@vueuse/core";
const { isFullscreen, toggle } = useFullscreen();
</script>
@ -23,15 +22,10 @@ const { isFullscreen, toggle } = useFullscreen();
<style lang="scss" scoped>
.screen-full {
width: 40px;
height: 48px;
width: 36px;
height: 62px;
display: flex;
align-items: center;
justify-content: space-around;
&:hover {
cursor: pointer;
background: #f0f0f0;
}
}
</style>

View File

@ -1,14 +1,18 @@
<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 { reactive, ref, unref, useCssModule } from "vue";
import { storageLocal, storageSession } from "/@/utils/storage";
import { reactive, ref, unref, useCssModule, getCurrentInstance } from "vue";
const router = useRouter();
const { isSelect } = useCssModule();
const instance =
getCurrentInstance().appContext.app.config.globalProperties.$storage;
//
const markValue = ref(storageLocal.getItem("showModel") || "smart");
@ -80,37 +84,54 @@ function onChange({ label }) {
emitter.emit("tagViewsShowModel", label);
}
const firstTheme = templateRef<HTMLElement | null>("firstTheme", null);
const secondTheme = templateRef<HTMLElement | null>("secondTheme", null);
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
);
const dataTheme = ref(storageLocal.getItem("data-theme") || "dark");
if (dataTheme.value) {
storageLocal.setItem("data-theme", unref(dataTheme));
window.document.body.setAttribute("data-theme", unref(dataTheme));
}
// dark
function onDark() {
storageLocal.setItem("data-theme", "dark");
window.document.body.setAttribute("data-theme", "dark");
toggleClass(true, isSelect, unref(firstTheme));
toggleClass(false, isSelect, unref(secondTheme));
}
// light
function onLight() {
storageLocal.setItem("data-theme", "light");
window.document.body.setAttribute("data-theme", "light");
toggleClass(false, isSelect, unref(firstTheme));
toggleClass(true, isSelect, unref(secondTheme));
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");
emitter.emit("logoChange", unref(logoVal));
}
function setTheme(layout: string, theme: string, dom: HTMLElement) {
dataTheme.value.layout = `${layout}-${theme}`;
window.document.body.setAttribute("data-layout", layout);
window.document.body.setAttribute("data-theme", theme);
instance.layout = { layout: `${layout}-${theme}` };
toggleClass(true, isSelect, unref(dom));
toggleClass(false, isSelect, unref(dom));
}
</script>
<template>
@ -124,9 +145,9 @@ function logoChange() {
placement="bottom"
>
<li
:class="dataTheme === 'dark' ? $style.isSelect : ''"
ref="firstTheme"
@click="onDark"
:class="dataTheme.layout === 'vertical-dark' ? $style.isSelect : ''"
ref="verticalDarkDom"
@click="setTheme('vertical', 'dark', verticalDarkDom)"
>
<div></div>
<div></div>
@ -140,9 +161,43 @@ function logoChange() {
placement="bottom"
>
<li
:class="dataTheme === 'light' ? $style.isSelect : ''"
ref="secondTheme"
@click="onLight"
:class="dataTheme.layout === 'vertical-light' ? $style.isSelect : ''"
ref="verticalLightDom"
@click="setTheme('vertical', 'light', verticalLightDom)"
>
<div></div>
<div></div>
</li>
</el-tooltip>
<el-tooltip
class="item"
effect="dark"
content="暗色主题"
placement="bottom"
>
<li
:class="dataTheme.layout === 'horizontal-dark' ? $style.isSelect : ''"
ref="horizontalDarkDom"
@click="setTheme('horizontal', 'dark', horizontalDarkDom)"
>
<div></div>
<div></div>
</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', horizontalLightDom)"
>
<div></div>
<div></div>
@ -237,18 +292,19 @@ function logoChange() {
.theme-stley {
margin-top: 25px;
width: 100%;
height: 60px;
height: 180px;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
li {
width: 30%;
height: 100%;
margin: 10px;
width: 36%;
height: 70px;
background: #f0f2f5;
position: relative;
overflow: hidden;
cursor: pointer;
background-color: #f0f2f5;
border-radius: 4px;
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
@ -265,7 +321,7 @@ function logoChange() {
height: 30%;
top: 0;
right: 0;
background-color: #fff;
background: #fff;
box-shadow: 0 0 1px #888;
position: absolute;
}
@ -278,7 +334,7 @@ function logoChange() {
width: 30%;
height: 100%;
box-shadow: 0 0 1px #888;
background-color: #fff;
background: #fff;
border-radius: 4px 0 0 4px;
}
@ -287,12 +343,34 @@ function logoChange() {
height: 30%;
top: 0;
right: 0;
background-color: #fff;
background: #fff;
box-shadow: 0 0 1px #888;
position: absolute;
}
}
}
&:nth-child(3) {
div {
&:nth-child(1) {
width: 100%;
height: 30%;
background: #1b2a47;
box-shadow: 0 0 1px #888;
}
}
}
&:nth-child(4) {
div {
&:nth-child(1) {
width: 100%;
height: 30%;
background: #fff;
box-shadow: 0 0 1px #888;
}
}
}
}
}
</style>

View File

@ -1,51 +0,0 @@
<template>
<component :is="type" v-bind="linkProps(to)">
<slot />
</component>
</template>
<script lang="ts">
import { computed, defineComponent, unref } from "vue";
import { isUrl } from "/@/utils/is";
export default defineComponent({
name: "Link",
props: {
to: {
type: String,
required: true
}
},
setup(props) {
const isExternal = computed(() => {
return isUrl(props.to);
});
const type = computed(() => {
if (unref(isExternal)) {
return "a";
}
return "router-link";
});
function linkProps(to) {
if (unref(isExternal)) {
return {
href: to,
target: "_blank",
rel: "noopener"
};
}
return {
to: to
};
}
return {
isExternal,
type,
linkProps
};
}
});
</script>

View File

@ -1,116 +0,0 @@
<template>
<div v-if="!item.hidden">
<template
v-if="
hasOneShowingChild(item.children, item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
!item.alwaysShow
"
>
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<i :class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
<template #title>
<span>{{ $t(onlyOneChild.meta.title) }}</span>
</template>
</el-menu-item>
</app-link>
</template>
<el-sub-menu
v-else
ref="subMenu"
:index="resolvePath(item.path)"
popper-append-to-body
>
<template #title>
<i :class="item.meta.icon"></i>
<span>{{ $t(item.meta.title) }}</span>
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-sub-menu>
</div>
</template>
<script lang="ts">
import path from "path";
import AppLink from "./Link.vue";
import { defineComponent, PropType, ref } from "vue";
import { RouteRecordRaw } from "vue-router";
import { isUrl } from "/@/utils/is.ts";
export default defineComponent({
name: "SidebarItem",
components: { AppLink },
props: {
item: {
type: Object as PropType<RouteRecordRaw>,
required: true
},
isNest: {
type: Boolean,
default: false
},
basePath: {
type: String,
default: ""
}
},
setup(props) {
const onlyOneChild = ref<RouteRecordRaw>({} as any);
function hasOneShowingChild(
children: RouteRecordRaw[] = [],
parent: RouteRecordRaw
) {
const showingChildren = children.filter((item: any) => {
if (item.hidden) {
// hiddentrue
return false;
} else {
onlyOneChild.value = item;
return true;
}
});
if (showingChildren.length === 1) {
return true;
}
if (showingChildren.length === 0) {
// @ts-ignore
onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
return true;
}
return false;
}
// const resolvePath = (routePath: string) => {
// return path.resolve(props.basePath, routePath);
// };
function resolvePath(routePath) {
if (isUrl(routePath)) {
return routePath;
}
if (isUrl(this.basePath)) {
return props.basePath;
}
// @ts-ignore
return path.resolve(props.basePath, routePath);
}
return { hasOneShowingChild, resolvePath, onlyOneChild };
}
});
</script>

View File

@ -0,0 +1,254 @@
<template>
<div class="horizontal-header">
<div class="horizontal-header-left" @click="backHome">
<i class="fa fa-optin-monster"></i>
<h4>{{ settings.title }}</h4>
</div>
<el-menu
:default-active="activeMenu"
unique-opened
router
class="horizontal-header-menu"
mode="horizontal"
@select="menuSelect"
>
<sidebar-item
v-for="route in routeStore.wholeRoutes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
<div class="horizontal-header-right">
<!-- 全屏 -->
<screenfull v-show="!deviceDetection()" />
<!-- 国际化 -->
<el-dropdown trigger="click">
<iconinternationality />
<template #dropdown>
<el-dropdown-menu class="translation">
<el-dropdown-item
:style="{
background: locale === 'zh' ? '#1b2a47' : '',
color: locale === 'zh' ? '#f4f4f5' : '#000'
}"
@click="translationCh"
>简体中文</el-dropdown-item
>
<el-dropdown-item
:style="{
background: locale === 'en' ? '#1b2a47' : '',
color: locale === 'en' ? '#f4f4f5' : '#000'
}"
@click="translationEn"
>English</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 退出登陆 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
/>
<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-menu>
</template>
</el-dropdown>
<i
class="el-icon-setting"
:title="$t('message.hssystemSet')"
@click="onPanel"
></i>
</div>
</div>
</template>
<script lang="ts">
import {
computed,
defineComponent,
unref,
watch,
getCurrentInstance
} from "vue";
import { useI18n } from "vue-i18n";
import settings from "/@/settings";
import { emitter } from "/@/utils/mitt";
import SidebarItem from "./sidebarItem.vue";
import { algorithm } from "/@/utils/algorithm";
import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage";
import { deviceDetection } from "/@/utils/deviceDetection";
import { usePermissionStoreHook } from "/@/store/modules/permission";
import iconinternationality from "/@/assets/svg/iconinternationality.svg";
let routerArrays: Array<object> = [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "message.hshome",
icon: "el-icon-s-home",
showLink: true,
savedPosition: false
}
}
];
export default defineComponent({
name: "sidebar",
components: { SidebarItem, screenfull, iconinternationality },
// @ts-ignore
computed: {
// eslint-disable-next-line vue/return-in-computed-property
currentLocale() {
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";
}
switch (this.$storage.locale?.locale) {
case "zh":
return true;
case "en":
return false;
}
}
},
setup() {
const instance =
getCurrentInstance().appContext.config.globalProperties.$storage;
const routeStore = usePermissionStoreHook();
const route = useRoute();
const router = useRouter();
const routers = useRouter().options.routes;
let usename = storageSession.getItem("info")?.username;
const { locale, t } = useI18n();
watch(
() => locale.value,
() => {
//@ts-ignore
// title
document.title = t(unref(route.meta.title));
}
);
// 退
const logout = (): void => {
storageSession.removeItem("info");
router.push("/login");
};
function onPanel() {
emitter.emit("openPanel");
}
const activeMenu = computed(() => {
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
});
const menuSelect = (indexPath: string): void => {
let parentPath = "";
let parentPathIndex = indexPath.lastIndexOf("/");
if (parentPathIndex > 0) {
parentPath = indexPath.slice(0, parentPathIndex);
}
//
function findCurrentRoute(routes) {
return routes.map(item => {
if (item.path === indexPath) {
//
emitter.emit("changLayoutRoute", {
indexPath,
parentPath
});
} else {
if (item.children) findCurrentRoute(item.children);
}
});
}
findCurrentRoute(algorithm.increaseIndexes(routers));
};
function backHome() {
router.push("/welcome");
}
//
function translationCh() {
instance.locale = { locale: "zh" };
locale.value = "zh";
window.location.reload();
}
// English
function translationEn() {
instance.locale = { locale: "en" };
locale.value = "en";
window.location.reload();
}
return {
locale,
usename,
settings,
routeStore,
activeMenu,
logout,
onPanel,
backHome,
menuSelect,
translationCh,
translationEn,
deviceDetection
};
}
});
</script>
<style lang="scss" scoped>
.translation {
.el-dropdown-menu__item {
padding: 0 40px !important;
}
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
}
}
.logout {
.el-dropdown-menu__item {
padding: 0 18px !important;
}
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
color: #606266;
background: #f0f0f0;
}
}
</style>

View File

@ -1,9 +1,17 @@
<script setup lang="ts">
import settings from "/@/settings";
const props = defineProps({
collapse: Boolean
});
</script>
<template>
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
<div class="sidebar-logo-container" :class="{ collapse: props.collapse }">
<transition name="sidebarLogoFade">
<router-link
v-if="collapse"
key="collapse"
v-if="props.collapse"
key="props.collapse"
:title="settings.title"
class="sidebar-logo-link"
to="/"
@ -25,25 +33,6 @@
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import settings from "/@/settings";
export default defineComponent({
props: {
collapse: {
type: Boolean,
required: true
}
},
setup() {
return {
settings
};
}
});
</script>
<style lang="scss" scoped>
.sidebar-logo-container {
position: relative;

View File

@ -0,0 +1,104 @@
<script setup lang="ts">
import path from "path";
import { PropType, ref } from "vue";
import { RouteRecordRaw } from "vue-router";
const props = defineProps({
item: {
type: Object as PropType<RouteRecordRaw>
},
isNest: {
type: Boolean,
default: false
},
basePath: {
type: String,
default: ""
}
});
type childrenType = {
path?: string;
noShowingChildren?: boolean;
children?: RouteRecordRaw[];
meta?: {
icon?: string;
title?: string;
};
};
const onlyOneChild = ref<RouteRecordRaw | childrenType>({} as any);
function hasOneShowingChild(
children: RouteRecordRaw[] = [],
parent: RouteRecordRaw
) {
const showingChildren = children.filter((item: any) => {
if (item.hidden) {
// hiddentrue
return false;
} else {
onlyOneChild.value = item;
return true;
}
});
if (showingChildren.length === 1) {
return true;
}
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
return true;
}
return false;
}
function resolvePath(routePath) {
return path.resolve(props.basePath, routePath);
}
</script>
<template>
<template
v-if="
hasOneShowingChild(props.item.children, props.item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
!props.item.alwaysShow
"
>
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<i
:class="
onlyOneChild.meta.icon || (props.item.meta && props.item.meta.icon)
"
/>
<template #title>
<span>{{ $t(onlyOneChild.meta.title) }}</span>
</template>
</el-menu-item>
</template>
<el-sub-menu
v-else
ref="subMenu"
:index="resolvePath(props.item.path)"
popper-append-to-body
>
<template #title>
<i :class="props.item.meta.icon"></i>
<span>{{ $t(props.item.meta.title) }}</span>
</template>
<sidebar-item
v-for="child in props.item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-sub-menu>
</template>

View File

@ -1,11 +1,12 @@
<template>
<div :class="{ 'has-logo': showLogo }">
<div :class="['sidebar-container', showLogo ? 'has-logo' : '']">
<Logo v-if="showLogo === '1'" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
unique-opened
router
:collapse-transition="false"
mode="vertical"
@select="menuSelect"
@ -22,14 +23,14 @@
</template>
<script lang="ts">
import { computed, defineComponent, ref, onBeforeMount } from "vue";
import Logo from "./logo.vue";
import { emitter } from "/@/utils/mitt";
import SidebarItem from "./sidebarItem.vue";
import { algorithm } from "/@/utils/algorithm";
import { storageLocal } from "/@/utils/storage";
import { useRoute, useRouter } from "vue-router";
import { useAppStoreHook } from "/@/store/modules/app";
import SidebarItem from "./SidebarItem.vue";
import { algorithm } from "/@/utils/algorithm";
import { emitter } from "/@/utils/mitt";
import Logo from "./Logo.vue";
import { storageLocal } from "/@/utils/storage";
import { computed, defineComponent, ref, onBeforeMount } from "vue";
import { usePermissionStoreHook } from "/@/store/modules/permission";
export default defineComponent({
@ -61,6 +62,7 @@ export default defineComponent({
parentPath = indexPath.slice(0, parentPathIndex);
}
//
// eslint-disable-next-line no-inner-declarations
function findCurrentRoute(routes) {
return routes.map(item => {
if (item.path === indexPath) {

View File

@ -1,3 +1,41 @@
<script lang="ts">
let routerArrays: Array<object> = [
{
path: "/welcome",
parentPath: "/",
meta: {
title: "message.hshome",
icon: "el-icon-s-home",
showLink: true,
savedPosition: false
}
}
];
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,
@ -10,13 +48,20 @@ import {
useCssModule
} from "vue";
import options from "/@/settings";
import { useI18n } from "vue-i18n";
import { toggleClass } from "/@/utils/operate";
import { useEventListener } from "@vueuse/core";
import { useAppStoreHook } from "/@/store/modules/app";
import fullScreen from "/@/assets/svg/full_screen.svg";
import exitScreen from "/@/assets/svg/exit_screen.svg";
import { useSettingStoreHook } from "/@/store/modules/settings";
import { Navbar, Sidebar, AppMain, setting, tag } from "./components";
import navbar from "./components/navbar.vue";
import tag from "./components/tag/index.vue";
import appMain from "./components/appMain.vue";
import setting from "./components/setting/index.vue";
import Vertical from "./components/sidebar/vertical.vue";
import Horizontal from "./components/sidebar/horizontal.vue";
interface setInter {
sidebar: any;
@ -118,19 +163,25 @@ onBeforeMount(() => {
</script>
<template>
<div :class="set.classes" class="app-wrapper">
<div :class="['app-wrapper', set.classes]">
<div
v-if="set.device === 'mobile' && set.sidebar.opened"
v-show="
set.device === 'mobile' &&
set.sidebar.opened &&
layout.includes('vertical')
"
class="drawer-bg"
@click="handleClickOutside(false)"
/>
<!-- 侧边栏 -->
<sidebar class="sidebar-container" v-if="!containerHiddenSideBar" />
<Vertical v-show="!containerHiddenSideBar && layout.includes('vertical')" />
<div class="main-container">
<div :class="{ 'fixed-header': set.fixedHeader }">
<!-- 顶部导航栏 -->
<navbar v-show="!containerHiddenSideBar" />
<navbar
v-show="!containerHiddenSideBar && layout.includes('vertical')"
/>
<!-- tabs标签页 -->
<Horizontal v-show="layout.includes('horizontal')" />
<tag>
<span @click="onFullScreen">
<fullScreen v-if="!containerHiddenSideBar" />
@ -194,10 +245,6 @@ $sideBarWidth: 210px;
transition: width 0.28s;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
.mobile .fixed-header {
width: 100%;
}

View File

@ -1,6 +1,7 @@
import App from "./App.vue";
import router from "./router";
import { setupStore } from "/@/store";
import { getServerConfig } from "./config";
import { createApp, Directive } from "vue";
import { usI18n } from "../src/plugins/i18n";
import { useTable } from "../src/plugins/vxe-table";
@ -14,13 +15,8 @@ import "./assets/iconfont/iconfont.js";
import "./assets/iconfont/iconfont.css";
import "v-contextmenu/dist/themes/default.css";
import { setConfig, getConfig } from "./config";
import axios from "axios";
const app = createApp(App);
app.config.globalProperties.$config = getConfig();
// 响应式storage
import Storage from "responsive-storage";
// @ts-ignore
@ -47,6 +43,13 @@ app.use(Storage, {
default: Storage.getData(undefined, "locale") ?? {
locale: "zh"
}
},
// layout模式以及主题
layout: {
type: Object,
default: Storage.getData(undefined, "layout") ?? {
layout: "vertical-dark"
}
}
});
@ -56,35 +59,7 @@ Object.keys(directives).forEach(key => {
app.directive(key, (directives as { [key: string]: Directive })[key]);
});
// 获取项目动态全局配置
export const getServerConfig = async (): Promise<undefined> => {
return axios({
baseURL: "",
method: "get",
url:
process.env.NODE_ENV === "production"
? "/manages/serverConfig.json"
: "/serverConfig.json"
})
.then(({ data: config }) => {
let $config = app.config.globalProperties.$config;
// 自动注入项目配置
if (app && $config && typeof config === "object") {
$config = Object.assign($config, config);
app.config.globalProperties.$config = $config;
// 设置全局配置
setConfig($config);
}
// 设置全局baseURL
app.config.globalProperties.$baseUrl = $config.baseURL;
return $config;
})
.catch(() => {
throw "请在public文件夹下添加serverConfig.json配置文件";
});
};
getServerConfig().then(async () => {
getServerConfig(app).then(async () => {
setupStore(app);
app.use(router).use(useElementPlus).use(useTable).use(usI18n);
await router.isReady();

View File

@ -4,8 +4,10 @@ import {
RouteComponent,
createWebHashHistory
} from "vue-router";
import { split } from "lodash-es";
import { i18n } from "/@/plugins/i18n";
import NProgress from "/@/utils/progress";
import { openLink } from "/@/utils/link";
import { storageSession, storageLocal } from "/@/utils/storage";
import { usePermissionStoreHook } from "/@/store/modules/permission";
@ -128,13 +130,20 @@ const whiteList = ["/login", "/register"];
router.beforeEach((to, _from, next) => {
const name = storageSession.getItem("info");
NProgress.start();
const externalLink = to?.redirectedFrom?.fullPath;
// @ts-ignore
const { t } = i18n.global;
// @ts-ignore
to.meta.title ? (document.title = t(to.meta.title)) : "";
if (!externalLink) to.meta.title ? (document.title = t(to.meta.title)) : "";
if (name) {
if (_from?.name) {
next();
// 如果路由包含http 则是超链接 反之是普通路由
if (externalLink && externalLink.includes("http")) {
openLink(`http${split(externalLink, "http")[1]}`);
NProgress.done();
} else {
next();
}
} else {
// 刷新
if (usePermissionStoreHook().wholeRoutes.length === 0)

View File

@ -36,9 +36,7 @@
// dropdown
.el-dropdown-menu {
a {
display: block;
}
padding: 2px 0 2px 0 !important;
}
// to fix el-date-picker css style
@ -51,6 +49,6 @@
}
// el-tooltip,的权重
.is-dark {
z-index: 99999 !important;
}
// .is-dark {
// z-index: 99999 !important;
// }

View File

@ -84,12 +84,6 @@ ul {
display: none !important;
}
.resetTop {
top: 48px !important;
outline: 0;
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
}
// 灰色模式
.html-grey {
filter: grayscale(100%);
@ -115,7 +109,3 @@ ul {
.mobile-spacing {
margin: 0;
}
.el-popper[data-popper-placement^="bottom"] > .el-popper__arrow {
top: 0 !important;
}

View File

@ -8,11 +8,13 @@
// 子菜单背景
$subMenuBg,
// 鼠标覆盖子菜单时的背景
$subMenuHover
$subMenuHover,
// vertical模式下主体内容距离网页文档左侧的距离
$sideBarWidth,
$navTextColor
) {
$menuText: #7a80b4;
$menuActiveText: #7a80b4;
$sideBarWidth: 210px;
.main-container {
min-height: 100%;
@ -21,9 +23,13 @@
position: relative;
}
.el-popper.is-light {
border: none !important;
}
.sidebar-container {
transition: width 0.28s;
width: $sideBarWidth !important;
width: $sideBarWidth;
background-color: $menuBg;
height: 100%;
position: fixed;
@ -35,16 +41,15 @@
overflow: hidden;
box-shadow: 0 0 1px #888;
// reset element-plus css
.scrollbar-wrapper {
overflow-x: hidden !important;
}
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out,
0s padding-right ease-in-out;
}
.scrollbar-wrapper {
overflow-x: hidden !important;
}
.el-scrollbar__bar.is-vertical {
right: 0;
}
@ -72,9 +77,7 @@
.el-menu {
border: none;
height: 100%;
background-color: transparent;
// background-color: $menuBg !important;
// width: 100% !important;
background-color: transparent !important;
}
.el-menu-item,
@ -85,7 +88,7 @@
// menu hover
.submenu-title-noDropdown,
.el-sub-menu__title {
background: $menuBg;
// background: $menuBg;
&:hover {
background-color: $menuHover !important;
@ -106,7 +109,7 @@
color: $subMenuActiveText !important;
}
& .nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu .el-menu--inline .el-sub-menu__title,
& .el-sub-menu .el-menu-item {
font-size: 12px;
min-width: $sideBarWidth !important;
@ -118,13 +121,327 @@
}
}
.horizontal-header {
display: flex;
justify-content: space-around;
background-color: $menuBg;
width: 100%;
height: 62px;
align-items: center;
.horizontal-header-left {
display: flex;
height: 100%;
width: auto;
min-width: 200px;
align-items: center;
padding-left: 10px;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: $menuHover;
}
i {
font-size: 30px;
color: #1890ff;
margin-right: 4px;
}
h4 {
font-size: 16px;
font-weight: 700;
color: $navTextColor;
transition: all 0.5s;
}
}
.horizontal-header-menu {
height: 100%;
min-width: 0;
flex: 1;
// todo::
overflow-x: auto;
align-items: center;
}
.horizontal-header-right {
display: flex;
min-width: 280px;
align-items: center;
color: $navTextColor;
justify-content: flex-end;
.screen-full {
cursor: pointer;
&:hover {
background: $menuHover;
}
}
.iconinternationality {
height: 62px;
width: 40px;
padding: 11px;
cursor: pointer;
color: $navTextColor;
&:hover {
background: $menuHover;
}
}
.el-dropdown-link {
width: 100px;
height: 62px;
padding: 10px;
display: flex;
align-items: center;
justify-content: space-around;
cursor: pointer;
color: $navTextColor;
&:hover {
background: $menuHover;
}
p {
font-size: 14px;
}
img {
width: 22px;
height: 22px;
border-radius: 50%;
}
}
.el-icon-setting {
height: 62px;
width: 40px;
padding: 11px;
display: flex;
cursor: pointer;
align-items: center;
&:hover {
background: $menuHover;
}
}
}
.el-menu {
border: none;
height: 100%;
background-color: transparent;
width: 100% !important;
}
.el-menu-item,
.el-sub-menu__title {
color: $menuText;
}
.submenu-title-noDropdown,
.el-sub-menu__title {
height: 60px;
background: $menuBg;
&:hover {
background-color: $menuHover !important;
}
}
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
color: $subMenuActiveText !important;
border-bottom-color: #409eff;
i {
color: $subMenuActiveText !important;
}
}
.is-active {
transition: color 0.3s;
color: $subMenuActiveText !important;
border-bottom-color: #409eff;
}
}
// vertical菜单折叠
.el-menu--vertical {
.el-menu--popup {
background-color: $subMenuBg !important;
.el-menu-item {
color: $menuText;
background-color: $subMenuBg;
&:hover {
background-color: $subMenuHover;
}
}
.el-sub-menu__title {
color: $menuText;
}
}
& > .el-menu {
i {
margin-right: 16px;
}
}
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
color: $subMenuActiveText !important;
i {
color: $subMenuActiveText !important;
}
}
// 子菜单中还有子菜单
.el-menu .el-sub-menu__title {
font-size: 12px;
min-width: $sideBarWidth !important;
background-color: $subMenuBg !important;
&:hover {
background-color: $menuHover !important;
}
}
.is-active {
transition: color 0.3s;
color: $subMenuActiveText !important;
}
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
&:hover {
background-color: $menuHover !important;
}
}
}
// horizontal菜单折叠
.el-menu--horizontal {
.el-menu--popup {
background-color: $subMenuBg !important;
.el-menu-item {
color: $menuText;
background-color: $subMenuBg;
&:hover {
background-color: $subMenuHover;
}
}
.el-sub-menu__title {
color: $menuText;
}
}
// 无子菜单时激活border-bottom
.router-link-exact-active > .submenu-title-noDropdown {
height: 60px;
border-bottom: 2px solid var(--el-menu-active-color);
}
// 子菜单中还有子菜单
.el-menu .el-sub-menu__title {
font-size: 12px;
min-width: $sideBarWidth !important;
background-color: $subMenuBg !important;
&:hover {
background-color: $menuHover !important;
}
}
& > .el-menu {
i {
margin-right: 16px;
}
}
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
color: $subMenuActiveText !important;
i {
color: $subMenuActiveText !important;
}
}
.is-active {
transition: color 0.3s;
color: $subMenuActiveText !important;
}
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
&:hover {
background-color: $menuHover !important;
}
}
}
.el-scrollbar__wrap {
overflow: auto;
height: 100%;
}
.el-menu--collapse .el-menu .el-sub-menu {
min-width: $sideBarWidth !important;
}
// 手机端
.mobile {
.main-container {
margin-left: 0 !important;
}
.sidebar-container {
transition: transform 0.28s;
width: $sideBarWidth !important;
}
&.hideSidebar {
.sidebar-container {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(-$sideBarWidth, 0, 0);
}
}
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
body[data-layout="vertical"] {
.hideSidebar {
.fixed-header {
width: calc(100% - 54px);
}
.sidebar-container {
width: 54px !important;
}
.main-container {
margin-left: 54px;
margin-left: 54px !important;
}
.submenu-title-noDropdown {
@ -161,122 +478,88 @@
}
}
}
// 菜单折叠
.el-menu--vertical {
.el-menu--popup {
background-color: $subMenuBg !important;
.el-menu-item {
color: $menuText;
background-color: $subMenuBg;
&:hover {
background-color: $subMenuHover;
}
}
.el-sub-menu__title {
color: $menuText;
}
}
& > .el-menu {
i {
margin-right: 16px;
}
}
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
color: $subMenuActiveText !important;
i {
color: $subMenuActiveText !important;
}
}
.is-active {
transition: color 0.3s;
color: $subMenuActiveText !important;
}
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
&:hover {
// you can use $subMenuHover
background-color: $menuHover !important;
}
}
}
.el-scrollbar__wrap {
overflow: auto;
height: 100%;
}
.el-menu--collapse .el-menu .el-sub-menu {
min-width: $sideBarWidth !important;
}
// 手机端
.mobile {
.main-container {
margin-left: 0;
}
.sidebar-container {
transition: transform 0.28s;
width: $sideBarWidth !important;
}
&.hideSidebar {
.sidebar-container {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(-$sideBarWidth, 0, 0);
}
}
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
// 暗色主题
body[data-theme="dark"] {
// vertical模式下暗色主题
body[data-layout="vertical"][data-theme="dark"] {
$subMenuActiveText: #f4f4f5;
$menuBg: #1b2a47;
$menuHover: #2a395b;
$subMenuBg: #1f2d3d;
$subMenuHover: #001528;
$sideBarWidth: 210px;
$navTextColor: #fff;
@include merge-style(
$subMenuActiveText,
$menuBg,
$menuHover,
$subMenuBg,
$subMenuHover
$subMenuHover,
$sideBarWidth,
$navTextColor
);
}
// 亮色主题
body[data-theme="light"] {
// vertical模式下亮色主题
body[data-layout="vertical"][data-theme="light"] {
$subMenuActiveText: #409eff;
$menuBg: #fff;
$menuHover: #e0ebf6;
$subMenuBg: #fff;
$subMenuHover: #e0ebf6;
$sideBarWidth: 210px;
$navTextColor: #7a80b4;
@include merge-style(
$subMenuActiveText,
$menuBg,
$menuHover,
$subMenuBg,
$subMenuHover
$subMenuHover,
$sideBarWidth,
$navTextColor
);
}
// horizontal模式下暗色主题
body[data-layout="horizontal"][data-theme="dark"] {
$subMenuActiveText: #f4f4f5;
$menuBg: #1b2a47;
$menuHover: #2a395b;
$subMenuBg: #1f2d3d;
$subMenuHover: #001528;
$sideBarWidth: 0;
$navTextColor: #fff;
@include merge-style(
$subMenuActiveText,
$menuBg,
$menuHover,
$subMenuBg,
$subMenuHover,
$sideBarWidth,
$navTextColor
);
}
// horizontal模式下亮色主题
body[data-layout="horizontal"][data-theme="light"] {
$subMenuActiveText: #409eff;
$menuBg: #fff;
$menuHover: #e0ebf6;
$subMenuBg: #fff;
$subMenuHover: #e0ebf6;
$sideBarWidth: 0;
$navTextColor: #7a80b4;
@include merge-style(
$subMenuActiveText,
$menuBg,
$menuHover,
$subMenuBg,
$subMenuHover,
$sideBarWidth,
$navTextColor
);
}

12
src/utils/link.ts Normal file
View File

@ -0,0 +1,12 @@
export const openLink = (link: string) => {
const $a: HTMLElement = document.createElement("a");
$a.setAttribute("href", link);
$a.setAttribute("target", "_blank");
$a.setAttribute("rel", "noreferrer noopener");
$a.setAttribute("id", "external");
document.getElementById("external") &&
document.body.removeChild(document.getElementById("external"));
document.body.appendChild($a);
$a.click();
$a.remove();
};

191
yarn.lock
View File

@ -420,11 +420,6 @@
dependencies:
chalk "^4.0.0"
"@element-plus/icons@^0.0.11":
version "0.0.11"
resolved "https://registry.npmjs.org/@element-plus/icons/-/icons-0.0.11.tgz#9b187c002774548b911850d17fa5fc2f9a515f57"
integrity sha512-iKQXSxXu131Ai+I9Ymtcof9WId7kaXvB1+WRfAfpQCW7UiAMYgdNDqb/u0hgTo2Yq3MwC4MWJnNuTBEpG8r7+A==
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@ -786,6 +781,16 @@
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-core@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.19.tgz#b537dd377ce51fdb64e9b30ebfbff7cd70a64cb9"
integrity sha512-8dOPX0YOtaXol0Zf2cfLQ4NU/yHYl2H7DCKsLEZ7gdvPK6ZSEwGLJ7IdghhY2YEshEpC5RB9QKdC5I07z8Dtjg==
dependencies:
"@babel/parser" "^7.15.0"
"@vue/shared" "3.2.19"
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-dom@3.2.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.11.tgz#d066f8e1f1812b4e881593819ade0fe6d654c776"
@ -794,7 +799,31 @@
"@vue/compiler-core" "3.2.11"
"@vue/shared" "3.2.11"
"@vue/compiler-sfc@3.2.11", "@vue/compiler-sfc@^3.0.11":
"@vue/compiler-dom@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.19.tgz#0607bc90de6af55fde73b09b3c4d0bf8cb597ed8"
integrity sha512-WzQoE8rfkFjPtIioc7SSgTsnz9g2oG61DU8KHnzPrRS7fW/lji6H2uCYJfp4Z6kZE8GjnHc1Ljwl3/gxDes0cw==
dependencies:
"@vue/compiler-core" "3.2.19"
"@vue/shared" "3.2.19"
"@vue/compiler-sfc@3.2.19", "@vue/compiler-sfc@^3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.19.tgz#d412195a98ebd49b84602f171719294a1d9549be"
integrity sha512-pLlbgkO1UHTO02MSpa/sFOXUwIDxSMiKZ1ozE5n71CY4DM+YmI+G3gT/ZHZ46WBId7f3VTF/D8pGwMygcQbrQA==
dependencies:
"@babel/parser" "^7.15.0"
"@vue/compiler-core" "3.2.19"
"@vue/compiler-dom" "3.2.19"
"@vue/compiler-ssr" "3.2.19"
"@vue/ref-transform" "3.2.19"
"@vue/shared" "3.2.19"
estree-walker "^2.0.2"
magic-string "^0.25.7"
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-sfc@^3.0.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.11.tgz#628fa12238760d9b9b339ac2e125a759224fadbf"
integrity sha512-cUIaS8mgJrQ6yucj2AupWAwBRITK3W/a8wCOn9g5fJGtOl8h4APY8vN3lzP8HIJDyEeRF3I8SfRhL+oX97kSnw==
@ -826,6 +855,14 @@
"@vue/compiler-dom" "3.2.11"
"@vue/shared" "3.2.11"
"@vue/compiler-ssr@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.19.tgz#3e91ecf70f8f961c5f63eacd2139bcdab9a7a07c"
integrity sha512-oLon0Cn3O7WEYzzmzZavGoqXH+199LT+smdjBT3Uf3UX4HwDNuBFCmvL0TsqV9SQnIgKvBRbQ7lhbpnd4lqM3w==
dependencies:
"@vue/compiler-dom" "3.2.19"
"@vue/shared" "3.2.19"
"@vue/devtools-api@^6.0.0-beta.13", "@vue/devtools-api@^6.0.0-beta.14", "@vue/devtools-api@^6.0.0-beta.15":
version "6.0.0-beta.15"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.15.tgz#ad7cb384e062f165bcf9c83732125bffbc2ad83d"
@ -845,12 +882,12 @@
dependencies:
vue-eslint-parser "^7.0.0"
"@vue/reactivity@3.2.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.11.tgz#ec04d33acaf2b92cca2960535bec81b26cc5772b"
integrity sha512-hEQstxPQbgGZq5qApzrvbDmRdK1KP96O/j4XrwT8fVkT1ytkFs4fH2xNEh9QKwXfybbQkLs77W7OfXCv5o6qbA==
"@vue/reactivity@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.19.tgz#fc6e0f0106f295226835cfed5ff5f84d927bea65"
integrity sha512-FtachoYs2SnyrWup5UikP54xDX6ZJ1s5VgHcJp4rkGoutU3Ry61jhs+nCX7J64zjX992Mh9gGUC0LqTs8q9vCA==
dependencies:
"@vue/shared" "3.2.11"
"@vue/shared" "3.2.19"
"@vue/ref-transform@3.2.11":
version "3.2.11"
@ -863,28 +900,52 @@
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/runtime-core@3.2.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.11.tgz#0dbe801be4bd0bfde253226797e7d304c8fdda30"
integrity sha512-horlxjWwSvModC87WdsWswzzHE5IexmKkQA65S5vFgP5hLUBW+HRyScDeuB/RRcFmqnf+ozacNCfap0kqcpODw==
"@vue/ref-transform@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.19.tgz#cf0f986486bb26838fbd09749e927bab19745600"
integrity sha512-03wwUnoIAeKti5IGGx6Vk/HEBJ+zUcm5wrUM3+PQsGf7IYnXTbeIfHHpx4HeSeWhnLAjqZjADQwW8uA4rBmVbg==
dependencies:
"@vue/reactivity" "3.2.11"
"@vue/shared" "3.2.11"
"@babel/parser" "^7.15.0"
"@vue/compiler-core" "3.2.19"
"@vue/shared" "3.2.19"
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/runtime-dom@3.2.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.11.tgz#04f9054a9e64bdf156c2fc22cad67cfaa8b84616"
integrity sha512-cOK1g0INdiCbds2xrrJKrrN+pDHuLz6esUs/crdEiupDuX7IeiMbdqrAQCkYHp5P1KLWcbGlkmwfVD7HQGii0Q==
"@vue/runtime-core@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.19.tgz#807715b7f4728abb84fa4a8efdbe37d8ddb4c6d3"
integrity sha512-qArZSWKxWsgKfxk9BelZ32nY0MZ31CAW2kUUyVJyxh4cTfHaXGbjiQB5JgsvKc49ROMNffv9t3/qjasQqAH+RQ==
dependencies:
"@vue/runtime-core" "3.2.11"
"@vue/shared" "3.2.11"
"@vue/reactivity" "3.2.19"
"@vue/shared" "3.2.19"
"@vue/runtime-dom@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.19.tgz#7e8bf645754703e360fa132e4be9113edf2377bb"
integrity sha512-hIRboxXwafeHhbZEkZYNV0MiJXPNf4fP0X6hM2TJb0vssz8BKhD9cF92BkRgZztTQevecbhk0gu4uAPJ3dxL9A==
dependencies:
"@vue/runtime-core" "3.2.19"
"@vue/shared" "3.2.19"
csstype "^2.6.8"
"@vue/server-renderer@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.19.tgz#870bcec9f7cdaee0c2187a169b6e636ab4362fb1"
integrity sha512-A9FNT7fgQJXItwdzWREntAgWKVtKYuXHBKGev/H4+ByTu8vB7gQXGcim01QxaJshdNg4dYuH2tEBZXCNCNx+/w==
dependencies:
"@vue/compiler-ssr" "3.2.19"
"@vue/shared" "3.2.19"
"@vue/shared@3.2.11":
version "3.2.11"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.11.tgz#01899f54949caf1ac241de397bd17069632574de"
integrity sha512-ovfXAsSsCvV9JVceWjkqC/7OF5HbgLOtCWjCIosmPGG8lxbPuavhIxRH1dTx4Dg9xLgRTNLvI3pVxG4ItQZekg==
"@vue/shared@3.2.19":
version "3.2.19"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.19.tgz#111ec3da18337d86274446984c49925b1b2b2dd7"
integrity sha512-Knqhx7WieLdVgwCAZgTVrDCXZ50uItuecLh9JdLC8O+a5ayaSyIQYveUK3hCRNC7ws5zalHmZwfdLMGaS8r4Ew==
"@vueuse/core@^6.4.1":
version "6.4.1"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-6.4.1.tgz#21416997a23bfb4924a5082ed6fa959027f80d04"
@ -1532,7 +1593,7 @@ dargs@^7.0.0:
resolved "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc"
integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==
dayjs@1.x, dayjs@^1.10.6:
dayjs@^1.10.6, dayjs@^1.10.7:
version "1.10.7"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468"
integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==
@ -1707,18 +1768,17 @@ electron-to-chromium@^1.3.830:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.840.tgz#3f2a1df97015d9b1db5d86a4c6bd4cdb920adcbb"
integrity sha512-yRoUmTLDJnkIJx23xLY7GbSvnmDCq++NSuxHDQ0jiyDJ9YZBUGJcrdUqm+ZwZFzMbCciVzfem2N2AWiHJcWlbw==
element-plus@^1.1.0-beta.12:
version "1.1.0-beta.12"
resolved "https://registry.npmjs.org/element-plus/-/element-plus-1.1.0-beta.12.tgz#2fd646f3c2f787dfb282d091ec6aa6945d1bec6a"
integrity sha512-IkFHcYWGDzHqeL2LpDM5ZQnuviqkNj8Bu9zg/Q6KImGk8xo4rqMf+e4rBHinIpeKzKdVag0c2TDABNBfKvjaPA==
element-plus@^1.1.0-beta.16:
version "1.1.0-beta.16"
resolved "https://registry.npmjs.org/element-plus/-/element-plus-1.1.0-beta.16.tgz#4409d9e33d005693f6039f5ed1fe05e301b3170d"
integrity sha512-4BZEldnIfFZs5A/saRqaWE4PwTot4p3YZU7qsDr3ev2zp35pcCL9TtpWMLIvNTMxvxKew0HTDPTk9fAWIZFQrQ==
dependencies:
"@element-plus/icons" "^0.0.11"
"@popperjs/core" "^2.10.1"
"@vueuse/core" "~6.1.0"
async-validator "^3.4.0"
dayjs "1.x"
dayjs "^1.10.7"
lodash "^4.17.21"
mitt "^2.1.0"
memoize-one "^5.2.1"
normalize-wheel "^1.0.1"
resize-observer-polyfill "^1.5.1"
@ -1817,9 +1877,9 @@ esbuild@0.11.3:
integrity sha512-BzVRHcCtFepjS9WcqRjqoIxLqgpK21a8J4Zi4msSGxDxiXVO1IbcqT1KjhdDDnJxKfe7bvzZrvMEX+bVO0Elcw==
esbuild@^0.12.17:
version "0.12.28"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.12.28.tgz#84da0d2a0d0dee181281545271e0d65cf6fab1ef"
integrity sha512-pZ0FrWZXlvQOATlp14lRSk1N9GkeJ3vLIwOcUoo3ICQn9WNR4rWoNi81pbn6sC1iYUy7QPqNzI3+AEzokwyVcA==
version "0.12.29"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.12.29.tgz#be602db7c4dc78944a9dbde0d1ea19d36c1f882d"
integrity sha512-w/XuoBCSwepyiZtIRsKsetiLDUVGPVw1E/R3VTFSecIy8UR7Cq3SOtwKHJMFoVqqVG36aGkzh4e8BvpO1Fdc7g==
escalade@^3.1.1:
version "3.1.1"
@ -2939,6 +2999,11 @@ mdn-data@2.0.14:
resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
memoize-one@^5.2.1:
version "5.2.1"
resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
meow@^8.0.0:
version "8.1.2"
resolved "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897"
@ -3081,7 +3146,12 @@ multimatch@^4.0.0:
arrify "^2.0.1"
minimatch "^3.0.4"
nanoid@^3.1.23:
nanocolors@^0.1.5:
version "0.1.12"
resolved "https://registry.npmjs.org/nanocolors/-/nanocolors-0.1.12.tgz#8577482c58cbd7b5bb1681db4cf48f11a87fd5f6"
integrity sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==
nanoid@^3.1.23, nanoid@^3.1.25:
version "3.1.25"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
@ -3504,7 +3574,7 @@ postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^8.1.10, postcss@^8.2.6, postcss@^8.3.6:
postcss@^8.1.10, postcss@^8.2.6:
version "8.3.6"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
@ -3513,6 +3583,15 @@ postcss@^8.1.10, postcss@^8.2.6, postcss@^8.3.6:
nanoid "^3.1.23"
source-map-js "^0.6.2"
postcss@^8.3.6:
version "8.3.7"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.3.7.tgz#ec88563588c8da8e58e7226f7633b51ae221eeda"
integrity sha512-9SaY7nnyQ63/WittqZYAvkkYPyKxchMKH71UDzeTmWuLSvxTRpeEeABZAzlCi55cuGcoFyoV/amX2BdsafQidQ==
dependencies:
nanocolors "^0.1.5"
nanoid "^3.1.25"
source-map-js "^0.6.2"
preact@^10.4.8:
version "10.5.14"
resolved "https://registry.npmjs.org/preact/-/preact-10.5.14.tgz#0b14a2eefba3c10a57116b90d1a65f5f00cd2701"
@ -3713,12 +3792,12 @@ resolve@^1.1.7, resolve@^1.10.0, resolve@^1.19.0, resolve@^1.20.0:
is-core-module "^2.2.0"
path-parse "^1.0.6"
responsive-storage@^1.0.9:
version "1.0.9"
resolved "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.9.tgz#389544da44fbd34adb8bd210dd6b4d6d4795642f"
integrity sha512-GODZF3a50hvnBvAntqDgiEub4+xXRcdACH1wnsM8KVmSnSd0IKqCcrE0fwk5b6y3lPW2h+ZpB3bBMcQpkuTeJg==
responsive-storage@^1.0.10:
version "1.0.10"
resolved "https://registry.npmjs.org/responsive-storage/-/responsive-storage-1.0.10.tgz#a872d7a1ea4f78f3e77d60ae62910483114cd445"
integrity sha512-M4j7C7/2xAxEfXuwoyt4Xh9N14o0pItsBnMK/BrNOi0mGpxcpDERNrSCPFvVM0avmpi4tliYduqU96ffOT16Ww==
dependencies:
vue "^3.1.1"
vue "^3.2.19"
restore-cursor@^3.1.0:
version "3.1.0"
@ -3741,9 +3820,9 @@ rimraf@^3.0.2:
glob "^7.1.3"
rollup@^2.38.5:
version "2.56.3"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz#b63edadd9851b0d618a6d0e6af8201955a77aeff"
integrity sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==
version "2.57.0"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.57.0.tgz#c1694475eb22e1022477c0f4635fd0ac80713173"
integrity sha512-bKQIh1rWKofRee6mv8SrF2HdP6pea5QkwBZSMImJysFj39gQuiV8MEPBjXOCpzk3wSYp63M2v2wkWBmFC8O/rg==
optionalDependencies:
fsevents "~2.3.2"
@ -4446,10 +4525,10 @@ vite-svg-loader@^2.2.0:
"@vue/compiler-sfc" "^3.0.11"
svgo "^2.3.0"
vite@^2.5.7:
version "2.5.7"
resolved "https://registry.npmjs.org/vite/-/vite-2.5.7.tgz#e495be9d8bcbf9d30c7141efdccacde746ee0125"
integrity sha512-hyUoWmRPhjN1aI+ZSBqDINKdIq7aokHE2ZXiztOg4YlmtpeQtMwMeyxv6X9YxHZmvGzg/js/eATM9Z1nwyakxg==
vite@^2.5.10:
version "2.5.10"
resolved "https://registry.npmjs.org/vite/-/vite-2.5.10.tgz#c598e3b5a7e1956ffc52eb3b3420d177fc2ed2a5"
integrity sha512-0ObiHTi5AHyXdJcvZ67HMsDgVpjT5RehvVKv6+Q0jFZ7zDI28PF5zK9mYz2avxdA+4iJMdwCz6wnGNnn4WX5Gg==
dependencies:
esbuild "^0.12.17"
postcss "^8.3.6"
@ -4505,14 +4584,16 @@ vue-types@^4.1.0:
dependencies:
is-plain-object "5.0.0"
vue@3.2.11, vue@^3.1.1:
version "3.2.11"
resolved "https://registry.npmjs.org/vue/-/vue-3.2.11.tgz#6b92295048df705ddac558fd3e3ed553e55e57c8"
integrity sha512-JkI3/eIgfk4E0f/p319TD3EZgOwBQfftgnkRsXlT7OrRyyiyoyUXn6embPGZXSBxD3LoZ9SWhJoxLhFh5AleeA==
vue@^3.2.19:
version "3.2.19"
resolved "https://registry.npmjs.org/vue/-/vue-3.2.19.tgz#da2c80a6a0271c7097fee9e31692adfd9d569c8f"
integrity sha512-6KAMdIfAtlK+qohTIUE4urwAv4A3YRuo8uAbByApUmiB0CziGAAPs6qVugN6oHPia8YIafHB/37K0O6KZ7sGmA==
dependencies:
"@vue/compiler-dom" "3.2.11"
"@vue/runtime-dom" "3.2.11"
"@vue/shared" "3.2.11"
"@vue/compiler-dom" "3.2.19"
"@vue/compiler-sfc" "3.2.19"
"@vue/runtime-dom" "3.2.19"
"@vue/server-renderer" "3.2.19"
"@vue/shared" "3.2.19"
vuedraggable@^4.1.0:
version "4.1.0"