release: update 2.9.0

This commit is contained in:
xiaoxian521 2022-02-05 17:34:01 +08:00
parent e33bdb52f3
commit fd4cad8d4c
50 changed files with 1020 additions and 1120 deletions

View File

@ -1,3 +1,14 @@
# 2.9.0 (2022-2-5)
### 🎫 Feat
- Added package size analysis, command `pnpm report`
### 🍏 Perf
- Use `iconify` to introduce icons on demand, optimize icon size, and reduce network requests
- Optimize the route, the route can not pass `showLink: true`, it is displayed by default
# 2.8.5 (2022-1-21) # 2.8.5 (2022-1-21)
### 🎫 Feat ### 🎫 Feat

View File

@ -1,3 +1,14 @@
# 2.9.0 (2022-2-5)
### 🎫 Feat
- Added package size analysis, command `pnpm report`
### 🍏 Perf
- Use `iconify` to introduce icons on demand, optimize icon size, and reduce network requests
- Optimize the route, the route can not pass `showLink: true`, it is displayed by default
# 2.8.5 (2022-1-21) # 2.8.5 (2022-1-21)
### 🎫 Feat ### 🎫 Feat

View File

@ -1,3 +1,14 @@
# 2.9.0(2022-2-5)
### 🎫 Feat
- 添加打包大小分析,命令`pnpm report`
### 🍏 Perf
- 采用`iconify`按需引入图标,优化图标大小,减少网络请求
- 优化路由,路由可不传`showLink: true`,默认显示
# 2.8.5(2022-1-21) # 2.8.5(2022-1-21)
### 🎫 Feat ### 🎫 Feat

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2021 啝裳 Copyright (c) 2022 啝裳
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

121
build/plugins.ts Normal file
View File

@ -0,0 +1,121 @@
import vue from "@vitejs/plugin-vue";
import svgLoader from "vite-svg-loader";
import legacy from "@vitejs/plugin-legacy";
import vueJsx from "@vitejs/plugin-vue-jsx";
import WindiCSS from "vite-plugin-windicss";
import { viteMockServe } from "vite-plugin-mock";
import liveReload from "vite-plugin-live-reload";
import styleImport from "vite-plugin-style-import";
import ElementPlus from "unplugin-element-plus/vite";
import { visualizer } from "rollup-plugin-visualizer";
import removeConsole from "vite-plugin-remove-console";
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
export function getPluginsList(command, VITE_LEGACY) {
const prodMock = true;
const lifecycle = process.env.npm_lifecycle_event;
return [
vue(),
// jsx、tsx语法支持
vueJsx(),
WindiCSS(),
// 线上环境删除console
removeConsole(),
// 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
liveReload(["src/layout/**/*", "src/router/**/*"]),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: [
{
scopeName: "layout-theme-default",
path: "src/layout/theme/default-vars.scss"
},
{
scopeName: "layout-theme-light",
path: "src/layout/theme/light-vars.scss"
},
{
scopeName: "layout-theme-dusk",
path: "src/layout/theme/dusk-vars.scss"
},
{
scopeName: "layout-theme-volcano",
path: "src/layout/theme/volcano-vars.scss"
},
{
scopeName: "layout-theme-yellow",
path: "src/layout/theme/yellow-vars.scss"
},
{
scopeName: "layout-theme-mingQing",
path: "src/layout/theme/mingQing-vars.scss"
},
{
scopeName: "layout-theme-auroraGreen",
path: "src/layout/theme/auroraGreen-vars.scss"
},
{
scopeName: "layout-theme-pink",
path: "src/layout/theme/pink-vars.scss"
},
{
scopeName: "layout-theme-saucePurple",
path: "src/layout/theme/saucePurple-vars.scss"
}
],
// 默认取 multipleScopeVars[0].scopeName
defaultScopeName: "",
// 在生产模式是否抽取独立的主题css文件extract为true以下属性有效
extract: true,
// 独立主题css文件的输出路径默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
outputDir: "",
// 会选取defaultScopeName对应的主题css文件在html添加link
themeLinkTagId: "head",
// "head"||"head-prepend" || "body" ||"body-prepend"
themeLinkTagInjectTo: "head",
// 是否对抽取的css文件内对应scopeName的权重类名移除
removeCssScopeName: false,
// 可以自定义css文件名称的函数
customThemeCssFileName: scopeName => scopeName
}
}),
// svg组件化支持
svgLoader(),
// 按需加载vxe-table
styleImport({
libs: [
{
libraryName: "vxe-table",
esModule: true,
ensureStyleFile: true,
resolveComponent: name => `vxe-table/es/${name}`,
resolveStyle: name => `vxe-table/es/${name}/style.css`
}
]
}),
ElementPlus({}),
// mock支持
viteMockServe({
mockPath: "mock",
localEnabled: command === "serve",
prodEnabled: command !== "serve" && prodMock,
injectCode: `
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer();
`,
logger: true
}),
// 是否为打包后的文件提供传统浏览器兼容性支持
VITE_LEGACY
? legacy({
targets: ["ie >= 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
})
: null,
// 打包分析
lifecycle === "report"
? visualizer({ open: true, brotliSize: true, filename: "report.html" })
: null
];
}

View File

@ -3,7 +3,6 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<link rel="stylesheet" href="/iconfont.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vue-pure-admin</title> <title>vue-pure-admin</title>
<script src="/sortable.min.js"></script> <script src="/sortable.min.js"></script>

View File

