feat: gate heavy online-dev frontend chunks

This commit is contained in:
2026-06-22 10:45:00 +08:00
parent d954279c9c
commit e33f08277b
6 changed files with 183 additions and 84 deletions
+2
View File
@@ -16,3 +16,5 @@ VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
VITE_ENABLE_ONLINE_DEV_DESIGN=false
VITE_ENABLE_DASHBOARD_ADVANCED_WIDGETS=false
+2
View File
@@ -7,3 +7,5 @@ VITE_PWA=false
VITE_ROUTER_HISTORY=history
VITE_INJECT_APP_LOADING=true
VITE_ARCHIVER=false
VITE_ENABLE_ONLINE_DEV_DESIGN=false
VITE_ENABLE_DASHBOARD_ADVANCED_WIDGETS=false
@@ -35,27 +35,44 @@ import { ChatBox } from '#/components/ChatBox';
import { useChatApi } from './composables/useChatApi';
import { useEventHandler } from './composables/useEventHandler';
const AppDesignPanel = defineAsyncComponent(() =>
const ENABLE_ONLINE_DEV_DESIGN =
import.meta.env.VITE_ENABLE_ONLINE_DEV_DESIGN === 'true';
const AppDesignPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/AppDesignPanel.vue'),
);
const AppSettingsPanel = defineAsyncComponent(() =>
)
: undefined;
const AppSettingsPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/AppSettingsPanel.vue'),
);
const DashboardBasicInfoConfirmPanel = defineAsyncComponent(() =>
)
: undefined;
const DashboardBasicInfoConfirmPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/DashboardBasicInfoConfirmPanel.vue'),
);
const DashboardDesignConfirmPanel = defineAsyncComponent(() =>
)
: undefined;
const DashboardDesignConfirmPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/DashboardDesignConfirmPanel.vue'),
);
const DashboardPublishConfirmPanel = defineAsyncComponent(() =>
)
: undefined;
const DashboardPublishConfirmPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/DashboardPublishConfirmPanel.vue'),
);
const DesignEditorPanel = defineAsyncComponent(() =>
)
: undefined;
const DesignEditorPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/DesignEditorPanel.vue'),
);
const SystemSummaryConfirmPanel = defineAsyncComponent(() =>
)
: undefined;
const SystemSummaryConfirmPanel = ENABLE_ONLINE_DEV_DESIGN
? defineAsyncComponent(() =>
import('#/components/form-editor/SystemSummaryConfirmPanel.vue'),
);
)
: undefined;
// ==================== Props ====================
const props = withDefaults(defineProps<AiChatPanelProps>(), {
@@ -235,13 +252,14 @@ const loadingAnimationTitle = ref('AI 正在开发...');
// 是否有任何设计面板打开
const hasAnyDesignPanelOpen = computed(
() =>
showDesignPanel.value ||
(ENABLE_ONLINE_DEV_DESIGN &&
(showDesignPanel.value ||
showAppDesignPanel.value ||
showAppSettingsPanel.value ||
showDashboardBasicInfoPanel.value ||
showDashboardDesignPanel.value ||
showDashboardPublishPanel.value ||
showSystemSummaryPanel.value ||
showSystemSummaryPanel.value)) ||
showLoadingAnimation.value,
);
@@ -290,6 +308,8 @@ const handleDesignPreview = (data: DesignPreviewData) => {
// 关闭加载动画
showLoadingAnimation.value = false;
if (!ENABLE_ONLINE_DEV_DESIGN) return;
switch (data.type) {
case 'app_design': {
currentAppDesign.value = data;
@@ -343,7 +363,7 @@ const { handleStreamEvent, updateAssistantMessage } = useEventHandler({
waitingConfig,
running,
conversationId: safeConversationId,
onDesignPreview: handleDesignPreview,
onDesignPreview: ENABLE_ONLINE_DEV_DESIGN ? handleDesignPreview : undefined,
});
// ==================== 加载历史消息 ====================
@@ -462,6 +482,7 @@ const runMessageWithExistingUserMsg = (
) => {
// 如果是 application 类型工作流且是全屏布局,显示加载动画
if (
ENABLE_ONLINE_DEV_DESIGN &&
props.layout === 'fullscreen' &&
props.agent?.workflow_type === 'application'
) {
@@ -533,6 +554,7 @@ const runMessage = (
// 如果是 application 类型工作流且是全屏布局,显示加载动画
if (
ENABLE_ONLINE_DEV_DESIGN &&
props.layout === 'fullscreen' &&
props.agent?.workflow_type === 'application'
) {
@@ -629,6 +651,7 @@ const handleInteractionSubmit = (messageId: string, value: any) => {
// 全屏布局且是 application 类型工作流时,显示加载动画
if (
ENABLE_ONLINE_DEV_DESIGN &&
props.layout === 'fullscreen' &&
props.agent?.workflow_type === 'application'
) {
@@ -667,6 +690,7 @@ const handleInteractionCancel = (messageId: string) => {
// 全屏布局且是 application 类型工作流时,显示加载动画
if (
ENABLE_ONLINE_DEV_DESIGN &&
props.layout === 'fullscreen' &&
props.agent?.workflow_type === 'application'
) {
@@ -778,6 +802,7 @@ const createDesignConfirmHandler = (
// 全屏布局且是 application 类型工作流时,显示加载动画
if (
ENABLE_ONLINE_DEV_DESIGN &&
props.layout === 'fullscreen' &&
props.agent?.workflow_type === 'application'
) {
@@ -1019,7 +1044,7 @@ onUnmounted(() => {
<!-- 设计编辑面板 -->
<DesignEditorPanel
v-if="showDesignPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showDesignPanel"
:visible="showDesignPanel"
:design="currentDesign as any"
@update:visible="showDesignPanel = $event"
@@ -1029,7 +1054,7 @@ onUnmounted(() => {
<!-- 应用设计面板 -->
<AppDesignPanel
v-if="showAppDesignPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showAppDesignPanel"
:visible="showAppDesignPanel"
:design="currentAppDesign as any"
@update:visible="showAppDesignPanel = $event"
@@ -1039,7 +1064,7 @@ onUnmounted(() => {
<!-- 应用设置面板 -->
<AppSettingsPanel
v-if="showAppSettingsPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showAppSettingsPanel"
:visible="showAppSettingsPanel"
:settings="currentAppSettings as any"
@update:visible="showAppSettingsPanel = $event"
@@ -1049,7 +1074,7 @@ onUnmounted(() => {
<!-- 仪表盘基础信息面板 -->
<DashboardBasicInfoConfirmPanel
v-if="showDashboardBasicInfoPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showDashboardBasicInfoPanel"
:visible="showDashboardBasicInfoPanel"
:basic-info="currentDashboardBasicInfo as any"
@update:visible="showDashboardBasicInfoPanel = $event"
@@ -1059,7 +1084,7 @@ onUnmounted(() => {
<!-- 仪表盘设计面板 -->
<DashboardDesignConfirmPanel
v-if="showDashboardDesignPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showDashboardDesignPanel"
:visible="showDashboardDesignPanel"
:design="currentDashboardDesign as any"
@update:visible="showDashboardDesignPanel = $event"
@@ -1069,7 +1094,7 @@ onUnmounted(() => {
<!-- 仪表盘发布面板 -->
<DashboardPublishConfirmPanel
v-if="showDashboardPublishPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showDashboardPublishPanel"
:visible="showDashboardPublishPanel"
:publish-data="currentDashboardPublish as any"
@update:visible="showDashboardPublishPanel = $event"
@@ -1079,7 +1104,7 @@ onUnmounted(() => {
<!-- 系统总结面板 -->
<SystemSummaryConfirmPanel
v-if="showSystemSummaryPanel"
v-if="ENABLE_ONLINE_DEV_DESIGN && showSystemSummaryPanel"
:visible="showSystemSummaryPanel"
:data="currentSystemSummary as any"
@update:visible="showSystemSummaryPanel = $event"
@@ -1089,7 +1114,7 @@ onUnmounted(() => {
</div>
<!-- 侧边栏布局时的设计面板(保持原有行为) -->
<template v-if="layout === 'sidebar'">
<template v-if="ENABLE_ONLINE_DEV_DESIGN && layout === 'sidebar'">
<DesignEditorPanel
v-if="showDesignPanel"
:visible="showDesignPanel"
@@ -103,11 +103,18 @@ export function useEventHandler(config: EventHandlerConfig) {
themeOptions: configData.themeOptions,
};
const hasDesignPanel = Boolean(onDesignPreview);
// 调用设计预览回调
onDesignPreview?.(previewData);
// 显示提示消息
const waitingContent = `**${configData.title}**\n\n${configData.message || '请在右侧面板中确认或编辑设计'}`;
const waitingContent = `**${configData.title}**\n\n${
configData.message ||
(hasDesignPanel
? '请在右侧面板中确认或编辑设计'
: '轻量版未启用在线开发设计面板,请直接在对话中确认或补充修改要求')
}`;
const initialMsg = messages.value.find((m) => m.id === msgId);
if (initialMsg && !initialMsg.content?.trim()) {
updateAssistantMessage(msgId, {
@@ -638,7 +645,7 @@ export function useEventHandler(config: EventHandlerConfig) {
emit('node-complete', {
node_id: event.node_id,
node_type: event.node_type,
status: event.status,
status: nodeSucceeded ? 'success' : 'failed',
elapsed_time: event.elapsed_time,
tokens_used: event.tokens_used,
error_message: event.error_message,
@@ -73,7 +73,9 @@ export interface DesignPreviewData {
title: string;
data: Record<string, any>;
nodeId: string;
data_sources?: any[];
form_fields?: any[];
schema_fields?: any[];
table_configs?: any[];
layoutOptions?: any[];
themeOptions?: any[];
@@ -99,6 +101,7 @@ export interface NodeEvent {
tokens_used?: number;
error_message?: string;
loop_iteration?: number;
warnings?: any[];
}
/** 循环迭代事件 */
@@ -34,6 +34,34 @@ const isEntered = ref(false);
// 数据更新动画状态
const isUpdating = ref(false);
const ENABLE_DASHBOARD_ADVANCED_WIDGETS =
import.meta.env.VITE_ENABLE_DASHBOARD_ADVANCED_WIDGETS === 'true';
const ADVANCED_WIDGET_TYPES = new Set([
'chart-area',
'chart-bar',
'chart-funnel',
'chart-gauge',
'chart-heatmap',
'chart-kline',
'chart-line',
'chart-pie',
'chart-radar',
'chart-ring',
'chart-sankey',
'chart-scatter',
'data-table',
'filter-date',
'filter-date-range',
'filter-input',
'filter-select',
'form-render',
'iframe',
'image',
'image-carousel',
'video-player',
]);
// 组件映射
const widgetComponents: Record<
string,
@@ -43,26 +71,6 @@ const widgetComponents: Record<
'progress-card': defineAsyncComponent(
() => import('./widgets/ProgressCard.vue'),
),
'chart-line': defineAsyncComponent(() => import('./widgets/ChartLine.vue')),
'chart-bar': defineAsyncComponent(() => import('./widgets/ChartBar.vue')),
'chart-pie': defineAsyncComponent(() => import('./widgets/ChartPie.vue')),
'chart-gauge': defineAsyncComponent(() => import('./widgets/ChartGauge.vue')),
'chart-area': defineAsyncComponent(() => import('./widgets/ChartArea.vue')),
'chart-radar': defineAsyncComponent(() => import('./widgets/ChartRadar.vue')),
'chart-funnel': defineAsyncComponent(
() => import('./widgets/ChartFunnel.vue'),
),
'chart-scatter': defineAsyncComponent(
() => import('./widgets/ChartScatter.vue'),
),
'chart-ring': defineAsyncComponent(() => import('./widgets/ChartRing.vue')),
'chart-heatmap': defineAsyncComponent(
() => import('./widgets/ChartHeatmap.vue'),
),
'chart-kline': defineAsyncComponent(() => import('./widgets/ChartKline.vue')),
'chart-sankey': defineAsyncComponent(
() => import('./widgets/ChartSankey.vue'),
),
'todo-list': defineAsyncComponent(() => import('./widgets/TodoList.vue')),
'notice-list': defineAsyncComponent(() => import('./widgets/NoticeList.vue')),
'ranking-list': defineAsyncComponent(
@@ -81,18 +89,6 @@ const widgetComponents: Record<
),
clock: defineAsyncComponent(() => import('./widgets/ClockWidget.vue')),
weather: defineAsyncComponent(() => import('./widgets/WeatherWidget.vue')),
'image-carousel': defineAsyncComponent(
() => import('./widgets/ImageCarousel.vue'),
),
'data-table': defineAsyncComponent(() => import('./widgets/DataTable.vue')),
'form-render': defineAsyncComponent(
() => import('./widgets/FormRenderWidget.vue'),
),
iframe: defineAsyncComponent(() => import('./widgets/IframeWidget.vue')),
'video-player': defineAsyncComponent(
() => import('./widgets/VideoPlayer.vue'),
),
image: defineAsyncComponent(() => import('./widgets/ImageWidget.vue')),
'approval-center': defineAsyncComponent(
() => import('./widgets/ApprovalCenter.vue'),
),
@@ -100,11 +96,46 @@ const widgetComponents: Record<
'server-monitor': defineAsyncComponent(
() => import('./widgets/ServerMonitor.vue'),
),
'filter-input': defineAsyncComponent(
() => import('./widgets/FilterInput.vue'),
...(ENABLE_DASHBOARD_ADVANCED_WIDGETS
? {
'chart-area': defineAsyncComponent(
() => import('./widgets/ChartArea.vue'),
),
'filter-select': defineAsyncComponent(
() => import('./widgets/FilterSelect.vue'),
'chart-bar': defineAsyncComponent(
() => import('./widgets/ChartBar.vue'),
),
'chart-funnel': defineAsyncComponent(
() => import('./widgets/ChartFunnel.vue'),
),
'chart-gauge': defineAsyncComponent(
() => import('./widgets/ChartGauge.vue'),
),
'chart-heatmap': defineAsyncComponent(
() => import('./widgets/ChartHeatmap.vue'),
),
'chart-kline': defineAsyncComponent(
() => import('./widgets/ChartKline.vue'),
),
'chart-line': defineAsyncComponent(
() => import('./widgets/ChartLine.vue'),
),
'chart-pie': defineAsyncComponent(
() => import('./widgets/ChartPie.vue'),
),
'chart-radar': defineAsyncComponent(
() => import('./widgets/ChartRadar.vue'),
),
'chart-ring': defineAsyncComponent(
() => import('./widgets/ChartRing.vue'),
),
'chart-sankey': defineAsyncComponent(
() => import('./widgets/ChartSankey.vue'),
),
'chart-scatter': defineAsyncComponent(
() => import('./widgets/ChartScatter.vue'),
),
'data-table': defineAsyncComponent(
() => import('./widgets/DataTable.vue'),
),
'filter-date': defineAsyncComponent(
() => import('./widgets/FilterDate.vue'),
@@ -112,6 +143,25 @@ const widgetComponents: Record<
'filter-date-range': defineAsyncComponent(
() => import('./widgets/FilterDateRange.vue'),
),
'filter-input': defineAsyncComponent(
() => import('./widgets/FilterInput.vue'),
),
'filter-select': defineAsyncComponent(
() => import('./widgets/FilterSelect.vue'),
),
'form-render': defineAsyncComponent(
() => import('./widgets/FormRenderWidget.vue'),
),
iframe: defineAsyncComponent(() => import('./widgets/IframeWidget.vue')),
image: defineAsyncComponent(() => import('./widgets/ImageWidget.vue')),
'image-carousel': defineAsyncComponent(
() => import('./widgets/ImageCarousel.vue'),
),
'video-player': defineAsyncComponent(
() => import('./widgets/VideoPlayer.vue'),
),
}
: {}),
};
const store = useDashboardDesignStore();
@@ -120,6 +170,12 @@ const currentComponent = computed(() => {
return widgetComponents[props.widget.type];
});
const isDisabledAdvancedWidget = computed(
() =>
!ENABLE_DASHBOARD_ADVANCED_WIDGETS &&
ADVANCED_WIDGET_TYPES.has(props.widget.type),
);
// 从 paramBindings 解析出实际参数值
function resolveParams(): Record<string, any> | undefined {
const bindings = props.widget.dataSource?.paramBindings;
@@ -324,7 +380,11 @@ const animationClass = computed(() => {
v-else
class="flex h-full w-full items-center justify-center text-gray-400"
>
{{ $t('dashboard-design.unknownWidget') }}: {{ widget.type }}
{{
isDisabledAdvancedWidget
? '轻量版未启用高级组件'
: $t('dashboard-design.unknownWidget')
}}: {{ widget.type }}
</div>
</div>
</template>