⬆️ 升级 arco 版本.

This commit is contained in:
lijiahang
2024-03-22 20:01:05 +08:00
parent 27c1e16e57
commit a3d4420754
12 changed files with 373 additions and 174 deletions

View File

@@ -21,7 +21,7 @@
</div>
<!-- 顶部菜单 -->
<div class="center-side">
<menu-tree v-if="topMenu" />
<system-menu-tree v-if="topMenu" />
</div>
<!-- 右侧操作 -->
<ul class="right-side">
@@ -214,7 +214,7 @@
import { preferenceTipsKey } from './const';
import { REDIRECT_ROUTE_NAME, routerToTag } from '@/router/constants';
import { openNewRoute } from '@/router';
import MenuTree from '@/components/system/menu/tree/index.vue';
import SystemMenuTree from '@/components/system/menu/tree/index.vue';
import MessageBox from '@/components/system/message-box/index.vue';
import UpdatePasswordModal from '@/components/user/user/update-password-modal/index.vue';

View File

@@ -4,7 +4,7 @@
<div class="tab-bar-box">
<div class="tab-bar-scroll">
<div class="tags-wrap">
<TabItem v-for="(tag, index) in tagList"
<tab-item v-for="(tag, index) in tagList"
:key="tag.fullPath"
:index="index"
:item-data="tag" />

View File

