perf: split light dashboard runtime

This commit is contained in:
2026-06-22 12:42:23 +08:00
parent c8756be02e
commit 01b801bebc
21 changed files with 591 additions and 67 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardConfig } from './store/dashboardDesignStore';
import type { DashboardConfig } from './store/dashboardRuntimeStore';
/**
* 仪表盘渲染器
@@ -0,0 +1,135 @@
<script setup lang="ts">
import type { DashboardConfig } from './store/dashboardRuntimeStore';
import { computed, onMounted, ref, watch } from 'vue';
import { $t } from '@vben/locales';
import { ElEmpty } from 'element-plus';
import LightWidgetRenderer from './components/LightWidgetRenderer.vue';
const props = defineProps<{
config: DashboardConfig | string;
}>();
const dashboardConfig = ref<DashboardConfig | null>(null);
function parseConfig() {
if (!props.config) {
dashboardConfig.value = null;
return;
}
if (typeof props.config === 'string') {
try {
dashboardConfig.value = JSON.parse(props.config);
} catch {
console.error('Invalid light dashboard config JSON');
dashboardConfig.value = null;
}
} else {
dashboardConfig.value = props.config;
}
}
onMounted(parseConfig);
watch(() => props.config, parseConfig);
const layout = computed(() => {
if (!dashboardConfig.value) return [];
return dashboardConfig.value.widgets.map((w) => ({
i: w.i,
x: w.x,
y: w.y,
w: w.w,
h: w.h,
}));
});
const gridStyle = computed(() => {
if (!dashboardConfig.value) return {};
const [gapX, gapY] = dashboardConfig.value.margin;
const style: Record<string, string> = {
display: 'grid',
gap: `${gapY}px ${gapX}px`,
gridAutoRows: `${dashboardConfig.value.rowHeight}px`,
gridTemplateColumns: `repeat(${dashboardConfig.value.columns}, minmax(0, 1fr))`,
};
if (!dashboardConfig.value.showOuterMargin) {
style.marginLeft = `-${gapX}px`;
style.marginRight = `-${gapX}px`;
style.marginTop = `-${gapY}px`;
style.width = `calc(100% + ${gapX * 2}px)`;
}
return style;
});
function getWidget(i: string) {
if (!dashboardConfig.value) return null;
return dashboardConfig.value.widgets.find((w) => w.i === i);
}
function getAnimationDelay(i: string) {
if (!dashboardConfig.value) return 0;
const index = dashboardConfig.value.widgets.findIndex((w) => w.i === i);
return index * 60;
}
function getItemStyle(item: { h: number; w: number; x: number; y: number }) {
return {
gridColumn: `${item.x + 1} / span ${item.w}`,
gridRow: `${item.y + 1} / span ${item.h}`,
};
}
</script>
<template>
<div
class="dashboard-renderer h-full"
:style="
dashboardConfig?.backgroundColor?.includes('gradient')
? { background: dashboardConfig.backgroundColor }
: { backgroundColor: dashboardConfig?.backgroundColor || '' }
"
>
<div v-if="dashboardConfig && layout.length > 0">
<div :style="gridStyle">
<div
v-for="item in layout"
:key="item.i"
class="dashboard-widget"
:style="getItemStyle(item)"
>
<LightWidgetRenderer
v-if="getWidget(item.i)"
:widget="getWidget(item.i)!"
:is-design-mode="false"
:animation-delay="getAnimationDelay(item.i)"
/>
</div>
</div>
</div>
<ElEmpty
v-else
:description="$t('dashboard-design.noConfigTip')"
class="py-20"
/>
</div>
</template>
<style scoped>
.dashboard-renderer {
background-color: var(--el-bg-color-page);
}
.dashboard-widget {
overflow: hidden;
background: var(--el-bg-color);
border-radius: 8px;
box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
}
</style>
@@ -0,0 +1,147 @@
<script setup lang="ts">
import type {
DashboardWidget,
WidgetMaterial,
} from '../store/dashboardRuntimeStore';
import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
import { $t } from '@vben/locales';
import { defaultWidgetStyle } from '../store/dashboardRuntimeStore';
const props = defineProps<{
animationDelay?: number;
isDesignMode?: boolean;
material?: WidgetMaterial;
widget: DashboardWidget;
}>();
const isEntered = ref(false);
const isUpdating = ref(false);
const widgetComponents: Record<
string,
ReturnType<typeof defineAsyncComponent>
> = {
'announcement-list': defineAsyncComponent(
() => import('./widgets/AnnouncementList.vue'),
),
'approval-center': defineAsyncComponent(
() => import('./widgets/ApprovalCenter.vue'),
),
'my-apps': defineAsyncComponent(() => import('./widgets/MyApps.vue')),
'notice-list': defineAsyncComponent(() => import('./widgets/NoticeList.vue')),
'quick-links': defineAsyncComponent(() => import('./widgets/QuickLinks.vue')),
'server-monitor': defineAsyncComponent(
() => import('./widgets/ServerMonitor.vue'),
),
weather: defineAsyncComponent(() => import('./widgets/WeatherWidget.vue')),
'welcome-card': defineAsyncComponent(
() => import('./widgets/WelcomeCard.vue'),
),
};
const currentComponent = computed(() => widgetComponents[props.widget.type]);
const mergedWidget = computed(() => props.widget);
const widgetStyle = computed(() => {
const style = { ...defaultWidgetStyle, ...props.widget.style };
const css: Record<string, string> = {};
const bgValue = style.backgroundColor || 'var(--el-bg-color)';
if (bgValue.includes('gradient')) {
css.background = bgValue;
} else {
css.backgroundColor = bgValue;
}
if (style.borderWidth && style.borderWidth > 0) {
css.borderWidth = `${style.borderWidth}px`;
css.borderStyle = style.borderStyle || 'solid';
css.borderColor = style.borderColor || 'var(--el-border-color)';
}
if (style.borderRadius !== undefined) {
css.borderRadius = `${style.borderRadius}px`;
}
if (style.shadowEnabled) {
const color = style.shadowColor || 'rgba(0, 0, 0, 0.1)';
const blur = style.shadowBlur || 4;
const x = style.shadowOffsetX || 0;
const y = style.shadowOffsetY || 1;
css.boxShadow = `${x}px ${y}px ${blur}px ${color}`;
} else {
css.boxShadow = 'none';
}
return css;
});
onMounted(() => {
setTimeout(() => {
isEntered.value = true;
}, props.animationDelay || 0);
});
const animationClass = computed(() => ({
'widget-enter': true,
'widget-entered': isEntered.value,
'widget-updating': isUpdating.value,
}));
</script>
<template>
<div
class="widget-renderer relative h-full w-full overflow-hidden"
:class="animationClass"
:style="widgetStyle"
>
<component
:is="currentComponent"
v-if="currentComponent"
:widget="mergedWidget"
:is-design-mode="isDesignMode"
/>
<div
v-else
class="flex h-full w-full items-center justify-center text-gray-400"
>
{{ $t('dashboard-design.unknownWidget') }}: {{ widget.type }}
</div>
</div>
</template>
<style scoped>
@keyframes pulse-update {
0% {
transform: scale(1);
}
50% {
box-shadow: 0 0 0 2px var(--el-color-primary-light-5);
transform: scale(1.02);
}
100% {
transform: scale(1);
}
}
.widget-enter {
opacity: 0;
transform: translateY(20px) scale(0.95);
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.widget-entered {
opacity: 1;
transform: translateY(0) scale(1);
}
.widget-updating {
animation: pulse-update 0.3s ease-in-out;
}
</style>
@@ -2,7 +2,7 @@
import type {
DashboardWidget,
WidgetMaterial,
} from '../store/dashboardDesignStore';
} from '../store/dashboardRuntimeStore';
import {
computed,
@@ -18,8 +18,8 @@ import { $t } from '@vben/locales';
import {
defaultWidgetStyle,
useDashboardDesignStore,
} from '../store/dashboardDesignStore';
useDashboardRuntimeStore,
} from '../store/dashboardRuntimeStore';
import { createRefreshTimer, fetchWidgetData } from '../utils/dataFetcher';
const props = defineProps<{
@@ -106,15 +106,13 @@ const widgetComponents: Record<
'filter-select': defineAsyncComponent(
() => import('./widgets/FilterSelect.vue'),
),
'filter-date': defineAsyncComponent(
() => import('./widgets/FilterDate.vue'),
),
'filter-date': defineAsyncComponent(() => import('./widgets/FilterDate.vue')),
'filter-date-range': defineAsyncComponent(
() => import('./widgets/FilterDateRange.vue'),
),
};
const store = useDashboardDesignStore();
const store = useDashboardRuntimeStore();
const currentComponent = computed(() => {
return widgetComponents[props.widget.type];
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import type { UserAnnouncement } from '#/api/core/announcement';
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '#/components/dashboard-design';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed } from 'vue';
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, ref, watch } from 'vue';
@@ -7,14 +7,14 @@ import { $t } from '@vben/locales';
import { ElDatePicker } from 'element-plus';
import { useDashboardDesignStore } from '../../store/dashboardDesignStore';
import { useDashboardRuntimeStore } from '../../store/dashboardRuntimeStore';
const props = defineProps<{
isDesignMode?: boolean;
widget: DashboardWidget;
}>();
const store = useDashboardDesignStore();
const store = useDashboardRuntimeStore();
const dateValue = ref<string>(props.widget.props.defaultValue || '');
const label = computed(() => props.widget.props.label || '');
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, ref, watch } from 'vue';
@@ -7,14 +7,14 @@ import { $t } from '@vben/locales';
import { ElDatePicker } from 'element-plus';
import { useDashboardDesignStore } from '../../store/dashboardDesignStore';
import { useDashboardRuntimeStore } from '../../store/dashboardRuntimeStore';
const props = defineProps<{
isDesignMode?: boolean;
widget: DashboardWidget;
}>();
const store = useDashboardDesignStore();
const store = useDashboardRuntimeStore();
const dateRange = ref<[string, string] | []>(
props.widget.props.defaultValue || [],
);
@@ -30,12 +30,8 @@ const endPlaceholder = computed(
props.widget.props.endPlaceholder ||
$t('dashboard-design.material.defaultProps.filterEndDate'),
);
const startParamKey = computed(
() => props.widget.props.startParamKey || '',
);
const endParamKey = computed(
() => props.widget.props.endParamKey || '',
);
const startParamKey = computed(() => props.widget.props.startParamKey || '');
const endParamKey = computed(() => props.widget.props.endParamKey || '');
const dateFormat = computed(
() => props.widget.props.dateFormat || 'YYYY-MM-DD',
);
@@ -108,9 +104,7 @@ watch(
{ immediate: true },
);
const hasParamKey = computed(
() => startParamKey.value || endParamKey.value,
);
const hasParamKey = computed(() => startParamKey.value || endParamKey.value);
</script>
<template>
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, ref, watch } from 'vue';
@@ -8,14 +8,14 @@ import { $t } from '@vben/locales';
import { ElInput } from 'element-plus';
import { useDashboardDesignStore } from '../../store/dashboardDesignStore';
import { useDashboardRuntimeStore } from '../../store/dashboardRuntimeStore';
const props = defineProps<{
isDesignMode?: boolean;
widget: DashboardWidget;
}>();
const store = useDashboardDesignStore();
const store = useDashboardRuntimeStore();
const inputValue = ref(props.widget.props.defaultValue || '');
const label = computed(() => props.widget.props.label || '');
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, onMounted, ref, watch } from 'vue';
@@ -9,14 +9,14 @@ import { ElOption, ElSelect } from 'element-plus';
import { requestClient } from '#/api/request';
import { useDashboardDesignStore } from '../../store/dashboardDesignStore';
import { useDashboardRuntimeStore } from '../../store/dashboardRuntimeStore';
const props = defineProps<{
isDesignMode?: boolean;
widget: DashboardWidget;
}>();
const store = useDashboardDesignStore();
const store = useDashboardRuntimeStore();
const selectValue = ref<any>(props.widget.props.defaultValue || '');
const dynamicOptions = ref<{ label: string; value: any }[]>([]);
const loadingOptions = ref(false);
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '#/components/dashboard-design';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import type { ApplicationListItem } from '#/api/core/application';
import { computed, onMounted, ref } from 'vue';
@@ -107,20 +107,23 @@ onMounted(() => {
</div>
<!-- 应用网格 -->
<ElScrollbar class="flex-1">
<div
v-if="displayApps.length > 0"
class="flex flex-wrap gap-4"
>
<div v-if="displayApps.length > 0" class="flex flex-wrap gap-4">
<div
v-for="app in displayApps"
:key="app.id"
class="flex cursor-pointer flex-col items-center gap-2 transition-transform hover:scale-105 m-4"
class="m-4 flex cursor-pointer flex-col items-center gap-2 transition-transform hover:scale-105"
style="width: 72px"
@click="handleClick(app)"
>
<div
class="flex h-12 w-12 items-center justify-center rounded-xl"
style="background: linear-gradient(135deg, var(--el-color-primary-light-3), var(--el-color-primary))"
style="
background: linear-gradient(
135deg,
var(--el-color-primary-light-3),
var(--el-color-primary)
);
"
>
<IconifyIcon
v-if="app.icon"
@@ -129,9 +132,10 @@ onMounted(() => {
/>
<AppWindow v-else class="h-6 w-6 text-white" />
</div>
<span class="text-muted-foreground w-full truncate text-center text-xs">{{
getAppName(app)
}}</span>
<span
class="text-muted-foreground w-full truncate text-center text-xs"
>{{ getAppName(app) }}</span
>
</div>
</div>
<ElEmpty
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import type { Message } from '#/api/core/message';
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '#/components/dashboard-design';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed } from 'vue';
import { useRouter } from 'vue-router';
@@ -3,7 +3,7 @@ import type {
RealtimeStats,
ServerMonitorResponse,
} from '#/api/core/server-monitor';
import type { DashboardWidget } from '#/components/dashboard-design';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, onMounted, onUnmounted, ref } from 'vue';
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { DashboardWidget } from '../../store/dashboardDesignStore';
import type { DashboardWidget } from '../../store/dashboardRuntimeStore';
import { computed, onMounted, onUnmounted, ref } from 'vue';
@@ -0,0 +1,141 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
export type DataSourceType = 'api' | 'dataSource' | 'static' | 'upload';
export interface FieldMapping {
source: string;
target: string;
}
export interface ParamBinding {
globalKey: string;
paramName: string;
}
export interface DataSourceConfig {
apiBody?: Record<string, any>;
apiHeaders?: Record<string, string>;
apiMethod?: 'GET' | 'POST';
apiParams?: Record<string, any>;
apiUrl?: string;
dataPath?: string;
dataSourceCode?: string;
fieldMappings?: FieldMapping[];
paramBindings?: ParamBinding[];
refreshEnabled?: boolean;
refreshInterval?: number;
type: DataSourceType;
}
export interface WidgetStyle {
backgroundColor?: string;
backgroundImage?: string;
backgroundSize?: 'auto' | 'contain' | 'cover';
borderColor?: string;
borderRadius?: number;
borderStyle?: 'dashed' | 'dotted' | 'none' | 'solid';
borderWidth?: number;
padding?: number;
shadowBlur?: number;
shadowColor?: string;
shadowEnabled?: boolean;
shadowOffsetX?: number;
shadowOffsetY?: number;
titleAlign?: 'center' | 'left' | 'right';
titleColor?: string;
titleFontSize?: number;
titleFontWeight?: 'bold' | 'normal';
titleShow?: boolean;
}
export interface DashboardWidget {
dataSource?: DataSourceConfig;
h: number;
i: string;
id: string;
maxH?: number;
maxW?: number;
minH?: number;
minW?: number;
props: Record<string, any>;
style?: WidgetStyle;
title?: string;
type: string;
w: number;
x: number;
y: number;
}
export interface DashboardConfig {
backgroundColor?: string;
columns: number;
id: string;
margin: [number, number];
name: string;
rowHeight: number;
showOuterMargin?: boolean;
widgets: DashboardWidget[];
}
export interface WidgetMaterial {
category: 'chart' | 'filter' | 'list' | 'widget';
defaultH: number;
defaultProps: Record<string, any>;
defaultW: number;
icon: string;
minH?: number;
minW?: number;
title: string;
type: string;
}
export const defaultWidgetStyle: WidgetStyle = {
backgroundColor: '',
borderWidth: 0,
borderColor: '',
borderStyle: 'solid',
borderRadius: 8,
shadowEnabled: true,
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 4,
shadowOffsetX: 0,
shadowOffsetY: 1,
padding: 16,
titleShow: true,
titleFontSize: 14,
titleColor: '',
titleAlign: 'left',
titleFontWeight: 'normal',
};
export const useDashboardRuntimeStore = defineStore('dashboard-runtime', () => {
const globalParams = ref<Record<string, any>>({});
const globalParamsVersion = ref(0);
const updateGlobalParam = (key: string, value: any) => {
globalParams.value = { ...globalParams.value, [key]: value };
globalParamsVersion.value++;
};
const removeGlobalParam = (key: string) => {
const next = { ...globalParams.value };
delete next[key];
globalParams.value = next;
globalParamsVersion.value++;
};
const clearGlobalParams = () => {
globalParams.value = {};
globalParamsVersion.value++;
};
return {
clearGlobalParams,
globalParams,
globalParamsVersion,
removeGlobalParam,
updateGlobalParam,
};
});
@@ -1,7 +1,7 @@
import type {
DataSourceConfig,
FieldMapping,
} from '../store/dashboardDesignStore';
} from '../store/dashboardRuntimeStore';
import { $t } from '@vben/locales';
@@ -87,7 +87,9 @@ export async function fetchWidgetData(
try {
const response = await requestClient.get(
`/api/core/data-source/execute/${dataSource.dataSourceCode}`,
{ params: params && Object.keys(params).length > 0 ? params : undefined },
{
params: params && Object.keys(params).length > 0 ? params : undefined,
},
);
// 后端返回格式是 {data: ...},需要提取 data 字段
@@ -1,19 +1,69 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue';
import { defineAsyncComponent, h, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElEmpty, ElMessage, ElScrollbar } from 'element-plus';
import { getPageByCodeApi } from '#/api/core/page-manager';
import DashboardRenderer from '#/components/dashboard-design/DashboardRenderer.vue';
defineOptions({ name: 'PageRender' });
const lightHomeWidgetTypes = new Set([
'announcement-list',
'approval-center',
'my-apps',
'notice-list',
'quick-links',
'server-monitor',
'weather',
'welcome-card',
]);
const LightDashboardRenderer = defineAsyncComponent({
loader: () =>
import('#/components/dashboard-design/LightDashboardRenderer.vue'),
delay: 120,
loadingComponent: {
render: () =>
h(
'div',
{
class:
'flex h-full min-h-[240px] items-center justify-center text-sm text-gray-500',
},
'正在加载控制中心...',
),
},
errorComponent: {
render: () => h(ElEmpty, { description: '控制中心加载失败' }),
},
});
const DashboardRenderer = defineAsyncComponent({
loader: () => import('#/components/dashboard-design/DashboardRenderer.vue'),
delay: 120,
loadingComponent: {
render: () =>
h(
'div',
{
class:
'flex h-full min-h-[240px] items-center justify-center text-sm text-gray-500',
},
'正在加载页面组件...',
),
},
errorComponent: {
render: () => h(ElEmpty, { description: '页面组件加载失败' }),
},
});
const route = useRoute();
const loading = ref(false);
const pageConfig = ref('');
const pageName = ref('');
const pageCode = ref('');
const useLightRenderer = ref(false);
function getPageCode(): string {
if (route.query.pageCode) {
@@ -33,6 +83,19 @@ function getPageCode(): string {
return '';
}
function canUseLightRenderer(code: string, config: any): boolean {
if (code !== 'main_home') return false;
const widgets = config?.widgets;
return (
Array.isArray(widgets) &&
widgets.every(
(widget) =>
lightHomeWidgetTypes.has(widget?.type) &&
(!widget?.dataSource || widget.dataSource.type === 'static'),
)
);
}
async function loadPageData() {
const code = getPageCode();
if (!code) {
@@ -45,12 +108,16 @@ async function loadPageData() {
try {
const page = await getPageByCodeApi(code);
pageName.value = page.name;
pageConfig.value =
const rawConfig =
page.page_config && Object.keys(page.page_config).length > 0
? JSON.stringify(page.page_config)
: '';
? page.page_config
: null;
pageName.value = page.name;
useLightRenderer.value = canUseLightRenderer(code, rawConfig);
pageConfig.value = rawConfig ? JSON.stringify(rawConfig) : '';
} catch (error: any) {
useLightRenderer.value = false;
ElMessage.error(error?.message || '加载页面失败');
} finally {
loading.value = false;
@@ -72,7 +139,11 @@ watch(
<template>
<ElScrollbar class="rounded-[8px] py-3">
<div v-loading="loading" class="h-[calc(100vh-120px)] rounded-[8px] px-3">
<DashboardRenderer v-if="pageConfig" :config="pageConfig" />
<LightDashboardRenderer
v-if="pageConfig && useLightRenderer"
:config="pageConfig"
/>
<DashboardRenderer v-else-if="pageConfig" :config="pageConfig" />
<ElEmpty v-else-if="!loading" description="暂无页面配置" />
</div>
</ElScrollbar>
@@ -11,7 +11,14 @@ import type { ChatMessage } from '#/components/ChatBox/index';
* Agent 对话面板组件
* 可复用于 Agent 编辑页面和 Agent 对话页面
*/
import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
import {
computed,
defineAsyncComponent,
nextTick,
onUnmounted,
ref,
watch,
} from 'vue';
import { $t } from '@vben/locales';
@@ -23,10 +30,16 @@ import {
sendAgentMessageStream,
} from '#/api/ai-platform/ai-platform';
import { ChatBox } from '#/components/ChatBox/index';
import { AppDesignPanel, DesignEditorPanel } from '#/components/form-editor';
import AiWorkingAnimation from '../../../../components/ai-loading/AiWorkingAnimation.vue';
const AppDesignPanel = defineAsyncComponent(
() => import('#/components/form-editor/AppDesignPanel.vue'),
);
const DesignEditorPanel = defineAsyncComponent(
() => import('#/components/form-editor/DesignEditorPanel.vue'),
);
const props = defineProps<{
/** Agent 详情(可选,用于显示名称和欢迎配置) */
agent?: Agent | null;
@@ -11,7 +11,7 @@ import type {
SystemSummaryData,
} from '#/components/form-editor';
import { computed, onUnmounted, ref, watch } from 'vue';
import { computed, defineAsyncComponent, onUnmounted, ref, watch } from 'vue';
import { Settings2, X } from '@vben/icons';
import { $t } from '@vben/locales';
@@ -30,15 +30,27 @@ import {
runWorkflowStreamApi,
} from '#/api/ai-platform/ai-platform';
import { ChatBox } from '#/components/ChatBox/index';
import {
AppDesignPanel,
AppSettingsPanel,
DashboardBasicInfoConfirmPanel,
DashboardDesignConfirmPanel,
DashboardPublishConfirmPanel,
DesignEditorPanel,
SystemSummaryConfirmPanel,
} from '#/components/form-editor';
const AppDesignPanel = defineAsyncComponent(
() => import('#/components/form-editor/AppDesignPanel.vue'),
);
const AppSettingsPanel = defineAsyncComponent(
() => import('#/components/form-editor/AppSettingsPanel.vue'),
);
const DashboardBasicInfoConfirmPanel = defineAsyncComponent(
() => import('#/components/form-editor/DashboardBasicInfoConfirmPanel.vue'),
);
const DashboardDesignConfirmPanel = defineAsyncComponent(
() => import('#/components/form-editor/DashboardDesignConfirmPanel.vue'),
);
const DashboardPublishConfirmPanel = defineAsyncComponent(
() => import('#/components/form-editor/DashboardPublishConfirmPanel.vue'),
);
const DesignEditorPanel = defineAsyncComponent(
() => import('#/components/form-editor/DesignEditorPanel.vue'),
);
const SystemSummaryConfirmPanel = defineAsyncComponent(
() => import('#/components/form-editor/SystemSummaryConfirmPanel.vue'),
);
const props = defineProps<{
nodes: any[];
@@ -1250,6 +1262,7 @@ onUnmounted(() => {
<!-- 设计编辑面板 -->
<DesignEditorPanel
v-if="showDesignPanel"
:visible="showDesignPanel"
:design="currentDesign"
@update:visible="showDesignPanel = $event"
@@ -1259,6 +1272,7 @@ onUnmounted(() => {
<!-- 应用设计面板 -->
<AppDesignPanel
v-if="showAppDesignPanel"
:visible="showAppDesignPanel"
:design="currentAppDesign"
@update:visible="showAppDesignPanel = $event"
@@ -1268,6 +1282,7 @@ onUnmounted(() => {
<!-- 应用设置面板 -->
<AppSettingsPanel
v-if="showAppSettingsPanel"
:visible="showAppSettingsPanel"
:settings="currentAppSettings"
@update:visible="showAppSettingsPanel = $event"
@@ -1277,6 +1292,7 @@ onUnmounted(() => {
<!-- 仪表盘基础信息面板 -->
<DashboardBasicInfoConfirmPanel
v-if="showDashboardBasicInfoPanel"
:visible="showDashboardBasicInfoPanel"
:basic-info="currentDashboardBasicInfo"
@update:visible="showDashboardBasicInfoPanel = $event"
@@ -1286,6 +1302,7 @@ onUnmounted(() => {
<!-- 仪表盘设计面板 -->
<DashboardDesignConfirmPanel
v-if="showDashboardDesignPanel"
:visible="showDashboardDesignPanel"
:design="currentDashboardDesign"
@update:visible="showDashboardDesignPanel = $event"
@@ -1295,6 +1312,7 @@ onUnmounted(() => {
<!-- 仪表盘发布面板 -->
<DashboardPublishConfirmPanel
v-if="showDashboardPublishPanel"
:visible="showDashboardPublishPanel"
:publish-data="currentDashboardPublish"
@update:visible="showDashboardPublishPanel = $event"
@@ -1304,6 +1322,7 @@ onUnmounted(() => {
<!-- 系统总结面板 -->
<SystemSummaryConfirmPanel
v-if="showSystemSummaryPanel"
:visible="showSystemSummaryPanel"
:data="currentSystemSummary"
@update:visible="showSystemSummaryPanel = $event"