@ -10,7 +10,6 @@ const systemRouter = {
icon: "setting", icon: "setting",
title: "menus.hssysManagement", title: "menus.hssysManagement",
i18n: true, i18n: true,
showLink: true,
rank: 6 rank: 6
}, },
children: [ children: [
@ -19,8 +18,7 @@ const systemRouter = {
name: "user", name: "user",
meta: { meta: {
title: "menus.hsBaseinfo", title: "menus.hsBaseinfo",
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -29,7 +27,6 @@ const systemRouter = {
meta: { meta: {
title: "menus.hsDict", title: "menus.hsDict",
i18n: true, i18n: true,
showLink: true,
keepAlive: true keepAlive: true
} }
} }
@ -44,7 +41,6 @@ const permissionRouter = {
title: "menus.permission", title: "menus.permission",
icon: "lollipop", icon: "lollipop",
i18n: true, i18n: true,
showLink: true,
rank: 3 rank: 3
}, },
children: [ children: [
@ -53,8 +49,7 @@ const permissionRouter = {
name: "permissionPage", name: "permissionPage",
meta: { meta: {
title: "menus.permissionPage", title: "menus.permissionPage",
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -63,7 +58,6 @@ const permissionRouter = {
meta: { meta: {
title: "menus.permissionButton", title: "menus.permissionButton",
i18n: true, i18n: true,
showLink: true,
authority: [] authority: []
} }
} }
@ -78,7 +72,6 @@ const tabsRouter = {
icon: "IF-team-icontabs", icon: "IF-team-icontabs",
title: "menus.hstabs", title: "menus.hstabs",
i18n: true, i18n: true,
showLink: true,
rank: 8 rank: 8
}, },
children: [ children: [
@ -87,7 +80,6 @@ const tabsRouter = {
name: "reTabs", name: "reTabs",
meta: { meta: {
title: "menus.hstabs", title: "menus.hstabs",
showLink: true,
i18n: true i18n: true
} }
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "vue-pure-admin", "name": "vue-pure-admin",
"version": "2.8.5", "version": "2.9.0",
"private": true, "private": true,
"engines": { "engines": {
"node": ">= 16", "node": ">= 16",
@ -10,6 +10,7 @@
"dev": "cross-env --max_old_space_size=4096 vite", "dev": "cross-env --max_old_space_size=4096 vite",
"serve": "pnpm dev", "serve": "pnpm dev",
"build": "rimraf dist && cross-env vite build", "build": "rimraf dist && cross-env vite build",
"report": "rimraf dist && cross-env vite build",
"preview": "vite preview", "preview": "vite preview",
"preview:build": "pnpm build && vite preview", "preview:build": "pnpm build && vite preview",
"clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install", "clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
@ -30,14 +31,11 @@
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1", "@amap/amap-jsapi-loader": "^1.0.1",
"@ctrl/tinycolor": "^3.4.0", "@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/core": "0.7.1",
"@logicflow/extension": "0.7.1", "@logicflow/extension": "0.7.1",
"@vueuse/core": "^7.5.3", "@vueuse/core": "^7.5.5",
"@vueuse/motion": "^2.0.0-beta.9", "@vueuse/motion": "^2.0.0-beta.9",
"@vueuse/shared": "^7.5.3", "@vueuse/shared": "^7.5.5",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"axios": "^0.25.0", "axios": "^0.25.0",
"cropperjs": "^1.5.11", "cropperjs": "^1.5.11",
@ -47,22 +45,20 @@
"echarts": "^5.2.1", "echarts": "^5.2.1",
"element-plus": "1.3.0-beta.1", "element-plus": "1.3.0-beta.1",
"element-resize-detector": "^1.2.3", "element-resize-detector": "^1.2.3",
"font-awesome": "^4.7.0",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path": "^0.12.7", "path": "^0.12.7",
"pinia": "^2.0.9", "pinia": "^2.0.11",
"qs": "^6.10.1", "qs": "^6.10.1",
"remixicon": "^2.5.0",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"responsive-storage": "^1.0.11", "responsive-storage": "^1.0.11",
"rgb-hex": "^4.0.0", "rgb-hex": "^4.0.0",
"v-contextmenu": "3.0.0", "v-contextmenu": "3.0.0",
"vue": "^3.2.27", "vue": "^3.2.29",
"vue-i18n": "^9.2.0-beta.26", "vue-i18n": "^9.2.0-beta.30",
"vue-json-pretty": "^2.0.2", "vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.12", "vue-router": "^4.0.12",
"vue-types": "^4.1.1", "vue-types": "^4.1.1",
@ -76,7 +72,10 @@
"@commitlint/cli": "13.1.0", "@commitlint/cli": "13.1.0",
"@commitlint/config-conventional": "13.1.0", "@commitlint/config-conventional": "13.1.0",
"@iconify-icons/ep": "^1.1.3", "@iconify-icons/ep": "^1.1.3",
"@iconify/vue": "^3.1.2", "@iconify-icons/fa": "^1.1.1",
"@iconify-icons/fa-solid": "^1.1.2",
"@iconify-icons/ri": "^1.1.1",
"@iconify/vue": "^3.1.3",
"@types/element-resize-detector": "1.1.3", "@types/element-resize-detector": "1.1.3",
"@types/js-cookie": "^3.0.1", "@types/js-cookie": "^3.0.1",
"@types/mockjs": "1.0.3", "@types/mockjs": "1.0.3",
@ -86,12 +85,12 @@
"@typescript-eslint/eslint-plugin": "4.31.0", "@typescript-eslint/eslint-plugin": "4.31.0",
"@typescript-eslint/parser": "4.31.0", "@typescript-eslint/parser": "4.31.0",
"@vitejs/plugin-legacy": "^1.6.4", "@vitejs/plugin-legacy": "^1.6.4",
"@vitejs/plugin-vue": "^2.0.1", "@vitejs/plugin-vue": "^2.1.0",
"@vitejs/plugin-vue-jsx": "^1.3.3", "@vitejs/plugin-vue-jsx": "^1.3.3",
"@vue/eslint-config-prettier": "6.0.0", "@vue/eslint-config-prettier": "6.0.0",
"@vue/eslint-config-typescript": "7.0.0", "@vue/eslint-config-typescript": "7.0.0",
"@zougt/vite-plugin-theme-preprocessor": "^1.4.4", "@zougt/vite-plugin-theme-preprocessor": "^1.4.4",
"autoprefixer": "10.2.4", "autoprefixer": "^10.4.2",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "7.30.0", "eslint": "7.30.0",
"eslint-plugin-prettier": "3.4.0", "eslint-plugin-prettier": "3.4.0",
@ -103,8 +102,9 @@
"prettier": "2.3.2", "prettier": "2.3.2",
"pretty-quick": "3.1.1", "pretty-quick": "3.1.1",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"sass": "^1.45.0", "rollup-plugin-visualizer": "^5.5.4",
"sass-loader": "^12.3.0", "sass": "^1.49.7",
"sass-loader": "^12.4.0",
"stylelint": "13.13.1", "stylelint": "13.13.1",
"stylelint-config-prettier": "8.0.2", "stylelint-config-prettier": "8.0.2",
"stylelint-config-standard": "22.0.0", "stylelint-config-standard": "22.0.0",

1123
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +0,0 @@
@font-face {
font-family: "iconfont"; /* project id 1098500 */
src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot");
src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot?#iefix")
format("embedded-opentype"),
url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff2") format("woff2"),
url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff") format("woff"),
url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.ttf") format("truetype"),
url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.svg#iconfont") format("svg");
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@ -1,5 +1,5 @@
{ {
"Version": "2.8.5", "Version": "2.9.0",
"Title": "PureAdmin", "Title": "PureAdmin",
"FixedHeader": true, "FixedHeader": true,
"HiddenSideBar": false, "HiddenSideBar": false,

View File

@ -1,154 +1,13 @@
import { h, App, defineComponent } from "vue";
import icon from "./src/Icon.vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import iconifyIconOffline from "./src/iconifyIconOffline"; import iconifyIconOffline from "./src/iconifyIconOffline";
import iconifyIconOnline from "./src/iconifyIconOnline"; import iconifyIconOnline from "./src/iconifyIconOnline";
import fontIcon from "./src/iconfont";
/**
* 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",
data() {
return { icon, property };
},
components: { FontAwesomeIcon },
render() {
return h(
FontAwesomeIcon,
{
icon: `${this.icon}`,
[property]: true
},
{
default: () => []
}
);
}
});
} else if (type === "fa") {
return defineComponent({
name: "faIcon",
data() {
return { icon: `fa ${icon}` };
},
render() {
return h(
"i",
{
class: `${this.icon}`
},
{
default: () => []
}
);
}
});
} else if (type === "IF") {
return defineComponent({
name: "IfIcon",
data() {
return { icon: `iconfont ${icon}` };
},
render() {
return h(
"i",
{
class: `${this.icon}`
},
{
default: () => []
}
);
}
});
} else if (type === "RI") {
return defineComponent({
name: "RiIcon",
data() {
return { icon: `ri-${icon}` };
},
render() {
return h(
"i",
{
class: `${this.icon}`
},
{
default: () => []
}
);
}
});
} else if (type === "EL") {
return defineComponent({
name: "ElIcon",
data() {
return { icon };
},
render() {
return h(
IconifyIconOffline,
{
icon: `${this.icon}`
},
{
default: () => []
}
);
}
});
} else if (type === "SVG") {
return icon;
}
}
export const Icon = Object.assign(icon, {
install(app: App) {
app.component(icon.name, icon);
}
});
export const IconifyIconOffline = iconifyIconOffline; export const IconifyIconOffline = iconifyIconOffline;
export const IconifyIconOnline = iconifyIconOnline; export const IconifyIconOnline = iconifyIconOnline;
export const FontIcon = fontIcon;
export default { export default {
Icon,
IconifyIconOffline, IconifyIconOffline,
IconifyIconOnline IconifyIconOnline,
FontIcon
}; };

View File

@ -1,97 +0,0 @@
<script lang="ts">
export default {
name: "Icon"
};
</script>
<script setup lang="ts">
import { ref, computed } from "vue";
const props = defineProps({
content: {
type: String,
default: ""
},
size: {
type: Number,
default: 18
},
width: {
type: Number,
default: 20
},
height: {
type: Number,
default: 20
},
color: {
type: String,
default: ""
},
svg: {
type: Boolean,
default: false
}
});
const emit = defineEmits<{
(e: "click"): void;
}>();
let text = ref("");
let className = computed(() => {
if (props.content.indexOf("fa-") > -1) {
return props.content.indexOf("fa ") === 0
? props.content
: ["fa", props.content];
} else if (props.content.indexOf("el-icon-") > -1) {
return props.content;
} else if (props.content.indexOf("#") > -1) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
text.value = props.content;
return "iconfont";
} else {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
text.value = props.content;
return "";
}
});
let iconStyle = computed(() => {
return (
"font-size: " +
props.size +
"px; color: " +
props.color +
"; width: " +
props.width +
"px; height: " +
props.height +
"px; font-style: normal;"
);
});
const clickHandle = () => {
emit("click");
};
</script>
<template>
<i
v-if="!props.svg"
:class="className"
:style="iconStyle"
v-html="text"
@click="clickHandle"
></i>
<svg
class="icon-svg"
v-if="props.svg"
aria-hidden="true"
:style="iconStyle"
@click="clickHandle"
>
<use :xlink:href="`#${props.content}`" />
</svg>
</template>

View File

@ -0,0 +1,39 @@
import { h, defineComponent, Component } from "vue";
import { IconifyIconOffline, FontIcon } from "../index";
// 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg
export function useRenderIcon(icon: string): Component {
// iconfont
const ifReg = /^IF-/;
// typeof icon === "function" 属于SVG
if (ifReg.test(icon)) {
// iconfont
const name = icon.split(ifReg)[1];
const iconName = name.slice(
0,
name.indexOf(" ") == -1 ? name.length : name.indexOf(" ")
);
const iconType = name.slice(name.indexOf(" ") + 1, name.length);
return defineComponent({
name: "FontIcon",
render() {
return h(FontIcon, {
icon: iconName,
iconType
});
}
});
} else if (typeof icon === "function") {
// svg
return icon;
} else {
return defineComponent({
name: "Icon",
render() {
return h(IconifyIconOffline, {
icon: icon
});
}
});
}
}

View File

@ -0,0 +1,48 @@
import { h, defineComponent } from "vue";
// 封装iconfont组件默认`font-class`引用模式,支持`unicode`引用、`font-class`引用、`symbol`引用 https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.20&helptype=code
export default defineComponent({
name: "fontIcon",
props: {
icon: {
type: String,
default: ""
}
},
render() {
const attrs = this.$attrs;
if (Object.keys(attrs).includes("uni") || attrs?.iconType === "uni") {
return h(
"i",
{
class: "iconfont",
...attrs
},
this.icon
);
} else if (
Object.keys(attrs).includes("svg") ||
attrs?.iconType === "svg"
) {
return h(
"svg",
{
class: "icon-svg",
"aria-hidden": true
},
{
default: () => [
h("use", {
"xlink:href": `#${this.icon}`
})
]
}
);
} else {
return h("i", {
class: `iconfont ${this.icon}`,
...attrs
});
}
}
});

View File

@ -1,5 +1,7 @@
import { h, defineComponent } from "vue"; import { h, defineComponent } from "vue";
import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline"; import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline";
// element-plus icon
import Check from "@iconify-icons/ep/check"; import Check from "@iconify-icons/ep/check";
import Menu from "@iconify-icons/ep/menu"; import Menu from "@iconify-icons/ep/menu";
import HomeFilled from "@iconify-icons/ep/home-filled"; import HomeFilled from "@iconify-icons/ep/home-filled";
@ -45,8 +47,25 @@ addIcon("tickets", Tickets);
addIcon("office-building", OfficeBuilding); addIcon("office-building", OfficeBuilding);
addIcon("notebook", Notebook); addIcon("notebook", Notebook);
// Iconify Icon在Vue里离线使用用于内网环境 // remixicon
// https://docs.iconify.design/icon-components/vue/offline.html import arrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
import arrowLeftSLine from "@iconify-icons/ri/arrow-left-s-line";
import logoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
import nodeTree from "@iconify-icons/ri/node-tree";
addIcon("arrow-right-s-line", arrowRightSLine);
addIcon("arrow-left-s-line", arrowLeftSLine);
addIcon("logout-circle-r-line", logoutCircleRLine);
addIcon("node-tree", nodeTree);
// Font Awesome 4
import faUser from "@iconify-icons/fa/user";
import faLock from "@iconify-icons/fa/lock";
import faSignOut from "@iconify-icons/fa/sign-out";
addIcon("fa-user", faUser);
addIcon("fa-lock", faLock);
addIcon("fa-sign-out", faSignOut);
// Iconify Icon在Vue里离线使用用于内网环境https://docs.iconify.design/icon-components/vue/offline.html
export default defineComponent({ export default defineComponent({
name: "IconifyIcon", name: "IconifyIcon",
components: { IconifyIcon }, components: { IconifyIcon },
@ -57,10 +76,12 @@ export default defineComponent({
} }
}, },
render() { render() {
const attrs = this.$attrs;
return h( return h(
IconifyIcon, IconifyIcon,
{ {
icon: `${this.icon}` icon: `${this.icon}`,
...attrs
}, },
{ {
default: () => [] default: () => []

View File

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

View File

@ -120,8 +120,10 @@ function translationEn() {
<template #dropdown> <template #dropdown>
<el-dropdown-menu class="logout"> <el-dropdown-menu class="logout">
<el-dropdown-item @click="logout"> <el-dropdown-item @click="logout">
<i class="ri-logout-circle-r-line"></i <IconifyIconOffline
>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item icon="logout-circle-r-line"
style="margin: 5px"
/>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>

View File

@ -108,7 +108,7 @@ export const noticesData: TabItem[] = [
{ {
avatar: "", avatar: "",
title: "任务名称", title: "任务名称",
description: "任务需要在 2021-11-16 20:00 前启动", description: "任务需要在 2022-11-16 20:00 前启动",
datetime: "", datetime: "",
extra: "未开始", extra: "未开始",
status: "info", status: "info",
@ -118,7 +118,7 @@ export const noticesData: TabItem[] = [
avatar: "", avatar: "",
title: "第三方紧急代码变更", title: "第三方紧急代码变更",
description: description:
"一拳提交于 2021-11-16需在 2021-11-18 前完成代码变更任务", "一拳提交于 2022-11-16需在 2022-11-18 前完成代码变更任务",
datetime: "", datetime: "",
extra: "马上到期", extra: "马上到期",
status: "danger", status: "danger",
@ -127,7 +127,7 @@ export const noticesData: TabItem[] = [
{ {
avatar: "", avatar: "",
title: "信息安全考试", title: "信息安全考试",
description: "指派小仙于 2021-12-12 前完成更新并发布", description: "指派小仙于 2022-12-12 前完成更新并发布",
datetime: "", datetime: "",
extra: "已耗时 8 天", extra: "已耗时 8 天",
status: "warning", status: "warning",

View File

@ -5,18 +5,14 @@ const { isFullscreen, toggle } = useFullscreen();
<template> <template>
<div class="screen-full" @click="toggle"> <div class="screen-full" @click="toggle">
<i <FontIcon
:title=" :title="
isFullscreen isFullscreen
? $t('buttons.hsexitfullscreen') ? $t('buttons.hsexitfullscreen')
: $t('buttons.hsfullscreen') : $t('buttons.hsfullscreen')
" "
:class=" :icon="isFullscreen ? 'team-iconexit-fullscreen' : 'team-iconfullscreen'"
isFullscreen />
? 'iconfont team-iconexit-fullscreen'
: 'iconfont team-iconfullscreen'
"
></i>
</div> </div>
</template> </template>

View File

@ -157,8 +157,7 @@ function onReset() {
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
icon: "home-filled", icon: "home-filled",
i18n: true, i18n: true
showLink: true
} }
} }
]); ]);
@ -437,7 +436,12 @@ nextTick(() => {
style="width: 90%; margin: 24px 15px" style="width: 90%; margin: 24px 15px"
@click="onReset" @click="onReset"
> >
<i class="fa fa-sign-out"></i> <IconifyIconOffline
icon="fa-sign-out"
width="15"
height="15"
style="margin-right: 4px"
/>
清空缓存并返回登录页</el-button 清空缓存并返回登录页</el-button
> >
</panel> </panel>

View File

@ -13,11 +13,9 @@ import Notice from "../notice/index.vue";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
import SidebarItem from "./sidebarItem.vue"; import SidebarItem from "./sidebarItem.vue";
import avatars from "/@/assets/avatars.jpg"; import avatars from "/@/assets/avatars.jpg";
import { algorithm } from "/@/utils/algorithm";
import screenfull from "../screenfull/index.vue"; import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage"; import { storageSession } from "/@/utils/storage";
import Icon from "/@/components/ReIcon/src/Icon.vue";
import { deviceDetection } from "/@/utils/deviceDetection"; import { deviceDetection } from "/@/utils/deviceDetection";
import { usePermissionStoreHook } from "/@/store/modules/permission"; import { usePermissionStoreHook } from "/@/store/modules/permission";
import globalization from "/@/assets/svg/globalization.svg?component"; import globalization from "/@/assets/svg/globalization.svg?component";
@ -92,7 +90,7 @@ const menuSelect = (indexPath: string): void => {
} }
}); });
} }
findCurrentRoute(algorithm.increaseIndexes(routers)); findCurrentRoute(routers);
}; };
function backHome() { function backHome() {
@ -128,7 +126,11 @@ onMounted(() => {
<template> <template>
<div class="horizontal-header"> <div class="horizontal-header">
<div class="horizontal-header-left" @click="backHome"> <div class="horizontal-header-left" @click="backHome">
<Icon svg :width="35" :height="35" content="team-iconlogo" /> <FontIcon
icon="team-iconlogo"
svg
style="width: 35px; height: 35px"
></FontIcon>
<h4>{{ title }}</h4> <h4>{{ title }}</h4>
</div> </div>
<el-menu <el-menu
@ -183,8 +185,11 @@ onMounted(() => {
<template #dropdown> <template #dropdown>
<el-dropdown-menu class="logout"> <el-dropdown-menu class="logout">
<el-dropdown-item @click="logout"> <el-dropdown-item @click="logout">
<i class="ri-logout-circle-r-line"></i <IconifyIconOffline
>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item icon="logout-circle-r-line"
style="margin: 5px"
/>
{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
> >
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { getCurrentInstance } from "vue"; import { getCurrentInstance } from "vue";
import Icon from "/@/components/ReIcon/src/Icon.vue";
const props = defineProps({ const props = defineProps({
collapse: Boolean collapse: Boolean
}); });
@ -19,7 +18,11 @@ const title =
class="sidebar-logo-link" class="sidebar-logo-link"
to="/" to="/"
> >
<Icon svg :width="35" :height="35" content="team-iconlogo" /> <FontIcon
icon="team-iconlogo"
svg
style="width: 35px; height: 35px"
></FontIcon>
<span class="sidebar-title">{{ title }}</span> <span class="sidebar-title">{{ title }}</span>
</router-link> </router-link>
<router-link <router-link
@ -29,7 +32,11 @@ const title =
class="sidebar-logo-link" class="sidebar-logo-link"
to="/" to="/"
> >
<Icon svg :width="35" :height="35" content="team-iconlogo" /> <FontIcon
icon="team-iconlogo"
svg
style="width: 35px; height: 35px"
></FontIcon>
<span class="sidebar-title">{{ title }}</span> <span class="sidebar-title">{{ title }}</span>
</router-link> </router-link>
</transition> </transition>

View File

@ -10,9 +10,8 @@ import {
import path from "path"; import path from "path";
import { childrenType } from "../../types"; import { childrenType } from "../../types";
import { transformI18n } from "/@/plugins/i18n"; import { transformI18n } from "/@/plugins/i18n";
import { findIconReg } from "/@/components/ReIcon";
import Icon from "/@/components/ReIcon/src/Icon.vue";
import { useAppStoreHook } from "/@/store/modules/app"; import { useAppStoreHook } from "/@/store/modules/app";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
const instance = getCurrentInstance().appContext.app.config.globalProperties; const instance = getCurrentInstance().appContext.app.config.globalProperties;
const menuMode = instance.$storage.layout?.layout === "vertical"; const menuMode = instance.$storage.layout?.layout === "vertical";
@ -32,6 +31,19 @@ const props = defineProps({
} }
}); });
const getExtraIconStyle = computed((): CSSProperties => {
if (useAppStoreHook().getSidebarStatus) {
return {
position: "absolute",
right: "10px"
};
} else {
return {
position: "static"
};
}
});
const getNoDropdownStyle = computed((): CSSProperties => { const getNoDropdownStyle = computed((): CSSProperties => {
return { return {
display: "flex", display: "flex",
@ -143,7 +155,7 @@ function resolvePath(routePath) {
<el-icon v-show="props.item.meta.icon"> <el-icon v-show="props.item.meta.icon">
<component <component
:is=" :is="
findIconReg( useRenderIcon(
onlyOneChild.meta.icon || onlyOneChild.meta.icon ||
(props.item.meta && props.item.meta.icon) (props.item.meta && props.item.meta.icon)
) )
@ -176,11 +188,14 @@ function resolvePath(routePath) {
}} }}
</span> </span>
</el-tooltip> </el-tooltip>
<Icon <FontIcon
v-if="onlyOneChild.meta.extraIcon" v-if="onlyOneChild.meta.extraIcon"
width="30px"
height="30px"
:style="getExtraIconStyle"
:icon="onlyOneChild.meta.extraIcon.name"
:svg="onlyOneChild.meta.extraIcon.svg ? true : false" :svg="onlyOneChild.meta.extraIcon.svg ? true : false"
:content="`${onlyOneChild.meta.extraIcon.name}`" ></FontIcon>
/>
</div> </div>
</template> </template>
</el-menu-item> </el-menu-item>
@ -195,7 +210,7 @@ function resolvePath(routePath) {
<template #title> <template #title>
<el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon"> <el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon">
<component <component
:is="findIconReg(props.item.meta && props.item.meta.icon)" :is="useRenderIcon(props.item.meta && props.item.meta.icon)"
></component> ></component>
</el-icon> </el-icon>
<span v-if="!menuMode">{{ <span v-if="!menuMode">{{
@ -220,11 +235,14 @@ function resolvePath(routePath) {
</span> </span>
</div> </div>
</el-tooltip> </el-tooltip>
<Icon <FontIcon
v-if="props.item.meta.extraIcon" v-if="props.item.meta.extraIcon"
width="30px"
height="30px"
style="position: absolute; right: 10px"
:icon="props.item.meta.extraIcon.name"
:svg="props.item.meta.extraIcon.svg ? true : false" :svg="props.item.meta.extraIcon.svg ? true : false"
:content="`${props.item.meta.extraIcon.name}`" ></FontIcon>
/>
</template> </template>
<sidebar-item <sidebar-item
v-for="child in props.item.children" v-for="child in props.item.children"

View File

@ -2,7 +2,6 @@
import Logo from "./logo.vue"; import Logo from "./logo.vue";
import { emitter } from "/@/utils/mitt"; import { emitter } from "/@/utils/mitt";
import SidebarItem from "./sidebarItem.vue"; import SidebarItem from "./sidebarItem.vue";
import { algorithm } from "/@/utils/algorithm";
import { storageLocal } from "/@/utils/storage"; import { storageLocal } from "/@/utils/storage";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { computed, ref, onBeforeMount } from "vue"; import { computed, ref, onBeforeMount } from "vue";
@ -48,7 +47,7 @@ const menuSelect = (indexPath: string): void => {
} }
}); });
} }
findCurrentRoute(algorithm.increaseIndexes(router)); findCurrentRoute(router);
}; };
onBeforeMount(() => { onBeforeMount(() => {

View File

@ -253,13 +253,23 @@
} }
} }
.ri-arrow-left-s-line { .arrow-left,
.arrow-right {
width: 40px; width: 40px;
height: 38px; height: 38px;
line-height: 38px;
text-align: center;
font-size: 20px;
color: #00000073; color: #00000073;
position: relative;
svg {
width: 20px;
height: 20px;
position: absolute;
left: 50%;
transform: translate(-50%, 50%);
}
}
.arrow-left {
box-shadow: 5px 0 5px -6px #ccc; box-shadow: 5px 0 5px -6px #ccc;
&:hover { &:hover {
@ -267,15 +277,9 @@
} }
} }
.ri-arrow-right-s-line { .arrow-right {
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; box-shadow: -5px 0 5px -6px #ccc;
border-right: 1px solid #ccc;
&:hover { &:hover {
cursor: e-resize; cursor: e-resize;

View File

@ -40,11 +40,11 @@ const activeIndex = ref<number>(-1);
let refreshButton = "refresh-button"; let refreshButton = "refresh-button";
const instance = getCurrentInstance(); const instance = getCurrentInstance();
const pureSetting = useSettingStoreHook(); const pureSetting = useSettingStoreHook();
const showTags = ref(storageLocal.getItem("tagsVal") || false);
const tabDom = templateRef<HTMLElement | null>("tabDom", null); const tabDom = templateRef<HTMLElement | null>("tabDom", null);
const containerDom = templateRef<HTMLElement | null>("containerDom", null); const containerDom = templateRef<HTMLElement | null>("containerDom", null);
const scrollbarDom = templateRef<HTMLElement | null>("scrollbarDom", null); const scrollbarDom = templateRef<HTMLElement | null>("scrollbarDom", null);
const showTags =
ref(storageLocal.getItem("responsive-configure").hideTabs) ?? "false";
let multiTags: ComputedRef<Array<RouteConfigs>> = computed(() => { let multiTags: ComputedRef<Array<RouteConfigs>> = computed(() => {
return useMultiTagsStoreHook()?.multiTags; return useMultiTagsStoreHook()?.multiTags;
}); });
@ -129,14 +129,14 @@ const moveToView = (index: number): void => {
return; return;
} }
const tabItemEl = instance.refs["dynamic" + index][0]; const tabItemEl = instance.refs["dynamic" + index][0];
const tabItemElOffsetLeft = (tabItemEl as HTMLElement).offsetLeft; const tabItemElOffsetLeft = (tabItemEl as HTMLElement)?.offsetLeft;
const tabItemOffsetWidth = (tabItemEl as HTMLElement).offsetWidth; const tabItemOffsetWidth = (tabItemEl as HTMLElement)?.offsetWidth;
// //
const scrollbarDomWidth = scrollbarDom.value const scrollbarDomWidth = scrollbarDom.value
? scrollbarDom.value.offsetWidth ? scrollbarDom.value?.offsetWidth
: 0; : 0;
// //
const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0; const tabDomWidth = tabDom.value ? tabDom.value?.offsetWidth : 0;
if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) { if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) {
translateX.value = 0; translateX.value = 0;
@ -314,8 +314,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
i18n: true, i18n: true,
icon: "el-icon-s-home", icon: "home-filled"
showLink: true
} }
}, },
obj obj
@ -470,7 +469,6 @@ function showMenuModel(
* currentIndex为1时左侧的菜单是首页则不显示关闭左侧标签页 * currentIndex为1时左侧的菜单是首页则不显示关闭左侧标签页
* 如果currentIndex等于routeLength-1右侧没有菜单则不显示关闭右侧标签页 * 如果currentIndex等于routeLength-1右侧没有菜单则不显示关闭右侧标签页
*/ */
if (currentIndex === 1 && routeLength !== 2) { if (currentIndex === 1 && routeLength !== 2) {
// //
tagsViews[2].show = false; tagsViews[2].show = false;
@ -631,7 +629,9 @@ const getContextMenuStyle = computed((): CSSProperties => {
<template> <template>
<div ref="containerDom" class="tags-view" v-if="!showTags"> <div ref="containerDom" class="tags-view" v-if="!showTags">
<i class="ri-arrow-left-s-line" @click="handleScroll(200)"></i> <div class="arrow-left">
<IconifyIconOffline icon="arrow-left-s-line" @click="handleScroll(200)" />
</div>
<div ref="scrollbarDom" class="scroll-container"> <div ref="scrollbarDom" class="scroll-container">
<div class="tab" ref="tabDom" :style="getTabStyle"> <div class="tab" ref="tabDom" :style="getTabStyle">
<div <div
@ -671,7 +671,12 @@ const getContextMenuStyle = computed((): CSSProperties => {
</div> </div>
</div> </div>
</div> </div>
<i class="ri-arrow-right-s-line" @click="handleScroll(-200)"></i> <span class="arrow-right">
<IconifyIconOffline
icon="arrow-right-s-line"
@click="handleScroll(-200)"
/>
</span>
<!-- 右键菜单按钮 --> <!-- 右键菜单按钮 -->
<transition name="el-zoom-in-top"> <transition name="el-zoom-in-top">
<ul <ul

View File

@ -1,6 +1,6 @@
/* 动态改变element-plus主题色 */ /* 动态改变element-plus主题色 */
import rgbHex from "rgb-hex"; import rgbHex from "rgb-hex";
import color from "css-color-function"; import { convert } from "css-color-function";
import { TinyColor } from "@ctrl/tinycolor"; import { TinyColor } from "@ctrl/tinycolor";
import epCss from "element-plus/dist/index.css"; import epCss from "element-plus/dist/index.css";
@ -48,7 +48,7 @@ export const createColors = (primary: string) => {
}; };
Object.keys(formula).forEach(key => { Object.keys(formula).forEach(key => {
const value = formula[key].replace(/primary/, primary); const value = formula[key].replace(/primary/, primary);
colors[key] = "#" + rgbHex(color.convert(value)); colors[key] = "#" + rgbHex(convert(value));
}); });
return colors; return colors;
}; };

View File

@ -6,8 +6,7 @@ export const routerArrays: Array<RouteConfigs> = [
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
i18n: true, i18n: true,
icon: "home-filled", icon: "home-filled"
showLink: true
} }
} }
]; ];

View File

@ -6,7 +6,6 @@ import { createApp, Directive } from "vue";
import { usI18n } from "../src/plugins/i18n"; import { usI18n } from "../src/plugins/i18n";
import { MotionPlugin } from "@vueuse/motion"; import { MotionPlugin } from "@vueuse/motion";
import { useTable } from "../src/plugins/vxe-table"; import { useTable } from "../src/plugins/vxe-table";
import { useFontawesome } from "../src/plugins/fontawesome";
import { useElementPlus } from "../src/plugins/element-plus"; import { useElementPlus } from "../src/plugins/element-plus";
import { injectResponsiveStorage } from "/@/utils/storage/responsive"; import { injectResponsiveStorage } from "/@/utils/storage/responsive";
@ -28,9 +27,14 @@ Object.keys(directives).forEach(key => {
}); });
// 全局注册`@iconify/vue`图标库 // 全局注册`@iconify/vue`图标库
import { IconifyIconOffline, IconifyIconOnline } from "./components/ReIcon"; import {
IconifyIconOffline,
IconifyIconOnline,
FontIcon
} from "./components/ReIcon";
app.component("IconifyIconOffline", IconifyIconOffline); app.component("IconifyIconOffline", IconifyIconOffline);
app.component("IconifyIconOnline", IconifyIconOnline); app.component("IconifyIconOnline", IconifyIconOnline);
app.component("FontIcon", FontIcon);
getServerConfig(app).then(async config => { getServerConfig(app).then(async config => {
injectResponsiveStorage(app, config); injectResponsiveStorage(app, config);
@ -40,8 +44,7 @@ getServerConfig(app).then(async config => {
.use(MotionPlugin) .use(MotionPlugin)
.use(useElementPlus) .use(useElementPlus)
.use(useTable) .use(useTable)
.use(usI18n) .use(usI18n);
.use(useFontawesome);
await router.isReady(); await router.isReady();
app.mount("#app"); app.mount("#app");
}); });

View File

@ -1,21 +0,0 @@
/** fontawesome45
* 4版本: www.fontawesome.com.cn/faicons/
* 5https://fontawesome.com/v5.15/icons?d=gallery&p=2&m=free
* https://github.com/FortAwesome/vue-fontawesome
*/
import { App } from "vue";
import "font-awesome/css/font-awesome.css";
import { library } from "@fortawesome/fontawesome-svg-core";
import {
faUserSecret,
faCoffee,
faSpinner
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
// github.com/Remix-Design/RemixIcon/blob/master/README_CN.md#%E5%AE%89%E8%A3%85%E5%BC%95%E5%85%A5
import "remixicon/fonts/remixicon.css";
export function useFontawesome(app: App) {
library.add(faUserSecret, faCoffee, faSpinner);
app.component("font-awesome-icon", FontAwesomeIcon);
}

View File

@ -10,7 +10,6 @@ const componentsRouter = {
icon: "menu", icon: "menu",
title: $t("menus.hscomponents"), title: $t("menus.hscomponents"),
i18n: true, i18n: true,
showLink: true,
rank: 4 rank: 4
}, },
children: [ children: [
@ -20,7 +19,6 @@ const componentsRouter = {
component: () => import("/@/views/components/video/index.vue"), component: () => import("/@/views/components/video/index.vue"),
meta: { meta: {
title: $t("menus.hsvideo"), title: $t("menus.hsvideo"),
showLink: true,
i18n: true i18n: true
} }
}, },
@ -30,7 +28,6 @@ const componentsRouter = {
component: () => import("/@/views/components/map/index.vue"), component: () => import("/@/views/components/map/index.vue"),
meta: { meta: {
title: $t("menus.hsmap"), title: $t("menus.hsmap"),
showLink: true,
keepAlive: true, keepAlive: true,
i18n: true, i18n: true,
transition: { transition: {
@ -44,7 +41,6 @@ const componentsRouter = {
component: () => import("/@/views/components/draggable/index.vue"), component: () => import("/@/views/components/draggable/index.vue"),
meta: { meta: {
title: $t("menus.hsdraggable"), title: $t("menus.hsdraggable"),
showLink: true,
i18n: true, i18n: true,
transition: { transition: {
enterTransition: "animate__zoomIn", enterTransition: "animate__zoomIn",
@ -59,7 +55,6 @@ const componentsRouter = {
component: () => import("/@/views/components/split-pane/index.vue"), component: () => import("/@/views/components/split-pane/index.vue"),
meta: { meta: {
title: $t("menus.hssplitPane"), title: $t("menus.hssplitPane"),
showLink: true,
i18n: true, i18n: true,
extraIcon: { extraIcon: {
svg: true, svg: true,
@ -73,8 +68,7 @@ const componentsRouter = {
component: () => import("/@/views/components/button/index.vue"), component: () => import("/@/views/components/button/index.vue"),
meta: { meta: {
title: $t("menus.hsbutton"), title: $t("menus.hsbutton"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -83,8 +77,7 @@ const componentsRouter = {
component: () => import("/@/views/components/cropping/index.vue"), component: () => import("/@/views/components/cropping/index.vue"),
meta: { meta: {
title: $t("menus.hscropping"), title: $t("menus.hscropping"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -93,8 +86,7 @@ const componentsRouter = {
component: () => import("/@/views/components/count-to/index.vue"), component: () => import("/@/views/components/count-to/index.vue"),
meta: { meta: {
title: $t("menus.hscountTo"), title: $t("menus.hscountTo"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -103,8 +95,7 @@ const componentsRouter = {
component: () => import("/@/views/components/selector/index.vue"), component: () => import("/@/views/components/selector/index.vue"),
meta: { meta: {
title: $t("menus.hsselector"), title: $t("menus.hsselector"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -113,8 +104,7 @@ const componentsRouter = {
component: () => import("/@/views/components/seamless-scroll/index.vue"), component: () => import("/@/views/components/seamless-scroll/index.vue"),
meta: { meta: {
title: $t("menus.hsseamless"), title: $t("menus.hsseamless"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -123,8 +113,7 @@ const componentsRouter = {
component: () => import("/@/views/components/contextmenu/index.vue"), component: () => import("/@/views/components/contextmenu/index.vue"),
meta: { meta: {
title: $t("menus.hscontextmenu"), title: $t("menus.hscontextmenu"),
i18n: true, i18n: true
showLink: true
} }
} }
] ]

View File

@ -10,7 +10,6 @@ const editorRouter = {
icon: "edit", icon: "edit",
title: $t("menus.hseditor"), title: $t("menus.hseditor"),
i18n: true, i18n: true,
showLink: true,
rank: 2 rank: 2
}, },
children: [ children: [
@ -20,7 +19,6 @@ const editorRouter = {
component: () => import("/@/views/editor/index.vue"), component: () => import("/@/views/editor/index.vue"),
meta: { meta: {
title: $t("menus.hseditor"), title: $t("menus.hseditor"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true, keepAlive: true,
extraIcon: { extraIcon: {

View File

@ -9,7 +9,6 @@ const errorRouter = {
meta: { meta: {
icon: "position", icon: "position",
title: $t("menus.hserror"), title: $t("menus.hserror"),
showLink: true,
i18n: true, i18n: true,
rank: 7 rank: 7
}, },
@ -20,8 +19,7 @@ const errorRouter = {
component: () => import("/@/views/error/401.vue"), component: () => import("/@/views/error/401.vue"),
meta: { meta: {
title: $t("menus.hsfourZeroOne"), title: $t("menus.hsfourZeroOne"),
i18n: true, i18n: true
showLink: true
} }
}, },
{ {
@ -30,8 +28,7 @@ const errorRouter = {
component: () => import("/@/views/error/404.vue"), component: () => import("/@/views/error/404.vue"),
meta: { meta: {
title: $t("menus.hsfourZeroFour"), title: $t("menus.hsfourZeroFour"),
i18n: true, i18n: true
showLink: true
} }
} }
] ]

View File

@ -8,7 +8,6 @@ const externalLink = {
meta: { meta: {
icon: "link", icon: "link",
title: $t("menus.externalLink"), title: $t("menus.externalLink"),
showLink: true,
i18n: true, i18n: true,
rank: 190 rank: 190
}, },
@ -17,7 +16,6 @@ const externalLink = {
path: "https://github.com/xiaoxian521/vue-pure-admin", path: "https://github.com/xiaoxian521/vue-pure-admin",
meta: { meta: {
title: $t("menus.externalLink"), title: $t("menus.externalLink"),
showLink: true,
i18n: true, i18n: true,
rank: 191 rank: 191
} }

View File

@ -9,7 +9,6 @@ const flowChartRouter = {
meta: { meta: {
icon: "set-up", icon: "set-up",
title: $t("menus.hsflowChart"), title: $t("menus.hsflowChart"),
showLink: true,
i18n: true, i18n: true,
rank: 1 rank: 1
}, },
@ -20,8 +19,7 @@ const flowChartRouter = {
component: () => import("/@/views/flow-chart/index.vue"), component: () => import("/@/views/flow-chart/index.vue"),
meta: { meta: {
title: $t("menus.hsflowChart"), title: $t("menus.hsflowChart"),
i18n: true, i18n: true
showLink: true
} }
} }
] ]

View File

@ -10,7 +10,6 @@ const guideRouter = {
icon: "guide", icon: "guide",
title: $t("menus.hsguide"), title: $t("menus.hsguide"),
i18n: true, i18n: true,
showLink: true,
rank: 10 rank: 10
}, },
children: [ children: [
@ -20,7 +19,6 @@ const guideRouter = {
component: () => import("/@/views/guide/index.vue"), component: () => import("/@/views/guide/index.vue"),
meta: { meta: {
title: $t("menus.hsguide"), title: $t("menus.hsguide"),
showLink: true,
i18n: true i18n: true
} }
} }

View File

@ -9,7 +9,6 @@ const homeRouter = {
meta: { meta: {
icon: "home-filled", icon: "home-filled",
title: $t("menus.hshome"), title: $t("menus.hshome"),
showLink: true,
i18n: true, i18n: true,
rank: 0 rank: 0
}, },
@ -20,8 +19,7 @@ const homeRouter = {
component: () => import("/@/views/welcome.vue"), component: () => import("/@/views/welcome.vue"),
meta: { meta: {
title: $t("menus.hshome"), title: $t("menus.hshome"),
i18n: true, i18n: true
showLink: true
} }
} }
] ]

View File

@ -7,10 +7,9 @@ const menuTreeRouter = {
component: Layout, component: Layout,
redirect: "/menuTree/index", redirect: "/menuTree/index",
meta: { meta: {
icon: "RI-node-tree", icon: "node-tree",
title: $t("menus.hsMenuTree"), title: $t("menus.hsMenuTree"),
i18n: true, i18n: true,
showLink: true,
rank: 9 rank: 9
}, },
children: [ children: [
@ -20,7 +19,6 @@ const menuTreeRouter = {
component: () => import("/@/views/menu-tree/index.vue"), component: () => import("/@/views/menu-tree/index.vue"),
meta: { meta: {
title: $t("menus.hsMenuTree"), title: $t("menus.hsMenuTree"),
showLink: true,
i18n: true i18n: true
} }
} }

View File

@ -9,7 +9,6 @@ const nestedRouter = {
meta: { meta: {
title: $t("menus.hsmenus"), title: $t("menus.hsmenus"),
icon: "histogram", icon: "histogram",
showLink: true,
i18n: true, i18n: true,
rank: 5 rank: 5
}, },
@ -20,7 +19,6 @@ const nestedRouter = {
name: "Menu1", name: "Menu1",
meta: { meta: {
title: $t("menus.hsmenu1"), title: $t("menus.hsmenu1"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
}, },
@ -32,7 +30,6 @@ const nestedRouter = {
name: "Menu1-1", name: "Menu1-1",
meta: { meta: {
title: $t("menus.hsmenu1-1"), title: $t("menus.hsmenu1-1"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
} }
@ -44,7 +41,6 @@ const nestedRouter = {
redirect: "/nested/menu1/menu1-2/menu1-2-1", redirect: "/nested/menu1/menu1-2/menu1-2-1",
meta: { meta: {
title: $t("menus.hsmenu1-2"), title: $t("menus.hsmenu1-2"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
}, },
@ -56,7 +52,6 @@ const nestedRouter = {
name: "Menu1-2-1", name: "Menu1-2-1",
meta: { meta: {
title: $t("menus.hsmenu1-2-1"), title: $t("menus.hsmenu1-2-1"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
} }
@ -68,7 +63,6 @@ const nestedRouter = {
name: "Menu1-2-2", name: "Menu1-2-2",
meta: { meta: {
title: $t("menus.hsmenu1-2-2"), title: $t("menus.hsmenu1-2-2"),
showLink: true,
keepAlive: true, keepAlive: true,
i18n: true, i18n: true,
extraIcon: { extraIcon: {
@ -85,7 +79,6 @@ const nestedRouter = {
name: "Menu1-3", name: "Menu1-3",
meta: { meta: {
title: $t("menus.hsmenu1-3"), title: $t("menus.hsmenu1-3"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
} }
@ -98,7 +91,6 @@ const nestedRouter = {
component: () => import("/@/views/nested/menu2/index.vue"), component: () => import("/@/views/nested/menu2/index.vue"),
meta: { meta: {
title: $t("menus.hsmenu2"), title: $t("menus.hsmenu2"),
showLink: true,
i18n: true, i18n: true,
keepAlive: true keepAlive: true
} }

View File

@ -30,7 +30,7 @@ function ascending(arr: any[]) {
// 过滤meta中showLink为false的路由 // 过滤meta中showLink为false的路由
function filterTree(data: RouteComponent[]) { function filterTree(data: RouteComponent[]) {
const newTree = data.filter( const newTree = data.filter(
(v: { meta: { showLink: boolean } }) => v.meta.showLink (v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false
); );
newTree.forEach( newTree.forEach(
(v: { children }) => v.children && (v.children = filterTree(v.children)) (v: { children }) => v.children && (v.children = filterTree(v.children))

View File

@ -17,8 +17,7 @@ export const useMultiTagsStore = defineStore({
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
icon: "home-filled", icon: "home-filled",
i18n: true, i18n: true
showLink: true
} }
} }
], ],

View File

@ -60,8 +60,7 @@ export const useUserStore = defineStore({
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
icon: "home-filled", icon: "home-filled",
i18n: true, i18n: true
showLink: true
} }
} }
]); ]);

View File

@ -85,7 +85,7 @@
align-items: center; align-items: center;
} }
.icon i { .icon svg {
color: #d9d9d9; color: #d9d9d9;
transition: 0.5s; transition: 0.5s;
} }
@ -107,7 +107,7 @@
padding: 0; padding: 0;
} }
.input-group.focus .icon i { .input-group.focus .icon svg {
color: #5392f0; color: #5392f0;
} }

View File

@ -306,6 +306,10 @@
height: 48px; height: 48px;
line-height: 48px; line-height: 48px;
background: $menuBg; background: $menuBg;
svg {
position: static !important;
}
} }
.is-active > .el-sub-menu__title, .is-active > .el-sub-menu__title,
@ -600,16 +604,6 @@ body[layout="vertical"] {
} }
} }
.el-sub-menu {
overflow: hidden;
& > .el-sub-menu__title {
.el-sub-menu__icon-arrow {
display: none;
}
}
}
/* 菜单折叠 */ /* 菜单折叠 */
.el-menu--collapse { .el-menu--collapse {
.el-sub-menu { .el-sub-menu {

View File

@ -1,21 +0,0 @@
interface ProxyAlgorithm {
increaseIndexes<T>(val: Array<T>): Array<T>;
}
class algorithmProxy implements ProxyAlgorithm {
constructor() {}
// 数组每一项添加索引字段
public increaseIndexes<T>(val: Array<T>): Array<T> {
return Object.keys(val)
.map(v => {
return {
...val[v],
key: v
};
})
.filter(v => v.meta && v.meta.showLink);
}
}
export const algorithm = new algorithmProxy();

View File

@ -47,8 +47,7 @@ export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
meta: { meta: {
title: "menus.hshome", title: "menus.hshome",
i18n: true, i18n: true,
icon: "home-filled", icon: "home-filled"
showLink: true
} }
} }
] ]

View File

@ -110,7 +110,7 @@ function onPwdBlur() {
}" }"
> >
<div class="icon"> <div class="icon">
<i class="fa fa-user"></i> <IconifyIconOffline icon="fa-user" width="14" height="14" />
</div> </div>
<div> <div>
<h5>用户名</h5> <h5>用户名</h5>
@ -139,7 +139,7 @@ function onPwdBlur() {
}" }"
> >
<div class="icon"> <div class="icon">
<i class="fa fa-lock"></i> <IconifyIconOffline icon="fa-lock" width="14" height="14" />
</div> </div>
<div> <div>
<h5>密码</h5> <h5>密码</h5>

2
types/global.d.ts vendored
View File

@ -11,6 +11,7 @@ declare module "vue" {
export interface GlobalComponents { export interface GlobalComponents {
IconifyIconOffline: typeof import("../src/components/ReIcon")["IconifyIconOffline"]; IconifyIconOffline: typeof import("../src/components/ReIcon")["IconifyIconOffline"];
IconifyIconOnline: typeof import("../src/components/ReIcon")["IconifyIconOnline"]; IconifyIconOnline: typeof import("../src/components/ReIcon")["IconifyIconOnline"];
FontIcon: typeof import("../src/components/ReIcon")["FontIcon"];
} }
} }
@ -22,7 +23,6 @@ declare global {
mozCancelAnimationFrame: (handle: number) => void; mozCancelAnimationFrame: (handle: number) => void;
oCancelAnimationFrame: (handle: number) => void; oCancelAnimationFrame: (handle: number) => void;
msCancelAnimationFrame: (handle: number) => void; msCancelAnimationFrame: (handle: number) => void;
webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number; webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number;
mozRequestAnimationFrame: (callback: FrameRequestCallback) => number; mozRequestAnimationFrame: (callback: FrameRequestCallback) => number;
oRequestAnimationFrame: (callback: FrameRequestCallback) => number; oRequestAnimationFrame: (callback: FrameRequestCallback) => number;

View File

@ -1,17 +1,7 @@
import { resolve } from "path"; import { resolve } from "path";
import vue from "@vitejs/plugin-vue";
import svgLoader from "vite-svg-loader";
import legacy from "@vitejs/plugin-legacy";
import vueJsx from "@vitejs/plugin-vue-jsx";
import WindiCSS from "vite-plugin-windicss";
import { warpperEnv, regExps } from "./build"; import { warpperEnv, regExps } from "./build";
import liveReload from "vite-plugin-live-reload"; import { getPluginsList } from "./build/plugins";
import { viteMockServe } from "vite-plugin-mock";
import styleImport from "vite-plugin-style-import";
import ElementPlus from "unplugin-element-plus/vite";
import removeConsole from "vite-plugin-remove-console";
import { UserConfigExport, ConfigEnv, loadEnv } from "vite"; import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
// 当前执行node命令时文件夹的地址工作目录 // 当前执行node命令时文件夹的地址工作目录
const root: string = process.cwd(); const root: string = process.cwd();
@ -37,7 +27,6 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN,
VITE_PROXY_DOMAIN_REAL VITE_PROXY_DOMAIN_REAL
} = warpperEnv(loadEnv(mode, root)); } = warpperEnv(loadEnv(mode, root));
const prodMock = true;
return { return {
base: VITE_PUBLIC_PATH, base: VITE_PUBLIC_PATH,
root, root,
@ -81,116 +70,16 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
} }
: null : null
}, },
plugins: [ plugins: getPluginsList(command, VITE_LEGACY),
vue(),
// jsx、tsx语法支持
vueJsx(),
WindiCSS(),
// 线上环境删除console
removeConsole(),
// 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
liveReload(["src/layout/**/*"]),
// 自定义主题
themePreprocessorPlugin({
scss: {
multipleScopeVars: [
{
scopeName: "layout-theme-default",
path: pathResolve("src/layout/theme/default-vars.scss")
},
{
scopeName: "layout-theme-light",
path: pathResolve("src/layout/theme/light-vars.scss")
},
{
scopeName: "layout-theme-dusk",
path: pathResolve("src/layout/theme/dusk-vars.scss")
},
{
scopeName: "layout-theme-volcano",
path: pathResolve("src/layout/theme/volcano-vars.scss")
},
{
scopeName: "layout-theme-yellow",
path: pathResolve("src/layout/theme/yellow-vars.scss")
},
{
scopeName: "layout-theme-mingQing",
path: pathResolve("src/layout/theme/mingQing-vars.scss")
},
{
scopeName: "layout-theme-auroraGreen",
path: pathResolve("src/layout/theme/auroraGreen-vars.scss")
},
{
scopeName: "layout-theme-pink",
path: pathResolve("src/layout/theme/pink-vars.scss")
},
{
scopeName: "layout-theme-saucePurple",
path: pathResolve("src/layout/theme/saucePurple-vars.scss")
}
],
// 默认取 multipleScopeVars[0].scopeName
defaultScopeName: "",
// 在生产模式是否抽取独立的主题css文件extract为true以下属性有效
extract: true,
// 独立主题css文件的输出路径默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
outputDir: "",
// 会选取defaultScopeName对应的主题css文件在html添加link
themeLinkTagId: "head",
// "head"||"head-prepend" || "body" ||"body-prepend"
themeLinkTagInjectTo: "head",
// 是否对抽取的css文件内对应scopeName的权重类名移除
removeCssScopeName: false,
// 可以自定义css文件名称的函数
customThemeCssFileName: scopeName => scopeName
}
}),
// svg组件化支持
svgLoader(),
// 按需加载vxe-table
styleImport({
libs: [
{
libraryName: "vxe-table",
esModule: true,
ensureStyleFile: true,
resolveComponent: name => `vxe-table/es/${name}`,
resolveStyle: name => `vxe-table/es/${name}/style.css`
}
]
}),
ElementPlus({}),
// mock支持
viteMockServe({
mockPath: "mock",
localEnabled: command === "serve",
prodEnabled: command !== "serve" && prodMock,
injectCode: `
import { setupProdMockServer } from './mockProdServer';
setupProdMockServer();
`,
logger: true
}),
// 是否为打包后的文件提供传统浏览器兼容性支持
VITE_LEGACY
? legacy({
targets: ["ie >= 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
})
: null
],
optimizeDeps: { optimizeDeps: {
include: [ include: [
"pinia", "pinia",
"vue-i18n", "vue-i18n",
"lodash-es", "lodash-es",
"@vueuse/core", "@vueuse/core",
"element-plus/lib/locale/lang/zh-cn", "@iconify/vue",
"element-plus/lib/locale/lang/en", "element-plus/lib/locale/lang/en",
"vxe-table/lib/locale/lang/zh-CN", "element-plus/lib/locale/lang/zh-cn"
"vxe-table/lib/locale/lang/en-US"
], ],
exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"] exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"]
}, },