mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-21 02:56:38 +08:00
refactor(projects): 去除vicons,统一使用iconify图标
This commit is contained in:
parent
e61ee32a88
commit
cd6db3d491
@ -8,10 +8,3 @@ export default [
|
||||
}),
|
||||
Icons()
|
||||
];
|
||||
|
||||
/**
|
||||
* iconify用法(安装对应的vscode智能提示的插件: Iconify IntelliSense)
|
||||
* 找图标:网址 https://icones.js.org/ 或者 vscode安装 icones插件
|
||||
* 确定图标名字:找到图标后复制名字 如:mdi:ab-testing 组件为: <icon-mdi:ab-testing />
|
||||
* 样式:同html标签一样直接应用style属性或者class属性; 通过设置color和font-size属性设置对应的颜色和大小
|
||||
*/
|
||||
|
24
doc/iconify使用文档.md
Normal file
24
doc/iconify使用文档.md
Normal file
@ -0,0 +1,24 @@
|
||||
iconify用法
|
||||
|
||||
一、静态用法:直接用图标的组件名称
|
||||
1.安装vscode智能提示的插件: Iconify IntelliSense
|
||||
2.找图标:网址 https://icones.js.org/ 或者 vscode安装 icones插件
|
||||
3.确定图标名字:找到图标后复制名字 如:'mdi:emoticon' 组件为: <icon-mdi:emoticon />
|
||||
4.设置样式:同html标签一样直接应用style属性或者class属性; 通过设置color和font-size属性设置对应的颜色和大小
|
||||
|
||||
二、多个图标动态渲染
|
||||
1.确定图标名字,如:'mdi:emoticon'
|
||||
2.引入Icon组件:
|
||||
import { Icon } from '@iconify/vue';
|
||||
3.动态渲染 <Icon icon="mdi:emoticon" />
|
||||
ps:Icon组件属性 https://docs.iconify.design/icon-components/vue/
|
||||
|
||||
三、结合naiveUI组件动态渲染
|
||||
1.确定图标名字,如:'mdi:emoticon'
|
||||
2.引入vue的h函数:
|
||||
import { h } from 'vue';
|
||||
3.引入Icon组件
|
||||
import { Icon } from '@iconify/vue';
|
||||
4.动态渲染
|
||||
() => h(Icon, { icon: 'mdi:emoticon', style: { color: '#f00', fontSize: '16px' } })
|
||||
ps:@/uitls已封装好了函数:iconifyRender
|
@ -41,14 +41,6 @@
|
||||
"@types/qs": "^6.9.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.3.0",
|
||||
"@typescript-eslint/parser": "^5.3.0",
|
||||
"@vicons/antd": "^0.11.0",
|
||||
"@vicons/carbon": "^0.11.0",
|
||||
"@vicons/fa": "^0.11.0",
|
||||
"@vicons/fluent": "^0.11.0",
|
||||
"@vicons/ionicons4": "^0.11.0",
|
||||
"@vicons/ionicons5": "^0.11.0",
|
||||
"@vicons/material": "^0.11.0",
|
||||
"@vicons/tabler": "^0.11.0",
|
||||
"@vitejs/plugin-vue": "^1.9.4",
|
||||
"@vue/compiler-sfc": "^3.2.21",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
|
@ -11,14 +11,6 @@ specifiers:
|
||||
'@types/qs': ^6.9.7
|
||||
'@typescript-eslint/eslint-plugin': ^5.3.0
|
||||
'@typescript-eslint/parser': ^5.3.0
|
||||
'@vicons/antd': ^0.11.0
|
||||
'@vicons/carbon': ^0.11.0
|
||||
'@vicons/fa': ^0.11.0
|
||||
'@vicons/fluent': ^0.11.0
|
||||
'@vicons/ionicons4': ^0.11.0
|
||||
'@vicons/ionicons5': ^0.11.0
|
||||
'@vicons/material': ^0.11.0
|
||||
'@vicons/tabler': ^0.11.0
|
||||
'@vitejs/plugin-vue': ^1.9.4
|
||||
'@vue/compiler-sfc': ^3.2.21
|
||||
'@vue/eslint-config-prettier': ^6.0.0
|
||||
@ -85,14 +77,6 @@ devDependencies:
|
||||
'@types/qs': registry.nlark.com/@types/qs/6.9.7
|
||||
'@typescript-eslint/eslint-plugin': registry.npmmirror.com/@typescript-eslint/eslint-plugin/5.3.0_f8873316f48f7781ccc3e081fc76e214
|
||||
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser/5.3.0_eslint@8.1.0+typescript@4.4.4
|
||||
'@vicons/antd': registry.nlark.com/@vicons/antd/0.11.0
|
||||
'@vicons/carbon': registry.nlark.com/@vicons/carbon/0.11.0
|
||||
'@vicons/fa': registry.nlark.com/@vicons/fa/0.11.0
|
||||
'@vicons/fluent': registry.nlark.com/@vicons/fluent/0.11.0
|
||||
'@vicons/ionicons4': registry.nlark.com/@vicons/ionicons4/0.11.0
|
||||
'@vicons/ionicons5': registry.nlark.com/@vicons/ionicons5/0.11.0
|
||||
'@vicons/material': registry.nlark.com/@vicons/material/0.11.0
|
||||
'@vicons/tabler': registry.nlark.com/@vicons/tabler/0.11.0
|
||||
'@vitejs/plugin-vue': registry.npmmirror.com/@vitejs/plugin-vue/1.9.4_vite@2.5.10
|
||||
'@vue/compiler-sfc': registry.npmmirror.com/@vue/compiler-sfc/3.2.21
|
||||
'@vue/eslint-config-prettier': 6.0.0_91df2dbc49a694d3127d896fd063ef53
|
||||
@ -902,54 +886,6 @@ packages:
|
||||
name: '@types/yargs-parser'
|
||||
version: 20.2.1
|
||||
|
||||
registry.nlark.com/@vicons/antd/0.11.0:
|
||||
resolution: {integrity: sha1-PSiVLQKK7XEtymHLgdvbEUVMVUI=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/antd/download/@vicons/antd-0.11.0.tgz}
|
||||
name: '@vicons/antd'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/carbon/0.11.0:
|
||||
resolution: {integrity: sha1-UQ4B6IOnOx1DQ6PrHRAUFEZGOr4=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/carbon/download/@vicons/carbon-0.11.0.tgz}
|
||||
name: '@vicons/carbon'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/fa/0.11.0:
|
||||
resolution: {integrity: sha1-3GeAslt5Q3NOfHXXTfL0RDsFcq4=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/fa/download/@vicons/fa-0.11.0.tgz}
|
||||
name: '@vicons/fa'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/fluent/0.11.0:
|
||||
resolution: {integrity: sha1-hPPNolVTnLlvRcicFgHiiS15gm8=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/fluent/download/@vicons/fluent-0.11.0.tgz}
|
||||
name: '@vicons/fluent'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/ionicons4/0.11.0:
|
||||
resolution: {integrity: sha1-pg9erWYdRz8XEDrQBRzoKtdxu+Y=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/ionicons4/download/@vicons/ionicons4-0.11.0.tgz}
|
||||
name: '@vicons/ionicons4'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/ionicons5/0.11.0:
|
||||
resolution: {integrity: sha1-VBhb+lcqCd9wCU2xlU8ov78TY+0=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/ionicons5/download/@vicons/ionicons5-0.11.0.tgz}
|
||||
name: '@vicons/ionicons5'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/material/0.11.0:
|
||||
resolution: {integrity: sha1-LCCRIfP/akZFD0loOX32wwCN+NE=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/material/download/@vicons/material-0.11.0.tgz}
|
||||
name: '@vicons/material'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/@vicons/tabler/0.11.0:
|
||||
resolution: {integrity: sha1-nrBXnADKowQMLBz55cDHa6EgT7M=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/@vicons/tabler/download/@vicons/tabler-0.11.0.tgz}
|
||||
name: '@vicons/tabler'
|
||||
version: 0.11.0
|
||||
dev: true
|
||||
|
||||
registry.nlark.com/JSONStream/1.3.5:
|
||||
resolution: {integrity: sha1-MgjB8I06TZkmGrZPkjArwV4RHKA=, registry: http://registry.npm.taobao.org/, tarball: https://registry.nlark.com/JSONStream/download/JSONStream-1.3.5.tgz}
|
||||
name: JSONStream
|
||||
|
@ -3,7 +3,7 @@
|
||||
<path
|
||||
d="M0,158.86Q0,80,0,1.1C0,.2.2,0,1.1,0Q79.44,0,157.78,0c.9,0,1.1.2,1.1,1.1q0,78.35,0,156.68c0,.9-.2,1.1-1.1,1.1Q78.9,158.83,0,158.86Z"
|
||||
transform="translate(0)"
|
||||
style="fill: #ffffff"
|
||||
style="fill: #ffffff00"
|
||||
/>
|
||||
<path
|
||||
d="M81.28,55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1,8.1,0,0,1,4-8.61,7.89,7.89,0,0,1,9.3,1.23,36,36,0,0,1,5.9,8.83,75.18,75.18,0,0,1,8.44,28.58,83.21,83.21,0,0,1-5.23,36.74c-.91,2.47-1.91,4.9-3,7.28a1.2,1.2,0,0,0,0,1.41c9.58,13.3,21.76,23,37.85,27.24a54.35,54.35,0,0,0,19.68,1.57,7.72,7.72,0,0,1,8.36,6.9,7.9,7.9,0,0,1-6.7,9,64.74,64.74,0,0,1-23-1.33,77.68,77.68,0,0,1-36.93-19.88,93.64,93.64,0,0,1-11.91-13.71A2.18,2.18,0,0,0,73.87,103a72.75,72.75,0,0,0-27.38,7.55c-11.6,6-20.67,14.58-26.4,26.45a10.13,10.13,0,0,1-3.7,4.7A8,8,0,0,1,7.2,141a7.86,7.86,0,0,1-2.36-9.28,60.32,60.32,0,0,1,8.72-14.52c12.2-15.43,28.21-24.59,47.32-28.57A85.08,85.08,0,0,1,73.07,87a1.22,1.22,0,0,0,1.18-.8A76.06,76.06,0,0,0,80.78,63.9,57.87,57.87,0,0,0,81.28,55.9Z"
|
||||
|
@ -1,4 +1,3 @@
|
||||
import type { Component } from 'vue';
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import type { MenuOption } from 'naive-ui';
|
||||
import { EnumRoutePath, EnumLoginModule } from '@/enum';
|
||||
@ -14,7 +13,7 @@ interface RouteMeta {
|
||||
/** 不作为菜单 */
|
||||
isNotMenu?: boolean;
|
||||
/** 菜单和面包屑对应的图标 */
|
||||
icon?: Component;
|
||||
icon?: string;
|
||||
/** 路由作为菜单时的排序 */
|
||||
order?: number;
|
||||
}
|
||||
|
@ -3,9 +3,23 @@
|
||||
<template v-for="breadcrumb in breadcrumbList" :key="breadcrumb.key">
|
||||
<n-breadcrumb-item>
|
||||
<n-dropdown v-if="breadcrumb.hasChildren" :options="breadcrumb.children" @select="dropdownSelect">
|
||||
<span>{{ breadcrumb.label }}</span>
|
||||
<span>
|
||||
<Icon
|
||||
v-if="theme.crumbsStyle.showIcon && breadcrumb.iconName"
|
||||
:icon="breadcrumb.iconName"
|
||||
class="inline-block mr-4px text-16px"
|
||||
/>
|
||||
<span>{{ breadcrumb.label }}</span>
|
||||
</span>
|
||||
</n-dropdown>
|
||||
<span v-else>{{ breadcrumb.label }}</span>
|
||||
<template v-else>
|
||||
<Icon
|
||||
v-if="theme.crumbsStyle.showIcon && breadcrumb.iconName"
|
||||
:icon="breadcrumb.iconName"
|
||||
class="inline-block mr-4px text-16px"
|
||||
/>
|
||||
<span>{{ breadcrumb.label }}</span>
|
||||
</template>
|
||||
</n-breadcrumb-item>
|
||||
</template>
|
||||
</n-breadcrumb>
|
||||
@ -14,10 +28,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { NBreadcrumb, NBreadcrumbItem, NDropdown } from 'naive-ui';
|
||||
import type { DropdownOption } from 'naive-ui';
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { EnumRoutePath } from '@/enum';
|
||||
import { useThemeStore } from '@/store';
|
||||
import type { RoutePathKey } from '@/interface';
|
||||
|
||||
type Breadcrumb = DropdownOption & {
|
||||
@ -26,9 +42,11 @@ type Breadcrumb = DropdownOption & {
|
||||
disabled: boolean;
|
||||
routeName: RoutePathKey;
|
||||
hasChildren: boolean;
|
||||
iconName?: string;
|
||||
children?: Breadcrumb[];
|
||||
};
|
||||
|
||||
const theme = useThemeStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
@ -52,6 +70,9 @@ function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
|
||||
routeName,
|
||||
hasChildren: false
|
||||
};
|
||||
if (item.meta?.icon) {
|
||||
breadcrumItem.iconName = item.meta.icon as string;
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
breadcrumItem.hasChildren = true;
|
||||
breadcrumItem.children = recursionBreadcrumb(item.children as RouteLocationMatched[]);
|
||||
|
@ -9,11 +9,10 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { NDropdown, useDialog } from 'naive-ui';
|
||||
import { UserAvatar, Logout } from '@vicons/carbon';
|
||||
import { dynamicIconRender, resetAuthStorage } from '@/utils';
|
||||
import { HoverContainer } from '@/components';
|
||||
import avatar from '@/assets/svg/avatar/avatar01.svg';
|
||||
import { useRouterChange } from '@/hooks';
|
||||
import { iconifyRender, resetAuthStorage } from '@/utils';
|
||||
import avatar from '@/assets/svg/avatar/avatar01.svg';
|
||||
|
||||
type DropdownKey = 'user-center' | 'logout';
|
||||
|
||||
@ -24,7 +23,7 @@ const options = [
|
||||
{
|
||||
label: '用户中心',
|
||||
key: 'user-center',
|
||||
icon: dynamicIconRender(UserAvatar)
|
||||
icon: iconifyRender('carbon:user-avatar')
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
@ -33,7 +32,7 @@ const options = [
|
||||
{
|
||||
label: '退出登录',
|
||||
key: 'logout',
|
||||
icon: dynamicIconRender(Logout)
|
||||
icon: iconifyRender('carbon:logout')
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -14,12 +14,11 @@
|
||||
import { computed, watch } from 'vue';
|
||||
import { NDropdown } from 'naive-ui';
|
||||
import type { DropdownOption } from 'naive-ui';
|
||||
import { ReloadOutlined, CloseOutlined, ColumnWidthOutlined, MinusOutlined } from '@vicons/antd';
|
||||
import { useAppStore } from '@/store';
|
||||
import { useReloadInject } from '@/context';
|
||||
import { useBoolean } from '@/hooks';
|
||||
import { ROUTE_HOME } from '@/router';
|
||||
import { useReloadInject } from '@/context';
|
||||
import { dynamicIconRender } from '@/utils';
|
||||
import { iconifyRender } from '@/utils';
|
||||
|
||||
interface Props {
|
||||
/** 右键菜单可见性 */
|
||||
@ -59,23 +58,23 @@ const options = computed<Option[]>(() => [
|
||||
label: '重新加载',
|
||||
key: 'reload-current',
|
||||
disabled: props.currentPath !== app.multiTab.activeRoute,
|
||||
icon: dynamicIconRender(ReloadOutlined)
|
||||
icon: iconifyRender('ant-design:reload-outlined')
|
||||
},
|
||||
{
|
||||
label: '关闭标签页',
|
||||
key: 'close-current',
|
||||
disabled: props.currentPath === ROUTE_HOME.path,
|
||||
icon: dynamicIconRender(CloseOutlined)
|
||||
icon: iconifyRender('ant-design:close-outlined')
|
||||
},
|
||||
{
|
||||
label: '关闭其他标签页',
|
||||
key: 'close-other',
|
||||
icon: dynamicIconRender(ColumnWidthOutlined)
|
||||
icon: iconifyRender('ant-design:column-width-outlined')
|
||||
},
|
||||
{
|
||||
label: '关闭全部标签页',
|
||||
key: 'close-all',
|
||||
icon: dynamicIconRender(MinusOutlined)
|
||||
icon: iconifyRender('ant-design:minus-outlined')
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { BookInformation24Regular } from '@vicons/fluent';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { ROUTE_NAME_MAP, setRouterCacheName, setSingleRoute } from '@/utils';
|
||||
@ -14,7 +13,7 @@ const ABOUT: CustomRoute = setSingleRoute(BasicLayout, {
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.about,
|
||||
icon: BookInformation24Regular
|
||||
icon: 'fluent:book-information-24-regular'
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { AppStore24Regular } from '@vicons/fluent';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
@ -17,7 +16,7 @@ const COMPONENT: CustomRoute = {
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.component,
|
||||
icon: AppStore24Regular
|
||||
icon: 'fluent:app-store-24-regular'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Dashboard } from '@vicons/carbon';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
@ -15,7 +14,7 @@ const DASHBOARD: CustomRoute = {
|
||||
redirect: { name: ROUTE_NAME_MAP.get('dashboard_analysis') },
|
||||
meta: {
|
||||
title: EnumRouteTitle.dashboard,
|
||||
icon: Dashboard
|
||||
icon: 'carbon:dashboard'
|
||||
},
|
||||
children: [
|
||||
ROUTE_HOME,
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Document } from '@vicons/carbon';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
@ -19,7 +18,7 @@ const DOCUMENT: CustomRoute = {
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.document,
|
||||
icon: Document
|
||||
icon: 'carbon:document'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { ExceptionOutlined } from '@vicons/antd';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout } from '@/layouts';
|
||||
@ -19,7 +18,7 @@ const EXCEPTION: CustomRoute = {
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
title: EnumRouteTitle.exception,
|
||||
icon: ExceptionOutlined
|
||||
icon: 'ant-design:exception-outlined'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Menu } from '@vicons/carbon';
|
||||
import type { CustomRoute } from '@/interface';
|
||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
|
||||
import { BasicLayout, BasicChildLayout } from '@/layouts';
|
||||
@ -14,7 +13,7 @@ const MULTI_MENU: CustomRoute = {
|
||||
redirect: { name: ROUTE_NAME_MAP.get('multi-menu_first') },
|
||||
meta: {
|
||||
title: EnumRouteTitle['multi-menu'],
|
||||
icon: Menu
|
||||
icon: 'carbon:menu'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -75,7 +75,7 @@
|
||||
},
|
||||
"crumbsStyle": {
|
||||
"visible": true,
|
||||
"showIcon": false
|
||||
"showIcon": true
|
||||
},
|
||||
"pageStyle": {
|
||||
"animate": true,
|
||||
|
@ -66,7 +66,7 @@ const defaultThemeSettings: ThemeSettings = {
|
||||
},
|
||||
crumbsStyle: {
|
||||
visible: true,
|
||||
showIcon: false
|
||||
showIcon: true
|
||||
},
|
||||
pageStyle: {
|
||||
animate: true,
|
||||
|
@ -1,12 +1,19 @@
|
||||
import { h } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { NIcon } from 'naive-ui';
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
/** 动态渲染vicon */
|
||||
export function dynamicIconRender(icon: Component) {
|
||||
return () => {
|
||||
return h(NIcon, null, {
|
||||
default: () => h(icon)
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 动态渲染iconify
|
||||
* @param icon - 图标名称
|
||||
* @param color - 图标颜色
|
||||
* @param size - 图标大小
|
||||
*/
|
||||
export function iconifyRender(icon: string, color?: string, size?: number) {
|
||||
const style: { color?: string; size?: string } = {};
|
||||
if (color) {
|
||||
style.color = color;
|
||||
}
|
||||
if (size) {
|
||||
style.size = `${size}px`;
|
||||
}
|
||||
return () => h(Icon, { icon, style });
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import type { Component } from 'vue';
|
||||
import type { CustomRoute, GlobalMenuOption } from '@/interface';
|
||||
import { dynamicIconRender } from '@/utils';
|
||||
import { iconifyRender } from '@/utils';
|
||||
|
||||
/** 判断路由是否作为菜单 */
|
||||
function asMenu(route: CustomRoute) {
|
||||
@ -8,10 +7,10 @@ function asMenu(route: CustomRoute) {
|
||||
}
|
||||
|
||||
/** 给菜单添加可选属性 */
|
||||
function addPartialProps(menuItem: GlobalMenuOption, icon?: Component, children?: GlobalMenuOption[]) {
|
||||
function addPartialProps(menuItem: GlobalMenuOption, icon?: string, children?: GlobalMenuOption[]) {
|
||||
const item = { ...menuItem };
|
||||
if (icon) {
|
||||
Object.assign(item, { icon: dynamicIconRender(icon) });
|
||||
Object.assign(item, { icon: iconifyRender(icon) });
|
||||
}
|
||||
if (children) {
|
||||
Object.assign(item, { children });
|
||||
|
@ -4,7 +4,7 @@
|
||||
<gradient-bg class="h-100px" :start-color="item.colors[0]" :end-color="item.colors[1]">
|
||||
<h3 class="text-16px">{{ item.title }}</h3>
|
||||
<div class="flex justify-between pt-12px">
|
||||
<component :is="item.icon" class="text-32px" />
|
||||
<Icon :icon="item.icon" class="text-32px" />
|
||||
<count-to
|
||||
:prefix="item.unit"
|
||||
:start-value="1"
|
||||
@ -18,12 +18,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { VNodeChild } from 'vue';
|
||||
import { NGrid, NGridItem } from 'naive-ui';
|
||||
import { BarChartOutlined, MoneyCollectOutlined, TrademarkOutlined } from '@vicons/antd';
|
||||
import { DocumentDownload } from '@vicons/carbon';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { CountTo } from '@/components';
|
||||
import { dynamicIconRender } from '@/utils';
|
||||
import { GradientBg } from './components';
|
||||
|
||||
interface CardData {
|
||||
@ -32,7 +29,7 @@ interface CardData {
|
||||
value: number;
|
||||
unit: string;
|
||||
colors: [string, string];
|
||||
icon: () => VNodeChild;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
const cardData: CardData[] = [
|
||||
@ -42,7 +39,7 @@ const cardData: CardData[] = [
|
||||
value: 1000000,
|
||||
unit: '',
|
||||
colors: ['#ec4786', '#b955a4'],
|
||||
icon: dynamicIconRender(BarChartOutlined)
|
||||
icon: 'ant-design:bar-chart-outlined'
|
||||
},
|
||||
{
|
||||
id: 'amount',
|
||||
@ -50,7 +47,7 @@ const cardData: CardData[] = [
|
||||
value: 234567.89,
|
||||
unit: '$',
|
||||
colors: ['#865ec0', '#5144b4'],
|
||||
icon: dynamicIconRender(MoneyCollectOutlined)
|
||||
icon: 'ant-design:money-collect-outlined'
|
||||
},
|
||||
{
|
||||
id: 'download',
|
||||
@ -58,7 +55,7 @@ const cardData: CardData[] = [
|
||||
value: 666666,
|
||||
unit: '',
|
||||
colors: ['#56cdf3', '#719de3'],
|
||||
icon: dynamicIconRender(DocumentDownload)
|
||||
icon: 'carbon:document-download'
|
||||
},
|
||||
{
|
||||
id: 'trade',
|
||||
@ -66,7 +63,7 @@ const cardData: CardData[] = [
|
||||
value: 999999,
|
||||
unit: '',
|
||||
colors: ['#fcbc25', '#f68057'],
|
||||
icon: dynamicIconRender(TrademarkOutlined)
|
||||
icon: 'ant-design:trademark-circle-outlined'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
@ -3,13 +3,13 @@
|
||||
<div class="flex-y-center justify-between">
|
||||
<div class="flex-y-center">
|
||||
<img src="@/assets/svg/avatar/avatar01.svg" alt="" class="w-70px h-70px" />
|
||||
<div class="pl-12px whitespace-nowrap">
|
||||
<div class="pl-12px">
|
||||
<h3 class="text-18px font-semibold">早安,{{ auth.userInfo.userName }}, 今天又是充满活力的一天!</h3>
|
||||
<p class="leading-30px text-[#999]">今日多云转晴,20℃ - 25℃!</p>
|
||||
</div>
|
||||
</div>
|
||||
<n-space :size="36">
|
||||
<n-statistic v-for="item in statisticData" :key="item.id" v-bind="item"></n-statistic>
|
||||
<n-space :size="24" :wrap="false">
|
||||
<n-statistic v-for="item in statisticData" :key="item.id" class="whitespace-nowrap" v-bind="item"></n-statistic>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-card>
|
||||
|
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div
|
||||
class="
|
||||
flex-col-center
|
||||
p-12px
|
||||
border-1px border-[#efeff5]
|
||||
dark:border-[#ffffff17]
|
||||
rounded-4px
|
||||
hover:shadow-sm
|
||||
cursor-pointer
|
||||
"
|
||||
>
|
||||
<Icon :icon="icon" :style="{ color: iconColor }" class="text-30px" />
|
||||
<p class="py-8px text-16px">{{ label }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
interface Props {
|
||||
/** 快捷操作名称 */
|
||||
label: string;
|
||||
/** 图标 */
|
||||
icon: string;
|
||||
/** 图标颜色 */
|
||||
iconColor: string;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
<style scoped></style>
|
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="p-4px border-1px border-[#efeff5] dark:border-[#ffffff17] rounded-4px hover:shadow-sm cursor-pointer">
|
||||
<header class="flex-y-center">
|
||||
<Icon :icon="icon" :style="{ color: iconColor }" class="text-30px" />
|
||||
<h3 class="pl-12px text-18px font-semibold">{{ name }}</h3>
|
||||
</header>
|
||||
<p class="py-8px h-56px text-[#999]">{{ description }}</p>
|
||||
<div class="flex justify-end">
|
||||
<span>{{ author }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
interface Props {
|
||||
/** 技术名称 */
|
||||
name: string;
|
||||
/** 技术描述 */
|
||||
description: string;
|
||||
/** 技术作者 */
|
||||
author: string;
|
||||
/** 技术图标 */
|
||||
icon: string;
|
||||
/** 图标颜色 */
|
||||
iconColor?: string;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
</script>
|
||||
<style scoped></style>
|
@ -0,0 +1,4 @@
|
||||
import TechnologyCard from './TechnologyCard.vue';
|
||||
import ShortcutsCard from './ShortcutsCard.vue';
|
||||
|
||||
export { TechnologyCard, ShortcutsCard };
|
@ -1,29 +1,145 @@
|
||||
<template>
|
||||
<n-grid cols="s:1 m:2" responsive="screen" :x-gap="16" :y-gap="16">
|
||||
<n-grid-item>
|
||||
<n-grid :item-responsive="true" responsive="screen" :x-gap="16" :y-gap="16">
|
||||
<n-grid-item span="s:24 m:16">
|
||||
<n-space :vertical="true" :size="16">
|
||||
<n-card title="项目" :bordered="false" size="small" class="shadow-sm rounded-16px">
|
||||
<n-card title="项目主要技术栈" :bordered="false" size="small" class="shadow-sm rounded-16px">
|
||||
<template #header-extra>
|
||||
<a class="g_text-primary" href="javascript:;">全部项目</a>
|
||||
<a class="g_text-primary" href="javascript:;">更多技术栈</a>
|
||||
</template>
|
||||
<n-grid :item-responsive="true" responsive="screen" cols="m:2 l:3" :x-gap="8" :y-gap="8">
|
||||
<n-grid-item v-for="item in technology" :key="item.id">
|
||||
<technology-card v-bind="item" />
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
<n-card title="动态" :bordered="false" size="small" class="shadow-sm rounded-16px">
|
||||
<template #header-extra>
|
||||
<a class="g_text-primary" href="javascript:;">更多动态</a>
|
||||
</template>
|
||||
<n-list>
|
||||
<n-list-item v-for="item in activity" :key="item.id">
|
||||
<template #prefix>
|
||||
<div class="w-48px h-48px">
|
||||
<img src="@/assets/svg/avatar/avatar01.svg" alt="" class="wh-full" />
|
||||
</div>
|
||||
</template>
|
||||
<n-thing :title="item.content" :description="item.time" />
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<n-grid-item span="s:24 m:8">
|
||||
<n-space :vertical="true" :size="16">
|
||||
<n-card title="快捷操作" :bordered="false" size="small" class="shadow-sm rounded-16px"></n-card>
|
||||
<n-card title="XX指数" :bordered="false" size="small" class="shadow-sm rounded-16px"></n-card>
|
||||
<n-card title="快捷操作" :bordered="false" size="small" class="shadow-sm rounded-16px">
|
||||
<n-grid :item-responsive="true" responsive="screen" cols="m:2 l:3" :x-gap="8" :y-gap="8">
|
||||
<n-grid-item v-for="item in shortcuts" :key="item.id">
|
||||
<shortcuts-card v-bind="item" />
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
<n-card title="创意" :bordered="false" size="small" class="shadow-sm rounded-16px">
|
||||
<n-carousel :autoplay="true" :show-arrow="true">
|
||||
<banner-svg type="1" />
|
||||
<banner-svg type="2" />
|
||||
<banner-svg type="3" />
|
||||
</n-carousel>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { NGrid, NGridItem, NSpace, NCard } from 'naive-ui';
|
||||
import { NGrid, NGridItem, NSpace, NCard, NList, NListItem, NThing, NCarousel } from 'naive-ui';
|
||||
import { BannerSvg } from '@/components';
|
||||
import { TechnologyCard, ShortcutsCard } from './components';
|
||||
|
||||
interface Technology {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
author: string;
|
||||
icon: string;
|
||||
iconColor?: string;
|
||||
}
|
||||
|
||||
interface Activity {
|
||||
id: number;
|
||||
content: string;
|
||||
time: string;
|
||||
}
|
||||
|
||||
interface Shortcuts {
|
||||
id: number;
|
||||
label: string;
|
||||
icon: string;
|
||||
iconColor: string;
|
||||
}
|
||||
|
||||
const technology: Technology[] = [
|
||||
{
|
||||
id: 0,
|
||||
name: 'Vue',
|
||||
description: '一套用于构建用户界面的渐进式框架',
|
||||
author: '尤雨溪 - Evan You',
|
||||
icon: 'vscode-icons:file-type-vue'
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'TypeScript',
|
||||
description: 'JavaScript类型的超集,它可以编译成纯JavaScript',
|
||||
author: '微软 - Microsoft',
|
||||
icon: 'vscode-icons:file-type-typescript-official'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Vite',
|
||||
description: '下一代前端开发与构建工具',
|
||||
author: '尤雨溪 - Evan You',
|
||||
icon: 'vscode-icons:file-type-vite'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'NaiveUI',
|
||||
description: '一个 Vue 3 组件库',
|
||||
author: '图森未来 - TuSimple',
|
||||
icon: 'mdi:alpha-n-box-outline',
|
||||
iconColor: '#5fbc22'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'WindiCSS',
|
||||
description: '下一代实用优先的CSS框架',
|
||||
author: 'Windicss',
|
||||
icon: 'file-icons:windi',
|
||||
iconColor: '#48b0f1'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Pinia',
|
||||
description: 'vue状态管理框架,支持vue2、vue3',
|
||||
author: 'Posva',
|
||||
icon: 'mdi:fruit-pineapple',
|
||||
iconColor: '#fecf48'
|
||||
}
|
||||
];
|
||||
|
||||
const activity: Activity[] = [
|
||||
{ id: 4, content: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!', time: '2021-11-07 22:45:32' },
|
||||
{ id: 3, content: 'Soybean 正在忙于为soybean-admin写项目说明文档!', time: '2021-11-03 20:33:31' },
|
||||
{ id: 2, content: 'Soybean 准备为soybean-admin 1.0的发布做充分的准备工作!', time: '2021-10-31 22:43:12' },
|
||||
{ id: 1, content: '@yanbowe 向soybean-admin提交了一个bug,多标签栏不会自适应。', time: '2021-10-27 10:24:54' },
|
||||
{ id: 0, content: 'Soybean 在2021年5月28日创建了开源项目soybean-admin!', time: '2021-05-28 22:22:22' }
|
||||
];
|
||||
|
||||
const shortcuts: Shortcuts[] = [
|
||||
{ id: 0, label: '主控台', icon: 'mdi:desktop-mac-dashboard', iconColor: '#409eff' },
|
||||
{ id: 1, label: '系统管理', icon: 'ic:outline-settings', iconColor: '#7238d1' },
|
||||
{ id: 2, label: '权限管理', icon: 'mdi:family-tree', iconColor: '#f56c6c' },
|
||||
{ id: 3, label: '组件', icon: 'ion:layers', iconColor: '#8aca6b' },
|
||||
{ id: 4, label: '表格', icon: 'mdi:table-large', iconColor: '#fab251' },
|
||||
{ id: 5, label: '图表', icon: 'mdi:chart-areaspline', iconColor: '#1890ff' }
|
||||
];
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
@ -15,6 +15,7 @@ export default defineConfig({
|
||||
'wh-full': 'w-full h-full',
|
||||
'center-layout': 'w-1280px mx-auto px-15px',
|
||||
'flex-center': 'flex justify-center items-center',
|
||||
'flex-col-center': 'flex flex-col justify-center items-center',
|
||||
'flex-x-center': 'flex justify-center',
|
||||
'flex-y-center': 'flex items-center',
|
||||
'inline-flex-center': 'inline-flex justify-center items-center',
|
||||
|
Loading…
Reference in New Issue
Block a user