@@ -1,163 +1,160 @@
<script lang="tsx">
<template>
<a-menu class="full"
:mode="topMenu ? 'horizontal' : 'vertical'"
v-model:collapsed="collapsed"
v-model:open-keys="openKeys"
v-model:selected-keys="selectedKey"
:show-collapse-button="appStore.device !== 'mobile'"
:auto-open="false"
:auto-open-selected="true"
:level-indent="34"
@collapse="setCollapse">
<template v-for="menu in menuTree">
<!-- 一级菜单 -->
<a-menu-item v-if="!menu.children?.length"
:key="menu.name"
@click="(e) => goto(e, menu)">
<!-- 图标 -->
<template #icon>
<component v-if="menu.meta?.icon" :is="menu.meta?.icon" />
</template>
<!-- 名称 -->
{{ menu.meta?.locale || '' }}
</a-menu-item>
<!-- 父菜单 -->
<a-sub-menu v-else :key="menu.name">
<!-- 图标 -->
<template #icon>
<component v-if="menu.meta?.icon" :is="menu.meta?.icon" />
</template>
<!-- 名称 -->
<template #title>
{{ menu.meta?.locale || '' }}
</template>
<!-- 子菜单 -->
<a-menu-item v-for="child in menu.children"
:key="child.name"
@click="(e) => goto(e, child)">
<!-- 图标 -->
<template #icon v-if="child.meta?.icon">
<component :is="child.meta?.icon" />
</template>
<!-- 名称 -->
{{ child.meta?.locale || '' }}
</a-menu-item>
</a-sub-menu>
</template>
</a-menu>
</template>
<script lang="ts">
export default {
name: 'systemMenuTree'
};
</script>
<script lang="ts" setup>
import type { RouteMeta, RouteRecordRaw } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { compile, computed, defineComponent, h, ref } from 'vue';
import { computed, ref } from 'vue';
import { useAppStore } from '@/store';
import { listenerRouteChange } from '@/utils/route-listener';
import { openWindow, regexUrl } from '@/utils';
import { openNewRoute } from '@/router';
import useMenuTree from './use-menu-tree';
export default defineComponent({
name: 'menuTree',
emit: ['collapse'],
setup() {
const appStore = useAppStore();
const router = useRouter();
const route = useRoute();
const { menuTree } = useMenuTree();
const collapsed = computed({
get() {
if (appStore.device === 'desktop') return appStore.menuCollapse;
return false;
},
set(value: boolean) {
appStore.updateSettings({ menuCollapse: value });
},
});
const emits = defineEmits(['collapse']);
const topMenu = computed(() => appStore.topMenu);
const openKeys = ref<string[]>([]);
const selectedKey = ref<string[]>([]);
const appStore = useAppStore();
const router = useRouter();
const route = useRoute();
const { menuTree } = useMenuTree();
// 跳转路由
const goto = (e: any, item: RouteRecordRaw) => {
// 打开外链
if (regexUrl.test(item.path)) {
openWindow(item.path);
return;
}
const { hideInMenu, activeMenu, newWindow } = item.meta as RouteMeta;
// 新页面打开
if (newWindow || e.ctrlKey) {
openNewRoute({
name: item.name,
});
return;
}
// 设置 selectedKey
if (route.name === item.name && !hideInMenu && !activeMenu) {
selectedKey.value = [item.name as string];
return;
}
// 触发跳转
router.push({
name: item.name,
});
};
const findMenuOpenKeys = (target: string) => {
const result: string[] = [];
let isFind = false;
const backtrack = (item: RouteRecordRaw, keys: string[]) => {
if (item.name === target) {
isFind = true;
result.push(...keys);
return;
}
if (item.children?.length) {
item.children.forEach((el) => {
backtrack(el, [...keys, el.name as string]);
});
}
};
menuTree.value.forEach((el: RouteRecordRaw) => {
if (isFind) return;
backtrack(el, [el.name as string]);
});
return result;
};
// 监听路由 设置打开的 key
listenerRouteChange((newRoute) => {
const { activeMenu, hideInMenu } = newRoute.meta;
if (!hideInMenu || activeMenu) {
const menuOpenKeys = findMenuOpenKeys(
(activeMenu || newRoute.name) as string
);
const keySet = new Set([...menuOpenKeys, ...openKeys.value]);
openKeys.value = [...keySet];
selectedKey.value = [
activeMenu || menuOpenKeys[menuOpenKeys.length - 1],
];
}
}, true);
// 展开菜单
const setCollapse = (val: boolean) => {
if (appStore.device === 'desktop')
appStore.updateSettings({ menuCollapse: val });
};
// 渲染菜单
const renderSubMenu = () => {
function travel(_route: RouteRecordRaw[], nodes = []) {
if (_route) {
_route.forEach((element) => {
// This is demo, modify nodes as needed
const icon = element?.meta?.icon
? () => h(compile(`<${element?.meta?.icon}/>`))
: null;
const node =
element?.children && element?.children.length !== 0 ? (
<a-sub-menu
key={element?.name}
v-slots={{
icon,
// 去除国际化 title: () => h(compile(t(element?.meta?.locale || ''))),
title: () => h(compile(element?.meta?.locale || '')),
}}
>
{travel(element?.children)}
</a-sub-menu>
) : (
<a-menu-item
key={element?.name}
v-slots={{ icon }}
onClick={($event: any) => goto($event, element)}
>
{element?.meta?.locale || ''}
</a-menu-item>
);
nodes.push(node as never);
});
}
return nodes;
}
return travel(menuTree.value);
};
return () => (
<a-menu
mode={topMenu.value ? 'horizontal' : 'vertical'}
v-model:collapsed={collapsed.value}
v-model:open-keys={openKeys.value}
show-collapse-button={appStore.device !== 'mobile'}
auto-open={false}
selected-keys={selectedKey.value}
auto-open-selected={true}
level-indent={34}
style="height: 100%; width:100%;"
onCollapse={setCollapse}
>
{renderSubMenu()}
</a-menu>
);
const collapsed = computed({
get() {
if (appStore.device === 'desktop') return appStore.menuCollapse;
return false;
},
set(value: boolean) {
appStore.updateSettings({ menuCollapse: value });
},
});
const topMenu = computed(() => appStore.topMenu);
const openKeys = ref<string[]>([]);
const selectedKey = ref<string[]>([]);
// 跳转路由
const goto = (e: any, item: RouteRecordRaw) => {
// 打开外链
if (regexUrl.test(item.path)) {
openWindow(item.path);
return;
}
const { hideInMenu, activeMenu, newWindow } = item.meta as RouteMeta;
// 新页面打开
if (newWindow || e.ctrlKey) {
openNewRoute({
name: item.name,
});
return;
}
// 设置 selectedKey
if (route.name === item.name && !hideInMenu && !activeMenu) {
selectedKey.value = [item.name as string];
return;
}
// 触发跳转
router.push({
name: item.name,
});
};
const findMenuOpenKeys = (target: string) => {
const result: string[] = [];
let isFind = false;
const backtrack = (item: RouteRecordRaw, keys: string[]) => {
if (item.name === target) {
isFind = true;
result.push(...keys);
return;
}
if (item.children?.length) {
item.children.forEach((el) => {
backtrack(el, [...keys, el.name as string]);
});
}
};
menuTree.value.forEach((el: RouteRecordRaw) => {
if (isFind) return;
backtrack(el, [el.name as string]);
});
return result;
};
// 监听路由 设置打开的 key
listenerRouteChange((newRoute) => {
const { activeMenu, hideInMenu } = newRoute.meta;
if (!hideInMenu || activeMenu) {
const menuOpenKeys = findMenuOpenKeys(
(activeMenu || newRoute.name) as string
);
const keySet = new Set([...menuOpenKeys, ...openKeys.value]);
openKeys.value = [...keySet];
selectedKey.value = [
activeMenu || menuOpenKeys[menuOpenKeys.length - 1],
];
}
}, true);
// 展开菜单
const setCollapse = (val: boolean) => {
if (appStore.device === 'desktop')
appStore.updateSettings({ menuCollapse: val });
};
</script>
<style lang="less" scoped>

View File

@@ -0,0 +1,189 @@
<script lang="tsx">
import type { RouteMeta, RouteRecordRaw } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { compile, computed, defineComponent, h, ref } from 'vue';
import { useAppStore } from '@/store';
import { listenerRouteChange } from '@/utils/route-listener';
import { openWindow, regexUrl } from '@/utils';
import { openNewRoute } from '@/router';
import useMenuTree from './use-menu-tree';
export default defineComponent({
name: 'menuTree',
emit: ['collapse'],
setup() {
const appStore = useAppStore();
const router = useRouter();
const route = useRoute();
const { menuTree } = useMenuTree();
const collapsed = computed({
get() {
if (appStore.device === 'desktop') return appStore.menuCollapse;
return false;
},
set(value: boolean) {
appStore.updateSettings({ menuCollapse: value });
},
});
const topMenu = computed(() => appStore.topMenu);
const openKeys = ref<string[]>([]);
const selectedKey = ref<string[]>([]);
// 跳转路由
const goto = (e: any, item: RouteRecordRaw) => {
// 打开外链
if (regexUrl.test(item.path)) {
openWindow(item.path);
return;
}
const { hideInMenu, activeMenu, newWindow } = item.meta as RouteMeta;
// 新页面打开
if (newWindow || e.ctrlKey) {
openNewRoute({
name: item.name,
});
return;
}
// 设置 selectedKey
if (route.name === item.name && !hideInMenu && !activeMenu) {
selectedKey.value = [item.name as string];
return;
}
// 触发跳转
router.push({
name: item.name,
});
};
const findMenuOpenKeys = (target: string) => {
const result: string[] = [];
let isFind = false;
const backtrack = (item: RouteRecordRaw, keys: string[]) => {
if (item.name === target) {
isFind = true;
result.push(...keys);
return;
}
if (item.children?.length) {
item.children.forEach((el) => {
backtrack(el, [...keys, el.name as string]);
});
}
};
menuTree.value.forEach((el: RouteRecordRaw) => {
if (isFind) return;
backtrack(el, [el.name as string]);
});
return result;
};
// 监听路由 设置打开的 key
listenerRouteChange((newRoute) => {
const { activeMenu, hideInMenu } = newRoute.meta;
if (!hideInMenu || activeMenu) {
const menuOpenKeys = findMenuOpenKeys(
(activeMenu || newRoute.name) as string
);
const keySet = new Set([...menuOpenKeys, ...openKeys.value]);
openKeys.value = [...keySet];
selectedKey.value = [
activeMenu || menuOpenKeys[menuOpenKeys.length - 1],
];
}
}, true);
// 展开菜单
const setCollapse = (val: boolean) => {
if (appStore.device === 'desktop')
appStore.updateSettings({ menuCollapse: val });
};
// 渲染菜单
const renderSubMenu = () => {
function travel(_route: RouteRecordRaw[], nodes = []) {
if (_route) {
_route.forEach((element) => {
// This is demo, modify nodes as needed
const icon = element?.meta?.icon
? () => h(compile(`<${element?.meta?.icon}/>`))
: null;
const node =
element?.children && element?.children.length !== 0 ? (
<a-sub-menu
key={element?.name}
v-slots={{
icon,
// 去除国际化 title: () => h(compile(t(element?.meta?.locale || ''))),
title: () => h(compile(element?.meta?.locale || '')),
}}
>
{travel(element?.children)}
</a-sub-menu>
) : (
<a-menu-item
key={element?.name}
v-slots={{ icon }}
onClick={($event: any) => goto($event, element)}
>
{element?.meta?.locale || ''}
</a-menu-item>
);
nodes.push(node as never);
});
}
return nodes;
}
return travel(menuTree.value);
};
return () => (
<a-menu
mode={topMenu.value ? 'horizontal' : 'vertical'}
v-model:collapsed={collapsed.value}
v-model:open-keys={openKeys.value}
show-collapse-button={appStore.device !== 'mobile'}
auto-open={false}
selected-keys={selectedKey.value}
auto-open-selected={true}
level-indent={34}
style="height: 100%; width:100%;"
onCollapse={setCollapse}
>
{renderSubMenu()}
</a-menu>
);
},
});
</script>
<style lang="less" scoped>
:deep(.arco-menu-inner) {
.arco-menu-inline-header {
display: flex;
align-items: center;
}
.arco-icon {
&:not(.arco-icon-down) {
font-size: 18px;
}
}
.arco-menu-icon {
margin-right: 10px !important;
}
.arco-menu-indent-list {
width: 28px;
display: inline-block;
}
.arco-menu-title {
user-select: none;
}
}
</style>

View File

@@ -8,8 +8,10 @@ export default function useMenuTree() {
const appRoute = computed(() => {
return menuStore.appMenus;
});
const menuTree = computed(() => {
const menuTree = computed<RouteRecordNormalized[]>(() => {
const copyRouter = cloneDeep(appRoute.value) as RouteRecordNormalized[];
// 排序
copyRouter.sort((a: RouteRecordNormalized, b: RouteRecordNormalized) => {
return (a.meta.order || 0) - (b.meta.order || 0);
});

View File

@@ -10,11 +10,11 @@
<div class="pagination-wrapper">
<a-pagination v-if="pagination"
size="mini"
v-model:current="(pagination as PaginationProps).current"
v-model:page-size="(pagination as PaginationProps).pageSize"
v-model:current="(pagination as any).current"
v-model:page-size="(pagination as any).pageSize"
v-bind="pagination as any"
:auto-adjust="false"
@change="page => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, page, (pagination as PaginationProps).pageSize)"
@change="page => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, page, (pagination as any).pageSize)"
@page-size-change="limit => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, 1, limit)" />
</div>
</div>
@@ -104,7 +104,6 @@
</script>
<script lang="ts" setup>
import type { PaginationProps } from '@arco-design/web-vue';
import type { CardProps } from '../types/props';
import { ref, computed } from 'vue';
import { useAppStore } from '@/store';

View File

@@ -2,9 +2,9 @@
<a-layout class="layout" :class="{ mobile: appStore.hideMenu }">
<!-- tab bar -->
<div v-if="navbar" class="layout-navbar">
<NavBar />
<nav-bar />
</div>
<a-layout>
<a-layout style="flex-direction: row;">
<!-- 左侧菜单栏 -->
<a-layout-sider v-if="renderMenu"
v-show="!hideMenu"
@@ -17,7 +17,7 @@
:hide-trigger="true"
@collapse="setCollapsed">
<div class="menu-wrapper">
<menu-tree />
<system-menu-tree />
</div>
</a-layout-sider>
<!-- 顶部菜单栏 -->
@@ -29,12 +29,12 @@
mask-closable
:closable="false"
@cancel="drawerCancel">
<menu-tree style="padding: 12px 16px;" />
<system-menu-tree style="padding: 12px 16px;" />
</a-drawer>
<!-- body -->
<a-layout class="layout-content" :style="paddingStyle">
<!-- 页签 -->
<TabBar v-if="appStore.tabBar" />
<tab-bar v-if="appStore.tabBar" />
<!-- 页面 -->
<a-layout-content style="height: 100%; width: 100%;">
<!-- 水印 -->
@@ -43,11 +43,11 @@
:z-index="9999"
style="width: 100%; height: 100%;"
:content="userStore.username || ''">
<PageLayout />
<page-layout />
</a-watermark>
</a-layout-content>
<!-- 页脚 -->
<Footer v-if="visibleFooter" />
<footer v-if="visibleFooter" />
</a-layout>
</a-layout>
</a-layout>
@@ -60,17 +60,18 @@
import useResponsive from '@/hooks/responsive';
import { toggleDrawerMenuKey } from '@/types/symbol';
import PageLayout from './page-layout.vue';
import MenuTree from '@/components/system/menu/tree/index.vue';
import NavBar from '@/components/app/navbar/index.vue';
import Footer from '@/components/app/footer/index.vue';
import TabBar from '@/components/app/tab-bar/index.vue';
import SystemMenuTree from '@/components/system/menu/tree/index.vue';
const isInit = ref(false);
const appStore = useAppStore();
const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
useResponsive(true);
const isInit = ref(false);
const navbarHeight = `60px`;
const navbar = computed(() => appStore.navbar);
const renderMenu = computed(() => appStore.menu && !appStore.topMenu);

View File

@@ -1,9 +1,9 @@
import type { PaginationProps, TableRowSelection } from '@arco-design/web-vue';
import type { TableExpandable } from '@arco-design/web-vue/es/table/interface';
import { reactive } from 'vue';
import { useAppStore } from '@/store';
import { isNumber } from '@/utils/is';
import { TablePageSizeOptions } from '@/types/const';
import { TableExpandable } from '@arco-design/web-vue/es/table/interface';
/**
* 创建列表分页

View File

@@ -34,6 +34,7 @@
.flat(1)
.filter(s => s.meta)
.map(s => s as RouteRecordNormalized)
.filter(s => s.meta.hideInMenu !== true)
.slice(0, 15);
// 打开路由