perf: 优化管理端生产加载体验
- 图标与重型组件按需加载,优化菜单预取和页面请求链路 - 开启 gzip 与静态缓存并修复子路由 KeepAlive 冲突
This commit is contained in:
@@ -213,7 +213,7 @@ const loadProviderDetail = async (
|
||||
if (!options.keepDraft) {
|
||||
syncProviderDraft();
|
||||
}
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
isDetailLoading.value = true;
|
||||
@@ -234,30 +234,64 @@ const loadProviderDetail = async (
|
||||
if (!options.keepDraft) {
|
||||
syncProviderDraft(selectedProvider.value);
|
||||
}
|
||||
return res.data;
|
||||
} else {
|
||||
ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
|
||||
}
|
||||
} finally {
|
||||
isDetailLoading.value = false;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const refreshProviderCounts = async (list: any[]) => {
|
||||
const entries = await Promise.all(
|
||||
list.map(async (provider) => {
|
||||
let providerCountRequestId = 0;
|
||||
const PROVIDER_COUNT_CONCURRENCY = 2;
|
||||
|
||||
const refreshProviderCounts = async (
|
||||
list: any[],
|
||||
excludedProviderId?: string,
|
||||
) => {
|
||||
const currentRequestId = ++providerCountRequestId;
|
||||
const pendingProviders = list.filter(
|
||||
(provider) => String(provider.id) !== excludedProviderId,
|
||||
);
|
||||
const entries: Array<[string, number]> = [];
|
||||
let cursor = 0;
|
||||
|
||||
const worker = async () => {
|
||||
while (cursor < pendingProviders.length) {
|
||||
const provider = pendingProviders[cursor++];
|
||||
const providerId = String(provider.id);
|
||||
try {
|
||||
const res = await api.get(
|
||||
`/api/v1/model/getList?providerId=${provider.id}`,
|
||||
`/api/v1/model/getList?providerId=${providerId}`,
|
||||
{},
|
||||
);
|
||||
return [provider.id, res.errorCode === 0 ? countModels(res.data) : 0];
|
||||
entries.push([
|
||||
providerId,
|
||||
res.errorCode === 0 ? countModels(res.data) : 0,
|
||||
]);
|
||||
} catch {
|
||||
return [provider.id, 0];
|
||||
entries.push([providerId, 0]);
|
||||
}
|
||||
}),
|
||||
}
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
Array.from(
|
||||
{
|
||||
length: Math.min(PROVIDER_COUNT_CONCURRENCY, pendingProviders.length),
|
||||
},
|
||||
worker,
|
||||
),
|
||||
);
|
||||
|
||||
providerCounts.value = Object.fromEntries(entries);
|
||||
if (currentRequestId === providerCountRequestId) {
|
||||
providerCounts.value = {
|
||||
...providerCounts.value,
|
||||
...Object.fromEntries(entries),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const loadProviders = async (
|
||||
@@ -272,12 +306,15 @@ const loadProviders = async (
|
||||
const res = await getLlmProviderList();
|
||||
const list = res?.data || [];
|
||||
providers.value = list;
|
||||
|
||||
if (refreshCounts) {
|
||||
await refreshProviderCounts(list);
|
||||
}
|
||||
providerCounts.value = Object.fromEntries(
|
||||
list.map((provider: any) => [
|
||||
String(provider.id),
|
||||
providerCounts.value[String(provider.id)] ?? 0,
|
||||
]),
|
||||
);
|
||||
|
||||
if (list.length === 0) {
|
||||
providerCountRequestId += 1;
|
||||
selectedProviderId.value = '';
|
||||
syncProviderDraft();
|
||||
syncGroupedModels({});
|
||||
@@ -300,6 +337,9 @@ const loadProviders = async (
|
||||
await loadProviderDetail(nextProviderId, {
|
||||
keepDraft: keepDraft && previousId === nextProviderId,
|
||||
});
|
||||
if (refreshCounts) {
|
||||
void refreshProviderCounts(list, String(nextProviderId));
|
||||
}
|
||||
} finally {
|
||||
isPageLoading.value = false;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,14 @@ import type {
|
||||
} from '#/components/page/CardList.vue';
|
||||
import type { OfflineImpactCheck } from '#/views/ai/shared/offline-impact';
|
||||
|
||||
import { computed, h, markRaw, onMounted, ref } from 'vue';
|
||||
|
||||
import ElXMarkdown from 'vue-element-plus-x/es/XMarkdown/index.js';
|
||||
import {
|
||||
computed,
|
||||
defineAsyncComponent,
|
||||
h,
|
||||
markRaw,
|
||||
onMounted,
|
||||
ref,
|
||||
} from 'vue';
|
||||
|
||||
import { useAccess } from '@easyflow/access';
|
||||
import { EasyFlowFormModal } from '@easyflow/common-ui';
|
||||
@@ -40,6 +45,7 @@ import {
|
||||
ElMessage,
|
||||
ElMessageBox,
|
||||
ElPopover,
|
||||
ElSkeleton,
|
||||
} from 'element-plus';
|
||||
import { tryit } from 'radash';
|
||||
|
||||
@@ -67,6 +73,10 @@ import {
|
||||
|
||||
import WorkflowModal from './WorkflowModal.vue';
|
||||
|
||||
const ElXMarkdown = defineAsyncComponent(
|
||||
() => import('vue-element-plus-x/es/XMarkdown/index.js'),
|
||||
);
|
||||
|
||||
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
||||
|
||||
interface FieldDefinition {
|
||||
@@ -1007,11 +1017,16 @@ function handleHeaderButtonClick(data: any) {
|
||||
class="workflow-api-markdown-wrap"
|
||||
@click="handleApiDocClick"
|
||||
>
|
||||
<ElXMarkdown
|
||||
:markdown="apiDocMarkdown"
|
||||
:allow-html="true"
|
||||
:sanitize="false"
|
||||
/>
|
||||
<Suspense>
|
||||
<ElXMarkdown
|
||||
:markdown="apiDocMarkdown"
|
||||
:allow-html="true"
|
||||
:sanitize="false"
|
||||
/>
|
||||
<template #fallback>
|
||||
<ElSkeleton :rows="6" animated />
|
||||
</template>
|
||||
</Suspense>
|
||||
</div>
|
||||
</ElDialog>
|
||||
<HeaderSearch
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { EchartsUIType } from '@easyflow/plugins/echarts';
|
||||
import type { EchartsUIType } from '@easyflow/plugins/echarts/workspace';
|
||||
|
||||
import type {
|
||||
DashboardAssistantTrendSeries,
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from 'vue';
|
||||
|
||||
import { AnalysisChartCard } from '@easyflow/common-ui';
|
||||
import { EchartsUI, useEcharts } from '@easyflow/plugins/echarts';
|
||||
import { EchartsUI, useEcharts } from '@easyflow/plugins/echarts/workspace';
|
||||
import { useUserStore } from '@easyflow/stores';
|
||||
import { convertToRgb, downloadFileFromBlob } from '@easyflow/utils';
|
||||
|
||||
@@ -307,17 +307,15 @@ async function loadOverview() {
|
||||
errorMessage.value = '';
|
||||
|
||||
try {
|
||||
const [data] = await Promise.all([
|
||||
getDashboardOverview(buildOverviewQuery()),
|
||||
loadAssistantOptions().catch(() => undefined),
|
||||
]);
|
||||
void loadAssistantOptions().catch(() => undefined);
|
||||
const data = await getDashboardOverview(buildOverviewQuery());
|
||||
overview.value = data;
|
||||
resetAssistantTrendSelection();
|
||||
await renderCharts();
|
||||
if (data.chatStatus?.available === false) {
|
||||
resetUserRanks();
|
||||
} else {
|
||||
await loadUserRanks();
|
||||
void loadUserRanks();
|
||||
}
|
||||
} catch (error) {
|
||||
overview.value = null;
|
||||
|
||||
Reference in New Issue
Block a user