chore: 重构图标

This commit is contained in:
xiaoxian521
2022-02-05 14:45:20 +08:00
parent 3a7832b7fe
commit d943550e10
54 changed files with 453 additions and 852 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

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 iconifyIconOnline from "./src/iconifyIconOnline";
/**
* find icon component
* @param icon icon图标
* @returns component
*/
export function findIconReg(icon: string) {
// fontawesome4
const fa4Reg = /^fa-/;
// fontawesome5+
const fa5Reg = /^FA-/;
// iconfont
const iFReg = /^IF-/;
// remixicon
const riReg = /^RI-/;
// typeof icon === "function" 属于SVG
if (fa5Reg.test(icon)) {
const text = icon.split(fa5Reg)[1];
return findIcon(
text.slice(0, text.indexOf(" ") == -1 ? text.length : text.indexOf(" ")),
"FA",
text.slice(text.indexOf(" ") + 1, text.length)
);
} else if (fa4Reg.test(icon)) {
return findIcon(icon.split(fa4Reg)[1], "fa");
} else if (iFReg.test(icon)) {
return findIcon(icon.split(iFReg)[1], "IF");
} else if (typeof icon === "function") {
return findIcon(icon, "SVG");
} else if (riReg.test(icon)) {
return findIcon(icon.split(riReg)[1], "RI");
} else {
return findIcon(icon, "EL");
}
}
// 支持fontawesome、iconfont、remixicon、element-plus/icons、自定义svg
export function findIcon(icon: String, type = "EL", property?: string) {
if (type === "FA") {
return defineComponent({
name: "FaIcon",
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);
}
});
import fontIcon from "./src/iconfont";
export const IconifyIconOffline = iconifyIconOffline;
export const IconifyIconOnline = iconifyIconOnline;
export const FontIcon = fontIcon;
export default {
Icon,
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 { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline";
// element-plus icon
import Check from "@iconify-icons/ep/check";
import Menu from "@iconify-icons/ep/menu";
import HomeFilled from "@iconify-icons/ep/home-filled";
@@ -45,8 +47,23 @@ addIcon("tickets", Tickets);
addIcon("office-building", OfficeBuilding);
addIcon("notebook", Notebook);
// Iconify Icon在Vue里离线使用用于内网环境
// https://docs.iconify.design/icon-components/vue/offline.html
// remixicon
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";
addIcon("arrow-right-s-line", arrowRightSLine);
addIcon("arrow-left-s-line", arrowLeftSLine);
addIcon("logout-circle-r-line", logoutCircleRLine);
// 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({
name: "IconifyIcon",
components: { IconifyIcon },
@@ -57,10 +74,12 @@ export default defineComponent({
}
},
render() {
const attrs = this.$attrs;
return h(
IconifyIcon,
{
icon: `${this.icon}`
icon: `${this.icon}`,
...attrs
},
{
default: () => []

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,11 +13,9 @@ import Notice from "../notice/index.vue";
import { templateRef } from "@vueuse/core";
import SidebarItem from "./sidebarItem.vue";
import avatars from "/@/assets/avatars.jpg";
import { algorithm } from "/@/utils/algorithm";
import screenfull from "../screenfull/index.vue";
import { useRoute, useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage";
import Icon from "/@/components/ReIcon/src/Icon.vue";
import { deviceDetection } from "/@/utils/deviceDetection";
import { usePermissionStoreHook } from "/@/store/modules/permission";
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() {
@@ -128,7 +126,11 @@ onMounted(() => {
<template>
<div class="horizontal-header">
<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>
</div>
<el-menu
@@ -183,8 +185,11 @@ onMounted(() => {
<template #dropdown>
<el-dropdown-menu class="logout">
<el-dropdown-item @click="logout">
<i class="ri-logout-circle-r-line"></i
>{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
<IconifyIconOffline
icon="logout-circle-r-line"
style="margin: 5px"
/>
{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
>
</el-dropdown-menu>
</template>

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { getCurrentInstance } from "vue";
import Icon from "/@/components/ReIcon/src/Icon.vue";
const props = defineProps({
collapse: Boolean
});
@@ -19,7 +18,11 @@ const title =
class="sidebar-logo-link"
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>
</router-link>
<router-link
@@ -29,7 +32,11 @@ const title =
class="sidebar-logo-link"
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>
</router-link>
</transition>

View File

@@ -10,9 +10,8 @@ import {
import path from "path";
import { childrenType } from "../../types";
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 { useRenderIcon } from "/@/components/ReIcon/src/hooks";
const instance = getCurrentInstance().appContext.app.config.globalProperties;
const menuMode = instance.$storage.layout?.layout === "vertical";
@@ -143,7 +142,7 @@ function resolvePath(routePath) {
<el-icon v-show="props.item.meta.icon">
<component
:is="
findIconReg(
useRenderIcon(
onlyOneChild.meta.icon ||
(props.item.meta && props.item.meta.icon)
)
@@ -176,11 +175,11 @@ function resolvePath(routePath) {
}}
</span>
</el-tooltip>
<Icon
<FontIcon
v-if="onlyOneChild.meta.extraIcon"
:icon="onlyOneChild.meta.extraIcon.name"
:svg="onlyOneChild.meta.extraIcon.svg ? true : false"
:content="`${onlyOneChild.meta.extraIcon.name}`"
/>
></FontIcon>
</div>
</template>
</el-menu-item>
@@ -195,7 +194,7 @@ function resolvePath(routePath) {
<template #title>
<el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon">
<component
:is="findIconReg(props.item.meta && props.item.meta.icon)"
:is="useRenderIcon(props.item.meta && props.item.meta.icon)"
></component>
</el-icon>
<span v-if="!menuMode">{{
@@ -220,11 +219,11 @@ function resolvePath(routePath) {
</span>
</div>
</el-tooltip>
<Icon
<FontIcon
v-if="props.item.meta.extraIcon"
:icon="props.item.meta.extraIcon.name"
:svg="props.item.meta.extraIcon.svg ? true : false"
:content="`${props.item.meta.extraIcon.name}`"
/>
></FontIcon>
</template>
<sidebar-item
v-for="child in props.item.children"

View File

@@ -2,7 +2,6 @@
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 { computed, ref, onBeforeMount } from "vue";
@@ -48,7 +47,7 @@ const menuSelect = (indexPath: string): void => {
}
});
}
findCurrentRoute(algorithm.increaseIndexes(router));
findCurrentRoute(router);
};
onBeforeMount(() => {

View File

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

View File

@@ -40,11 +40,11 @@ const activeIndex = ref<number>(-1);
let refreshButton = "refresh-button";
const instance = getCurrentInstance();
const pureSetting = useSettingStoreHook();
const showTags = ref(storageLocal.getItem("tagsVal") || false);
const tabDom = templateRef<HTMLElement | null>("tabDom", null);
const containerDom = templateRef<HTMLElement | null>("containerDom", null);
const scrollbarDom = templateRef<HTMLElement | null>("scrollbarDom", null);
const showTags =
ref(storageLocal.getItem("responsive-configure").hideTabs) ?? "false";
let multiTags: ComputedRef<Array<RouteConfigs>> = computed(() => {
return useMultiTagsStoreHook()?.multiTags;
});
@@ -129,14 +129,14 @@ const moveToView = (index: number): void => {
return;
}
const tabItemEl = instance.refs["dynamic" + index][0];
const tabItemElOffsetLeft = (tabItemEl as HTMLElement).offsetLeft;
const tabItemOffsetWidth = (tabItemEl as HTMLElement).offsetWidth;
const tabItemElOffsetLeft = (tabItemEl as HTMLElement)?.offsetLeft;
const tabItemOffsetWidth = (tabItemEl as HTMLElement)?.offsetWidth;
// 标签页导航栏可视长度(不包含溢出部分)
const scrollbarDomWidth = scrollbarDom.value
? scrollbarDom.value.offsetWidth
? scrollbarDom.value?.offsetWidth
: 0;
// 已有标签页总长度(包含溢出部分)
const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0;
const tabDomWidth = tabDom.value ? tabDom.value?.offsetWidth : 0;
if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) {
translateX.value = 0;
@@ -314,8 +314,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
meta: {
title: "menus.hshome",
i18n: true,
icon: "el-icon-s-home",
showLink: true
icon: "home-filled"
}
},
obj
@@ -470,7 +469,6 @@ function showMenuModel(
* currentIndex为1时左侧的菜单是首页则不显示关闭左侧标签页
* 如果currentIndex等于routeLength-1右侧没有菜单则不显示关闭右侧标签页
*/
if (currentIndex === 1 && routeLength !== 2) {
// 左侧的菜单是首页,右侧存在别的菜单
tagsViews[2].show = false;
@@ -631,7 +629,9 @@ const getContextMenuStyle = computed((): CSSProperties => {
<template>
<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 class="tab" ref="tabDom" :style="getTabStyle">
<div
@@ -671,7 +671,12 @@ const getContextMenuStyle = computed((): CSSProperties => {
</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">
<ul

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,6 @@
import { App, Component } from "vue";
import {
ElTag,
ElAffix,
ElSkeleton,
ElBreadcrumb,
ElBreadcrumbItem,
ElScrollbar,
@@ -10,30 +8,21 @@ import {
ElButton,
ElCol,
ElRow,
ElSpace,
ElDivider,
ElCard,
ElDropdown,
ElDialog,
ElMenu,
ElMenuItem,
ElDropdownItem,
ElDropdownMenu,
ElIcon,
ElInput,
ElForm,
ElFormItem,
ElPopover,
ElPopper,
ElTooltip,
ElDrawer,
ElPagination,
ElAlert,
ElRadio,
ElRadioButton,
ElRadioGroup,
ElDescriptions,
ElDescriptionsItem,
ElBacktop,
ElSwitch,
ElBadge,
@@ -43,7 +32,6 @@ import {
ElEmpty,
ElCollapse,
ElCollapseItem,
ElTreeV2,
// 指令
ElLoading,
ElInfiniteScroll
@@ -54,8 +42,6 @@ const plugins = [ElLoading, ElInfiniteScroll];
const components = [
ElTag,
ElAffix,
ElSkeleton,
ElBreadcrumb,
ElBreadcrumbItem,
ElScrollbar,
@@ -63,30 +49,21 @@ const components = [
ElButton,
ElCol,
ElRow,
ElSpace,
ElDivider,
ElCard,
ElDropdown,
ElDialog,
ElMenu,
ElMenuItem,
ElDropdownItem,
ElDropdownMenu,
ElIcon,
ElInput,
ElForm,
ElFormItem,
ElPopover,
ElPopper,
ElTooltip,
ElDrawer,
ElPagination,
ElAlert,
ElRadio,
ElRadioButton,
ElRadioGroup,
ElDescriptions,
ElDescriptionsItem,
ElBacktop,
ElSwitch,
ElBadge,
@@ -95,8 +72,7 @@ const components = [
ElAvatar,
ElEmpty,
ElCollapse,
ElCollapseItem,
ElTreeV2
ElCollapseItem
];
export function useElementPlus(app: App) {

View File

@@ -1,21 +0,0 @@
/** 兼容fontawesome4和5版本
* 4版本: www.fontawesome.com.cn/faicons/
* 5版本https://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

@@ -3,23 +3,9 @@ export default {
hslogin: "Login",
hssysManagement: "System Manage",
hsBaseinfo: "Base Info",
hsDict: "Dict Manage",
hseditor: "Editor",
hserror: "Error Page",
hsfourZeroFour: "404",
hsfourZeroOne: "401",
hscomponents: "Components",
hsvideo: "Video Components",
hsmap: "Map Components",
hsdraggable: "Draggable Components",
hssplitPane: "Split Pane",
hsbutton: "Button Components",
hscropping: "Picture Cropping",
hscountTo: "Digital Animation",
hsselector: "Selector Components",
hsflowChart: "Flow Chart",
hsseamless: "Seamless Scroll",
hscontextmenu: "Context Menu",
hsmenus: "MultiLevel Menu",
hsmenu1: "Menu1",
"hsmenu1-1": "Menu1-1",
@@ -31,8 +17,5 @@ export default {
permission: "Permission Manage",
permissionPage: "Page Permission",
permissionButton: "Button Permission",
hstabs: "Tabs Operate",
hsMenuTree: "Menu Tree",
hsguide: "Guide",
externalLink: "External Link"
};

View File

@@ -3,23 +3,9 @@ export default {
hslogin: "登陆",
hssysManagement: "系统管理",
hsBaseinfo: "基础信息",
hsDict: "字典管理",
hseditor: "编辑器",
hserror: "错误页面",
hsfourZeroFour: "404",
hsfourZeroOne: "401",
hscomponents: "组件",
hsvideo: "视频组件",
hsmap: "地图组件",
hsdraggable: "拖拽组件",
hssplitPane: "切割面板",
hsbutton: "按钮组件",
hscropping: "图片裁剪",
hscountTo: "数字动画",
hsselector: "选择器组件",
hsflowChart: "流程图",
hsseamless: "无缝滚动",
hscontextmenu: "右键菜单",
hsmenus: "多级菜单",
hsmenu1: "菜单1",
"hsmenu1-1": "菜单1-1",
@@ -31,8 +17,5 @@ export default {
permission: "权限管理",
permissionPage: "页面权限",
permissionButton: "按钮权限",
hstabs: "标签页操作",
hsMenuTree: "菜单树结构",
hsguide: "引导页",
externalLink: "外链"
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

@@ -1,54 +0,0 @@
interface ProxyLoader {
loadCss(src: string): any;
loadScript(src: string): Promise<any>;
loadScriptConcurrent(src: Array<string>): Promise<any>;
}
class loaderProxy implements ProxyLoader {
constructor() {}
protected scriptLoaderCache: Array<string> = [];
public loadCss = (src: string): any => {
const element: HTMLLinkElement = document.createElement("link");
element.rel = "stylesheet";
element.href = src;
document.body.appendChild(element);
};
public loadScript = async (src: string): Promise<any> => {
if (this.scriptLoaderCache.includes(src)) {
return src;
} else {
const element: HTMLScriptElement = document.createElement("script");
element.src = src;
document.body.appendChild(element);
element.onload = () => {
return this.scriptLoaderCache.push(src);
};
}
};
public loadScriptConcurrent = async (
srcList: Array<string>
): Promise<any> => {
if (Array.isArray(srcList)) {
const len: number = srcList.length;
if (len > 0) {
let count = 0;
srcList.map(src => {
if (src) {
this.loadScript(src).then(() => {
count++;
if (count === len) {
return;
}
});
}
});
}
}
};
}
export const loader = new loaderProxy();

View File

@@ -1,35 +0,0 @@
import ResizeObserver from "resize-observer-polyfill";
const isServer = typeof window === "undefined";
const resizeHandler = (entries: any[]): void => {
for (const entry of entries) {
const listeners = entry.target.__resizeListeners__ || [];
if (listeners.length) {
listeners.forEach((fn: () => any) => {
fn();
});
}
}
};
export const addResizeListener = (element: any, fn: () => any): any => {
if (isServer) return;
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
element.__ro__ = new ResizeObserver(resizeHandler);
element.__ro__.observe(element);
}
element.__resizeListeners__.push(fn);
};
export const removeResizeListener = (element: any, fn: () => any): any => {
if (!element || !element.__resizeListeners__) return;
element.__resizeListeners__.splice(
element.__resizeListeners__.indexOf(fn),
1
);
if (!element.__resizeListeners__.length) {
element.__ro__.disconnect();
}
};

View File

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

View File

@@ -1,43 +1,15 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { ref } from "vue";
import { useRouter } from "vue-router";
import { initRouter } from "/@/router/utils";
import { storageSession } from "/@/utils/storage";
import { addClass, removeClass } from "/@/utils/operate";
import bg from "/@/assets/login/bg.png";
import avatar from "/@/assets/login/avatar.svg?component";
import illustration0 from "/@/assets/login/illustration0.svg?component";
import illustration1 from "/@/assets/login/illustration1.svg?component";
import illustration2 from "/@/assets/login/illustration2.svg?component";
import illustration3 from "/@/assets/login/illustration3.svg?component";
import illustration4 from "/@/assets/login/illustration4.svg?component";
import illustration5 from "/@/assets/login/illustration5.svg?component";
import illustration6 from "/@/assets/login/illustration6.svg?component";
import illustration from "/@/assets/login/illustration.svg?component";
const router = useRouter();
// eslint-disable-next-line vue/return-in-computed-property
const currentWeek = computed(() => {
switch (String(new Date().getDay())) {
case "0":
return illustration0;
case "1":
return illustration1;
case "2":
return illustration2;
case "3":
return illustration3;
case "4":
return illustration4;
case "5":
return illustration5;
case "6":
return illustration6;
default:
return illustration4;
}
});
let user = ref("admin");
let pwd = ref("123456");
@@ -73,7 +45,7 @@ function onPwdBlur() {
<img :src="bg" class="wave" />
<div class="login-container">
<div class="img">
<component :is="currentWeek"></component>
<illustration />
</div>
<div class="login-box">
<div class="login-form">
@@ -110,7 +82,7 @@ function onPwdBlur() {
}"
>
<div class="icon">
<i class="fa fa-user"></i>
<IconifyIconOffline icon="fa-user" width="14" height="14" />
</div>
<div>
<h5>用户名</h5>
@@ -139,7 +111,7 @@ function onPwdBlur() {
}"
>
<div class="icon">
<i class="fa fa-lock"></i>
<IconifyIconOffline icon="fa-lock" width="14" height="14" />
</div>
<div>
<h5>密码</h5>