perf: 优化管理端生产加载体验
- 图标与重型组件按需加载,优化菜单预取和页面请求链路 - 开启 gzip 与静态缓存并修复子路由 KeepAlive 冲突
This commit is contained in:
@@ -4,7 +4,12 @@ import type { VNode } from 'vue';
|
||||
import { computed, ref, useAttrs, watch, watchEffect } from 'vue';
|
||||
|
||||
import { usePagination } from '@easyflow/hooks';
|
||||
import { EmptyIcon, Grip, listIcons } from '@easyflow/icons';
|
||||
import {
|
||||
EmptyIcon,
|
||||
Grip,
|
||||
listIcons,
|
||||
loadIconCollection,
|
||||
} from '@easyflow/icons';
|
||||
import { $t } from '@easyflow/locales';
|
||||
|
||||
import {
|
||||
@@ -75,6 +80,30 @@ const currentPage = ref(1);
|
||||
const keyword = ref('');
|
||||
const keywordDebounce = refDebounced(keyword, 300);
|
||||
const innerIcons = ref<string[]>([]);
|
||||
let iconLoadRequestId = 0;
|
||||
|
||||
const commonSvgIcons = [
|
||||
'svg:talk',
|
||||
'svg:plugin',
|
||||
'svg:workflow',
|
||||
'svg:approval',
|
||||
'svg:knowledge',
|
||||
'svg:resource',
|
||||
'svg:data-center',
|
||||
'svg:llm',
|
||||
'svg:account',
|
||||
'svg:role',
|
||||
'svg:menu',
|
||||
'svg:department',
|
||||
'svg:time',
|
||||
'svg:log',
|
||||
'svg:chat-history',
|
||||
'svg:setting',
|
||||
'svg:api',
|
||||
'svg:user-feedback',
|
||||
'svg:oauth',
|
||||
'svg:mcp',
|
||||
];
|
||||
|
||||
/* 当检索关键词变化时,重置分页 */
|
||||
watch(keywordDebounce, () => {
|
||||
@@ -82,36 +111,39 @@ watch(keywordDebounce, () => {
|
||||
setCurrentPage(1);
|
||||
});
|
||||
|
||||
watchDebounced(
|
||||
() => props.prefix,
|
||||
async (prefix) => {
|
||||
if (prefix && prefix !== 'svg' && props.autoFetchApi) {
|
||||
innerIcons.value = [
|
||||
'svg:talk',
|
||||
'svg:plugin',
|
||||
'svg:workflow',
|
||||
'svg:approval',
|
||||
'svg:knowledge',
|
||||
'svg:resource',
|
||||
'svg:data-center',
|
||||
'svg:llm',
|
||||
'svg:account',
|
||||
'svg:role',
|
||||
'svg:menu',
|
||||
'svg:department',
|
||||
'svg:time',
|
||||
'svg:log',
|
||||
'svg:chat-history',
|
||||
'svg:setting',
|
||||
'svg:api',
|
||||
'svg:user-feedback',
|
||||
'svg:oauth',
|
||||
'svg:mcp',
|
||||
...getLocalIconsData(prefix),
|
||||
];
|
||||
async function refreshInnerIcons(prefix?: string) {
|
||||
if (!prefix || prefix === 'svg' || !props.autoFetchApi) {
|
||||
return;
|
||||
}
|
||||
const requestId = ++iconLoadRequestId;
|
||||
try {
|
||||
await loadIconCollection(prefix);
|
||||
} catch (error) {
|
||||
console.error(`Failed to load icon collection: ${prefix}`, error);
|
||||
}
|
||||
if (requestId === iconLoadRequestId && prefix === props.prefix) {
|
||||
innerIcons.value = [...commonSvgIcons, ...getLocalIconsData(prefix, true)];
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
visible,
|
||||
(isVisible) => {
|
||||
if (isVisible) {
|
||||
void refreshInnerIcons(props.prefix);
|
||||
}
|
||||
},
|
||||
{ immediate: true, debounce: 500, maxWait: 1000 },
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watchDebounced(
|
||||
() => props.prefix,
|
||||
(prefix) => {
|
||||
if (visible.value) {
|
||||
void refreshInnerIcons(prefix);
|
||||
}
|
||||
},
|
||||
{ debounce: 300, maxWait: 600 },
|
||||
);
|
||||
|
||||
const currentList = computed(() => {
|
||||
|
||||
@@ -12,8 +12,8 @@ export const ICONS_MAP: Recordable<string[]> = {};
|
||||
* @param prefix 图标集名称
|
||||
* @returns 图标集中包含的所有图标名称
|
||||
*/
|
||||
export function getLocalIconsData(prefix: string): string[] {
|
||||
if (Reflect.has(ICONS_MAP, prefix) && ICONS_MAP[prefix]) {
|
||||
export function getLocalIconsData(prefix: string, refresh = false): string[] {
|
||||
if (!refresh && Reflect.has(ICONS_MAP, prefix) && ICONS_MAP[prefix]) {
|
||||
return ICONS_MAP[prefix];
|
||||
}
|
||||
ICONS_MAP[prefix] = listIcons('', prefix);
|
||||
|
||||
Reference in New Issue
Block a user