Restore full AI platform interactions

This commit is contained in:
2026-06-09 22:02:10 +08:00
parent 28169bd4ac
commit 0de22fa7e1
15 changed files with 1014 additions and 95 deletions
@@ -23,7 +23,7 @@ import {
sendAgentMessageStream,
} from '#/api/ai-platform/ai-platform';
import { ChatBox } from '#/components/ChatBox/index';
import { DesignEditorPanel } from '#/components/form-editor';
import { AppDesignPanel, DesignEditorPanel } from '#/components/form-editor';
import AiWorkingAnimation from '../../../../components/ai-loading/AiWorkingAnimation.vue';
@@ -54,6 +54,7 @@ const emit = defineEmits<{
// 设计面板显示状态
const showDesignPanel = ref(false);
const showAppDesignPanel = ref(false);
// 对话状态
const chatMessages = ref<AgentMessage[]>([]);
@@ -71,9 +72,17 @@ const waitingConfig = ref<any>(null);
// 设计面板状态
const currentDesign = ref<null | {
data: any;
data_sources?: any[];
form_fields?: any[];
nodeId: string;
table_configs?: any[];
title: string;
type: string;
}>(null);
// 应用设计面板状态
const currentAppDesign = ref<null | {
data: any;
nodeId: string;
schema_fields?: any[];
title: string;
type: string;
}>(null);
@@ -273,7 +282,7 @@ async function doSendMessage(message: string, addUserMessage: boolean = true) {
scrollToBottom();
// 发送流式请求
// 业务上下文由 API 层按 Agent 配置解析
// 系统变量(application_id 等)由 API 层自动注入
cancelStream = sendAgentMessageStream(
props.agentId,
{
@@ -484,17 +493,31 @@ function handleStreamEvent(
if (configData?.type === 'design_preview') {
const previewType = configData.preview_type;
currentDesign.value = {
type: previewType,
title:
configData.title ||
$t('ai-platform.agent.chatPanel.designPreview'),
data: configData.data || {},
nodeId: event.node_id || '',
data_sources: configData.data_sources || configData.table_configs || [],
schema_fields: configData.schema_fields || configData.form_fields || [],
};
showDesignPanel.value = true;
// 应用设计方案使用 AppDesignPanel(富文本编辑器)
if (previewType === 'app_design') {
currentAppDesign.value = {
type: previewType,
title:
configData.title ||
$t('ai-platform.agent.chatPanel.appDesignTitle'),
data: configData.data || {},
nodeId: event.node_id || '',
};
showAppDesignPanel.value = true;
} else {
// 其他设计类型使用 DesignEditorPanel(表单编辑器)
currentDesign.value = {
type: previewType,
title:
configData.title ||
$t('ai-platform.agent.chatPanel.designPreview'),
data: configData.data || {},
nodeId: event.node_id || '',
form_fields: configData.form_fields || [],
table_configs: configData.table_configs || [],
};
showDesignPanel.value = true;
}
// 显示提示消息
const waitingContent = `**${configData.title}**\n\n${configData.message || $t('ai-platform.agent.chatPanel.designPanelHint')}`;
@@ -772,6 +795,46 @@ function handleDesignCancel() {
currentDesign.value = null;
}
// 应用设计面板确认
function handleAppDesignConfirm(data: Record<string, any>) {
showAppDesignPanel.value = false;
// 添加用户确认消息
const userMsg: AgentMessage = {
id: generateId(),
role: 'user',
content: $t('ai-platform.agent.chatPanel.confirmAppDesign'),
status: 'completed',
reasoning_steps: [],
tool_calls: [],
prompt_tokens: 0,
completion_tokens: 0,
total_tokens: 0,
elapsed_time: 0,
error_message: '',
feedback: '',
created_at: new Date().toISOString(),
};
chatMessages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
currentAppDesign.value = null;
// 继续工作流,传递编辑后的数据
doSendMessage(JSON.stringify(data), false);
}
// 应用设计面板取消
function handleAppDesignCancel() {
showAppDesignPanel.value = false;
waitingForInput.value = false;
waitingConfig.value = null;
currentAppDesign.value = null;
}
// 暴露方法给父组件
defineExpose({
clearChat,
scrollToBottom,
@@ -838,13 +901,26 @@ onUnmounted(() => {
title: currentDesign.title,
data: currentDesign.data,
nodeId: currentDesign.nodeId,
data_sources: currentDesign.data_sources,
schema_fields: currentDesign.schema_fields,
form_fields: currentDesign.form_fields,
table_configs: currentDesign.table_configs,
}"
@confirm="handleDesignConfirm"
@close="handleDesignCancel"
/>
</div>
<!-- 应用设计面板 -->
<div
v-if="showAppDesignPanel && currentAppDesign"
class="flex flex-1 flex-col overflow-hidden"
>
<AppDesignPanel
:visible="showAppDesignPanel"
:design="currentAppDesign as any"
@update:visible="showAppDesignPanel = $event"
@confirm="handleAppDesignConfirm"
@close="handleAppDesignCancel"
/>
</div>
</div>
</template>
@@ -291,12 +291,9 @@ async function handlePreviewDoc(doc: KnowledgeDocumentListItem) {
docPreviewUrlList.value = [url];
docPreviewVisible.value = true;
} else {
try {
const url = await getFileUrl(doc.file_id);
window.open(url, '_blank');
} catch {
ElMessage.error($t('ai-platform.knowledge.chunkPreview.error'));
}
const ext = getDocFileExt(doc);
const query = new URLSearchParams({ name: doc.name || '', ext });
window.open(`/file-preview/${doc.file_id}?${query.toString()}`, '_blank');
}
}
@@ -870,7 +867,7 @@ async function handleSaveSettings() {
}
function handleBack() {
router.push(appContextStore.getContextPath('/ai-platform/knowledge-base'));
router.push(appContextStore.getContextPath('/ai-platform/knowledge'));
}
// Tab 切换时加载数据
@@ -5,6 +5,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import { $t } from '@vben/locales';
import { getWorkflowListApi } from '#/api/ai-platform/ai-platform';
import { useAppContextStore } from '#/store/app-context';
type TagType = 'danger' | 'info' | 'primary' | 'success' | 'warning';
@@ -51,6 +52,8 @@ export function formatTime(value?: string) {
}
export function useSearchFormSchema(): VbenFormSchema[] {
const appContextStore = useAppContextStore();
return [
{
component: 'ApiSelect',
@@ -58,7 +61,11 @@ export function useSearchFormSchema(): VbenFormSchema[] {
label: $t('ai-platform.workflowRuns.filters.workflow'),
componentProps: {
api: async () => {
const res = await getWorkflowListApi({ page: 1, pageSize: 200 });
const res = await getWorkflowListApi({
page: 1,
pageSize: 200,
applicationId: appContextStore.currentApp?.id,
});
return (res.items || []).map((item) => ({
label: item.name,
value: item.id,
@@ -11,6 +11,7 @@ import { ElButton, ElTag } from 'element-plus';
import { getAllWorkflowRunsApi } from '#/api/ai-platform/ai-platform';
import { useZqTable } from '#/components/zq-table';
import { useAppContextStore } from '#/store/app-context';
import RunStatusTag from './components/RunStatusTag.vue';
import {
@@ -26,6 +27,7 @@ import DetailDialog from './modules/detail-dialog.vue';
defineOptions({ name: 'WorkflowRunHistory' });
const appContextStore = useAppContextStore();
const detailRef = ref<InstanceType<typeof DetailDialog>>();
const triggerOptions = getTriggerOptions();
@@ -36,6 +38,7 @@ const fetchRunList = async (params: any) => {
workflowId: params.form?.workflowId || undefined,
status: params.form?.status || undefined,
triggerType: params.form?.triggerType || undefined,
applicationId: appContextStore.currentApp?.id,
});
return {
items: res.items,
@@ -2,13 +2,18 @@
import type { WorkflowStreamEvent } from '#/api/ai-platform/ai-platform';
import type { ChatMessage, ReasoningStep } from '#/components/ChatBox/index';
import type {
AppDesignData,
AppSettingsData,
DashboardBasicInfoData,
DashboardDesignData,
DashboardPublishData,
DesignData,
SystemSummaryData,
} from '#/components/form-editor';
import { computed, onUnmounted, ref, watch } from 'vue';
import { Close, Setting } from '@element-plus/icons-vue';
import { Settings2, X } from '@vben/icons';
import { $t } from '@vben/locales';
import {
@@ -26,6 +31,11 @@ import {
} from '#/api/ai-platform/ai-platform';
import { ChatBox } from '#/components/ChatBox/index';
import {
AppDesignPanel,
AppSettingsPanel,
DashboardBasicInfoConfirmPanel,
DashboardDesignConfirmPanel,
DashboardPublishConfirmPanel,
DesignEditorPanel,
SystemSummaryConfirmPanel,
} from '#/components/form-editor';
@@ -64,6 +74,30 @@ const currentRunId = ref('');
const showDesignPanel = ref(false);
const currentDesign = ref<DesignData | undefined>(undefined);
// 应用设计面板状态
const showAppDesignPanel = ref(false);
const currentAppDesign = ref<AppDesignData | undefined>(undefined);
// 应用设置面板状态
const showAppSettingsPanel = ref(false);
const currentAppSettings = ref<AppSettingsData | undefined>(undefined);
// 仪表盘基础信息面板状态
const showDashboardBasicInfoPanel = ref(false);
const currentDashboardBasicInfo = ref<DashboardBasicInfoData | undefined>(
undefined,
);
// 仪表盘设计面板状态
const showDashboardDesignPanel = ref(false);
const currentDashboardDesign = ref<DashboardDesignData | undefined>(undefined);
// 仪表盘发布面板状态
const showDashboardPublishPanel = ref(false);
const currentDashboardPublish = ref<DashboardPublishData | undefined>(
undefined,
);
// 系统总结面板状态
const showSystemSummaryPanel = ref(false);
const currentSystemSummary = ref<SystemSummaryData | undefined>(undefined);
@@ -215,7 +249,7 @@ const runWorkflow = (userMessage: string, inputs: Record<string, any>) => {
running.value = true;
// 流式运行(编辑器调试模式,使用草稿版本)
// 业务上下文由 API 层按 Workflow 配置解析
// 系统变量(application_id 等)由 API 层自动注入
cancelStream = runWorkflowStreamApi(
props.workflowId,
inputs,
@@ -566,6 +600,84 @@ const handleStreamEvent = (event: WorkflowStreamEvent, msgId: string) => {
if (configData?.type === 'design_preview') {
// 检查是否是应用设计类型
switch (configData.preview_type) {
case 'app_design': {
// 应用设计:打开专用的应用设计面板
currentAppDesign.value = {
type: 'app_design',
title:
configData.title ||
$t('ai-platform.workflow.editor.chatPanel.appDesignTitle'),
data: configData.data || {},
nodeId: event.node_id || '',
};
showAppDesignPanel.value = true;
break;
}
case 'app_settings': {
// 应用设置:打开专用的应用设置面板
currentAppSettings.value = {
type: 'app_settings',
title:
configData.title ||
$t('ai-platform.workflow.editor.chatPanel.appSettingsTitle'),
data: configData.data || {},
nodeId: event.node_id || '',
layoutOptions: configData.layoutOptions || [],
themeOptions: configData.themeOptions || [],
};
showAppSettingsPanel.value = true;
break;
}
case 'dashboard_basic_info': {
// 仪表盘基础信息:打开专用面板(在聊天框右侧)
currentDashboardBasicInfo.value = {
type: 'dashboard_basic_info',
title:
configData.title ||
$t(
'ai-platform.workflow.editor.chatPanel.dashboardBasicInfoTitle',
),
data: configData.data || {},
nodeId: event.node_id || '',
};
showDashboardBasicInfoPanel.value = true;
break;
}
case 'dashboard_design': {
// 仪表盘设计:打开设计器面板(在聊天框右侧)
currentDashboardDesign.value = {
type: 'dashboard_design',
title:
configData.title ||
$t(
'ai-platform.workflow.editor.chatPanel.dashboardDesignTitle',
),
data: configData.data || {},
nodeId: event.node_id || '',
};
showDashboardDesignPanel.value = true;
break;
}
case 'dashboard_publish': {
// 仪表盘发布:打开发布确认面板(在聊天框右侧)
currentDashboardPublish.value = {
type: 'dashboard_publish',
title:
configData.title ||
$t(
'ai-platform.workflow.editor.chatPanel.dashboardPublishTitle',
),
data: configData.data || {},
nodeId: event.node_id || '',
};
showDashboardPublishPanel.value = true;
break;
}
case 'system_summary': {
// 系统总结:打开总结展示面板
currentSystemSummary.value = {
@@ -589,10 +701,8 @@ const handleStreamEvent = (event: WorkflowStreamEvent, msgId: string) => {
$t('ai-platform.workflow.editor.chatPanel.designPreviewTitle'),
data: configData.data || {},
nodeId: event.node_id || '',
data_sources:
configData.data_sources || configData.table_configs || [],
schema_fields:
configData.schema_fields || configData.form_fields || [],
form_fields: configData.form_fields || [], // 传递表单字段列表(用于列表设计)
table_configs: configData.table_configs || [], // 传递数据表配置(用于表单设计)
};
showDesignPanel.value = true;
}
@@ -869,6 +979,153 @@ const handleDesignClose = () => {
};
// 处理应用设计确认
const handleAppDesignConfirm = (data: Record<string, any>) => {
showAppDesignPanel.value = false;
currentAppDesign.value = undefined;
// 添加用户确认消息
const userMsg: ChatMessage = {
id: generateId(),
role: 'user',
content: $t('ai-platform.workflow.editor.chatPanel.confirmAppDesign'),
timestamp: new Date(),
};
messages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
// 恢复工作流,传递编辑后的数据
resumeWorkflow(JSON.stringify(data));
};
// 处理应用设计面板关闭
const handleAppDesignClose = () => {
showAppDesignPanel.value = false;
currentAppDesign.value = undefined;
};
// 处理应用设置确认
const handleAppSettingsConfirm = (data: Record<string, any>) => {
showAppSettingsPanel.value = false;
currentAppSettings.value = undefined;
// 添加用户确认消息
const userMsg: ChatMessage = {
id: generateId(),
role: 'user',
content: $t('ai-platform.workflow.editor.chatPanel.confirmAppSettings'),
timestamp: new Date(),
};
messages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
// 恢复工作流,传递编辑后的数据
resumeWorkflow(JSON.stringify(data));
};
// 处理应用设置面板关闭
const handleAppSettingsClose = () => {
showAppSettingsPanel.value = false;
currentAppSettings.value = undefined;
};
// 处理仪表盘基础信息确认
const handleDashboardBasicInfoConfirm = (data: Record<string, any>) => {
showDashboardBasicInfoPanel.value = false;
currentDashboardBasicInfo.value = undefined;
// 添加用户确认消息
const userMsg: ChatMessage = {
id: generateId(),
role: 'user',
content: $t(
'ai-platform.workflow.editor.chatPanel.confirmDashboardBasicInfo',
),
timestamp: new Date(),
};
messages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
// 恢复工作流,传递编辑后的数据
resumeWorkflow(JSON.stringify(data));
};
// 处理仪表盘基础信息面板关闭
const handleDashboardBasicInfoClose = () => {
showDashboardBasicInfoPanel.value = false;
currentDashboardBasicInfo.value = undefined;
};
// 处理仪表盘设计确认
const handleDashboardDesignConfirm = (data: Record<string, any>) => {
showDashboardDesignPanel.value = false;
currentDashboardDesign.value = undefined;
// 添加用户确认消息
const userMsg: ChatMessage = {
id: generateId(),
role: 'user',
content: $t('ai-platform.workflow.editor.chatPanel.confirmDashboardDesign'),
timestamp: new Date(),
};
messages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
// 恢复工作流,传递编辑后的数据
resumeWorkflow(JSON.stringify(data));
};
// 处理仪表盘设计面板关闭
const handleDashboardDesignClose = () => {
showDashboardDesignPanel.value = false;
currentDashboardDesign.value = undefined;
};
// 处理仪表盘发布确认
const handleDashboardPublishConfirm = (data: Record<string, any>) => {
console.log('[ChatPanel] 接收到发布确认数据:', data);
showDashboardPublishPanel.value = false;
currentDashboardPublish.value = undefined;
// 添加用户确认消息
const userMsg: ChatMessage = {
id: generateId(),
role: 'user',
content: $t('ai-platform.workflow.editor.chatPanel.publishToMenu', {
name: data.menu_name,
}),
timestamp: new Date(),
};
messages.value.push(userMsg);
// 重置等待状态
waitingForInput.value = false;
waitingConfig.value = null;
// 恢复工作流,传递发布数据
const userInputStr = JSON.stringify(data);
console.log('[ChatPanel] 传递给 resumeWorkflow 的数据:', userInputStr);
resumeWorkflow(userInputStr);
};
// 处理仪表盘发布面板关闭
const handleDashboardPublishClose = () => {
showDashboardPublishPanel.value = false;
currentDashboardPublish.value = undefined;
};
// 处理系统总结确认
const handleSystemSummaryConfirm = (data: Record<string, any>) => {
showSystemSummaryPanel.value = false;
currentSystemSummary.value = undefined;
@@ -920,11 +1177,11 @@ onUnmounted(() => {
<ElButton
v-if="hasMultipleVariables"
link
:icon="Setting"
:icon="Settings2"
:title="$t('ai-platform.workflow.editor.chatPanel.configVariables')"
@click="variablesDialogVisible = true"
/>
<ElButton link :icon="Close" @click="$emit('close')" />
<ElButton link :icon="X" @click="$emit('close')" />
</div>
</div>
@@ -1001,6 +1258,51 @@ onUnmounted(() => {
/>
<!-- 应用设计面板 -->
<AppDesignPanel
:visible="showAppDesignPanel"
:design="currentAppDesign"
@update:visible="showAppDesignPanel = $event"
@confirm="handleAppDesignConfirm"
@close="handleAppDesignClose"
/>
<!-- 应用设置面板 -->
<AppSettingsPanel
:visible="showAppSettingsPanel"
:settings="currentAppSettings"
@update:visible="showAppSettingsPanel = $event"
@confirm="handleAppSettingsConfirm"
@close="handleAppSettingsClose"
/>
<!-- 仪表盘基础信息面板 -->
<DashboardBasicInfoConfirmPanel
:visible="showDashboardBasicInfoPanel"
:basic-info="currentDashboardBasicInfo"
@update:visible="showDashboardBasicInfoPanel = $event"
@confirm="handleDashboardBasicInfoConfirm"
@close="handleDashboardBasicInfoClose"
/>
<!-- 仪表盘设计面板 -->
<DashboardDesignConfirmPanel
:visible="showDashboardDesignPanel"
:design="currentDashboardDesign"
@update:visible="showDashboardDesignPanel = $event"
@confirm="handleDashboardDesignConfirm"
@close="handleDashboardDesignClose"
/>
<!-- 仪表盘发布面板 -->
<DashboardPublishConfirmPanel
:visible="showDashboardPublishPanel"
:publish-data="currentDashboardPublish"
@update:visible="showDashboardPublishPanel = $event"
@confirm="handleDashboardPublishConfirm"
@close="handleDashboardPublishClose"
/>
<!-- 系统总结面板 -->
<SystemSummaryConfirmPanel
:visible="showSystemSummaryPanel"
:data="currentSystemSummary"
@@ -222,7 +222,7 @@ const formattedInputs = computed(() => {
v-if="displayResult.tokens_used"
class="text-muted-foreground text-sm"
>
消耗 Token{{ displayResult.tokens_used }}
Tokens: {{ displayResult.tokens_used }}
</span>
<div v-if="hasIterations" class="flex items-center gap-1.5">
<span class="text-muted-foreground text-xs">
@@ -54,6 +54,7 @@ const components: Record<string, any> = {
),
// 循环节点
loop: defineAsyncComponent(() => import('../panels/LoopPanel.vue')),
// 表单节点
form_basic_info: defineAsyncComponent(
() => import('../panels/FormBasicInfoPanel.vue'),
),
@@ -75,6 +76,7 @@ const components: Record<string, any> = {
form_publish: defineAsyncComponent(
() => import('../panels/FormPublishPanel.vue'),
),
// 应用节点
app_create: defineAsyncComponent(
() => import('../panels/AppCreatePanel.vue'),
),
@@ -87,6 +89,7 @@ const components: Record<string, any> = {
app_update: defineAsyncComponent(
() => import('../panels/AppUpdatePanel.vue'),
),
// 仪表盘节点
dashboard_basic_info: defineAsyncComponent(
() => import('../panels/DashboardBasicInfoPanel.vue'),
),
@@ -99,9 +102,13 @@ const components: Record<string, any> = {
dashboard_publish: defineAsyncComponent(
() => import('../panels/DashboardPublishPanel.vue'),
),
// 系统总结节点
system_summary: defineAsyncComponent(
() => import('../panels/SystemSummaryPanel.vue'),
),
// 子流程节点
subflow: defineAsyncComponent(() => import('../panels/SubflowPanel.vue')),
// 表单数据节点
form_data_create: defineAsyncComponent(
() => import('../panels/FormDataPanel.vue'),
),
@@ -120,8 +127,6 @@ const components: Record<string, any> = {
form_schema_to_llm: defineAsyncComponent(
() => import('../panels/FormDataPanel.vue'),
),
// 子流程节点
subflow: defineAsyncComponent(() => import('../panels/SubflowPanel.vue')),
// Text-to-SQL 节点
text_to_sql: defineAsyncComponent(
() => import('../panels/TextToSqlPanel.vue'),
@@ -90,7 +90,7 @@ const totalStats = computed(() => {
(sum, s) => sum + (s.elapsed_time || 0),
0,
);
const totalTokenCount = completed.reduce(
const totalTokens = completed.reduce(
(sum, s) => sum + (s.tokens_used || 0),
0,
);
@@ -101,7 +101,7 @@ const totalStats = computed(() => {
failed: states.filter((s) => s.status === 'failed').length,
running: states.filter((s) => s.status === 'running').length,
totalTime,
totalTokenCount,
totalTokens,
};
});
@@ -547,8 +547,8 @@ const handleStop = () => {
{{ totalStats.completed }}/{{ totalStats.total }}
{{ $t('ai-platform.workflow.editor.runPanel.nodes') }}
</ElTag>
<ElTag v-if="totalStats.totalTokenCount > 0" size="small">
消耗 Token{{ totalStats.totalTokenCount }}
<ElTag v-if="totalStats.totalTokens > 0" size="small">
{{ totalStats.totalTokens }} tokens
</ElTag>
<ElTag v-if="totalStats.totalTime > 0" size="small">
{{ formatTime(totalStats.totalTime) }}
@@ -631,7 +631,7 @@ const handleStop = () => {
class="mt-1 pl-5"
>
<span v-if="state.tokens_used" class="text-muted-foreground">
消耗 Token{{ state.tokens_used }}
{{ state.tokens_used }} tokens
</span>
<span
v-if="state.error_message"
@@ -2,26 +2,28 @@
import { computed, ref } from 'vue';
import {
ArrowDown,
ArrowRight,
ChatLineRound,
Check,
Coin,
Collection,
Connection,
Cpu,
DataAnalysis,
Document,
Finished,
Guide,
Help,
Link,
MagicStick,
Operation,
AppWindow,
BookOpen,
Bot,
ChevronDown,
ChevronRight,
CircleHelp,
ClipboardCheck,
Code,
Combine,
Database,
FileText,
Globe,
HelpCircle,
LayoutDashboard,
LayoutTemplate,
ListChecks,
MessageSquareText,
Play,
Search,
Switch,
VideoPlay,
} from '@element-plus/icons-vue';
Snowflake,
Square,
} from '@vben/icons';
import { $t } from '@vben/locales';
import { useVueFlow } from '@vue-flow/core';
@@ -39,29 +41,52 @@ const collapsedNodes = ref<Set<string>>(new Set());
// 定义不同节点的图标
const icons: any = {
start: VideoPlay,
llm: MagicStick,
http: Link,
code: Cpu,
template: Document,
end: Finished,
db_query: Coin,
db_insert: Coin,
db_update: Coin,
db_delete: Coin,
db_sql: Coin,
question: Help,
choice: Operation,
message: ChatLineRound,
confirm: Check,
snowflake_cortex_llm: DataAnalysis,
snowflake_cortex_analyst: DataAnalysis,
loop: Switch,
merge: Connection,
subflow: Guide,
knowledge_retrieval: Collection,
start: Play,
llm: Bot,
http: Globe,
code: Code,
template: LayoutTemplate,
end: Square,
db_query: Database,
db_insert: Database,
db_update: Database,
db_delete: Database,
db_sql: Database,
// 对话流节点
question: HelpCircle,
choice: ListChecks,
message: MessageSquareText,
confirm: CircleHelp,
// Snowflake Cortex 节点
snowflake_cortex_llm: Snowflake,
snowflake_cortex_analyst: Snowflake,
// 循环节点
loop: Play,
// 合并节点
merge: Combine,
// 表单节点
form_basic_info: FileText,
form_database_design: Database,
form_database_create: Database,
// 应用节点
app_create: AppWindow,
app_design: LayoutDashboard,
app_settings: LayoutDashboard,
app_update: LayoutDashboard,
// 仪表盘节点
dashboard_basic_info: LayoutDashboard,
dashboard_design: LayoutDashboard,
dashboard_create: LayoutDashboard,
dashboard_publish: LayoutDashboard,
// 系统总结节点
system_summary: ClipboardCheck,
// 子流程节点
subflow: Play,
// 知识库检索节点
knowledge_retrieval: BookOpen,
};
// 获取当前节点的父循环节点(如果存在)
const getParentLoopNode = (nodeId: string) => {
const currentNode = nodes.value.find((n) => n.id === nodeId);
if (currentNode?.parentNode) {
@@ -114,6 +139,92 @@ const availableNodes = computed(() => {
// 根据节点类型获取输出变量 schema
switch (node.type) {
case 'app_create': {
variables = [
{
key: 'app_id',
label: $t('ai-platform.workflow.editor.variableSelector.appId'),
},
{
key: 'app_code',
label: $t('ai-platform.workflow.editor.variableSelector.appCode'),
},
{
key: 'app_name',
label: $t('ai-platform.workflow.editor.variableSelector.appName'),
},
{
key: 'success',
label: $t(
'ai-platform.workflow.editor.variableSelector.createSuccess',
),
},
];
break;
}
case 'app_design': {
variables = [
{
key: 'design_content',
label: $t(
'ai-platform.workflow.editor.variableSelector.designContent',
),
},
{
key: 'design_title',
label: $t(
'ai-platform.workflow.editor.variableSelector.designTitle',
),
},
{
key: 'confirmed',
label: $t(
'ai-platform.workflow.editor.variableSelector.isConfirmed',
),
},
];
break;
}
case 'app_settings': {
variables = [
{
key: 'settings',
label: $t(
'ai-platform.workflow.editor.variableSelector.appSettings',
),
},
{
key: 'confirmed',
label: $t(
'ai-platform.workflow.editor.variableSelector.isConfirmed',
),
},
];
break;
}
case 'app_update': {
variables = [
{
key: 'update_success',
label: $t(
'ai-platform.workflow.editor.variableSelector.updateSuccess',
),
},
{
key: 'config_id',
label: $t(
'ai-platform.workflow.editor.variableSelector.configId',
),
},
{
key: 'update_message',
label: $t(
'ai-platform.workflow.editor.variableSelector.updateMessage',
),
},
];
break;
}
case 'choice': {
const choiceVar = node.data.variable_name || 'user_choice';
variables = [
@@ -169,6 +280,96 @@ const availableNodes = computed(() => {
];
break;
}
case 'dashboard_basic_info': {
variables = [
{
key: 'dashboard_basic_info',
label: $t(
'ai-platform.workflow.editor.variableSelector.dashboardBasicInfo',
),
},
{
key: 'dashboard_name',
label: $t(
'ai-platform.workflow.editor.variableSelector.dashboardName',
),
},
{
key: 'dashboard_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.dashboardCode',
),
},
];
break;
}
case 'dashboard_create': {
variables = [
{
key: 'dashboard_id',
label: $t(
'ai-platform.workflow.editor.variableSelector.dashboardId',
),
},
{
key: 'dashboard_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.dashboardCode',
),
},
{
key: 'page_meta',
label: $t(
'ai-platform.workflow.editor.variableSelector.pageMeta',
),
},
];
break;
}
case 'dashboard_design': {
variables = [
{
key: 'page_config',
label: $t(
'ai-platform.workflow.editor.variableSelector.pageConfig',
),
},
{
key: 'design_title',
label: $t(
'ai-platform.workflow.editor.variableSelector.designTitle',
),
},
{
key: 'confirmed',
label: $t(
'ai-platform.workflow.editor.variableSelector.isConfirmed',
),
},
];
break;
}
case 'dashboard_publish': {
variables = [
{
key: 'menu_id',
label: $t('ai-platform.workflow.editor.variableSelector.menuId'),
},
{
key: 'route_path',
label: $t(
'ai-platform.workflow.editor.variableSelector.routePath',
),
},
{
key: 'publish_result',
label: $t(
'ai-platform.workflow.editor.variableSelector.publishResult',
),
},
];
break;
}
case 'db_delete': {
const deleteOutputVar = node.data.output_variable || 'delete_result';
variables = [
@@ -259,6 +460,205 @@ const availableNodes = computed(() => {
];
break;
}
case 'form_basic_info': {
variables = [
{
key: 'form_basic_info',
label: $t(
'ai-platform.workflow.editor.variableSelector.formBasicInfoObj',
),
},
{
key: 'form_name',
label: $t(
'ai-platform.workflow.editor.variableSelector.formName',
),
},
{
key: 'form_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.formCode',
),
},
{
key: 'form_type',
label: $t(
'ai-platform.workflow.editor.variableSelector.formType',
),
},
{
key: 'form_description',
label: $t(
'ai-platform.workflow.editor.variableSelector.formDescription',
),
},
{
key: 'form_sort',
label: $t(
'ai-platform.workflow.editor.variableSelector.formSort',
),
},
];
break;
}
case 'form_create': {
variables = [
{
key: 'form_id',
label: $t('ai-platform.workflow.editor.variableSelector.formId'),
},
{
key: 'form_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.formCode',
),
},
{
key: 'form_meta',
label: $t(
'ai-platform.workflow.editor.variableSelector.formMeta',
),
},
];
break;
}
case 'form_database_create': {
variables = [
{
key: 'creation_result',
label: $t(
'ai-platform.workflow.editor.variableSelector.creationResult',
),
},
{
key: 'all_tables_ready',
label: $t(
'ai-platform.workflow.editor.variableSelector.allTablesReady',
),
},
{
key: 'created_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.createdCount',
),
},
{
key: 'error_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.errorCount',
),
},
{
key: 'schema_name',
label: $t(
'ai-platform.workflow.editor.variableSelector.schemaName',
),
},
{
key: 'table_name',
label: $t(
'ai-platform.workflow.editor.variableSelector.tableName',
),
},
];
break;
}
case 'form_database_design': {
variables = [
{
key: 'database_design',
label: $t(
'ai-platform.workflow.editor.variableSelector.dbDesignObj',
),
},
{
key: 'table_name',
label: $t(
'ai-platform.workflow.editor.variableSelector.tableName',
),
},
{
key: 'field_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.fieldCount',
),
},
];
break;
}
case 'form_list_design': {
variables = [
{
key: 'list_config',
label: $t(
'ai-platform.workflow.editor.variableSelector.listConfig',
),
},
{
key: 'query_field_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.queryFieldCount',
),
},
{
key: 'column_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.columnCount',
),
},
];
break;
}
case 'form_publish': {
variables = [
{
key: 'menu_id',
label: $t('ai-platform.workflow.editor.variableSelector.menuId'),
},
{
key: 'route_path',
label: $t(
'ai-platform.workflow.editor.variableSelector.routePath',
),
},
{
key: 'publish_result',
label: $t(
'ai-platform.workflow.editor.variableSelector.publishResult',
),
},
];
break;
}
case 'form_ui_design': {
variables = [
{
key: 'form_ui_design',
label: $t(
'ai-platform.workflow.editor.variableSelector.formUiDesign',
),
},
{
key: 'form_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.formCode',
),
},
{
key: 'field_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.fieldCount',
),
},
{
key: 'group_count',
label: $t(
'ai-platform.workflow.editor.variableSelector.groupCount',
),
},
];
break;
}
case 'http': {
variables = [
{
@@ -485,6 +885,23 @@ const availableNodes = computed(() => {
),
isSystem: true,
},
{
key: 'application_id',
label: $t('ai-platform.workflow.editor.variableSelector.appId'),
isSystem: true,
},
{
key: 'application_code',
label: $t('ai-platform.workflow.editor.variableSelector.appCode'),
isSystem: true,
},
{
key: 'form_code',
label: $t(
'ai-platform.workflow.editor.variableSelector.formCode',
),
isSystem: true,
},
];
// 加上自定义变量
variables.push(
@@ -548,6 +965,33 @@ const availableNodes = computed(() => {
}
break;
}
case 'system_summary': {
variables = [
{
key: 'summary',
label: $t(
'ai-platform.workflow.editor.variableSelector.summaryData',
),
},
{
key: 'total_forms',
label: $t(
'ai-platform.workflow.editor.variableSelector.totalForms',
),
},
{
key: 'has_app',
label: $t('ai-platform.workflow.editor.variableSelector.hasApp'),
},
{
key: 'has_dashboard',
label: $t(
'ai-platform.workflow.editor.variableSelector.hasDashboard',
),
},
];
break;
}
case 'template': {
const templateOutputVar =
node.data.output_variable || 'template_result';
@@ -663,7 +1107,7 @@ const handleSelect = (nodeId: string, variable: string) => {
@click="toggleNodeCollapse(node.id)"
>
<component
:is="isNodeCollapsed(node.id) ? ArrowRight : ArrowDown"
:is="isNodeCollapsed(node.id) ? ChevronRight : ChevronDown"
class="text-muted-foreground size-3 shrink-0"
/>
<component
@@ -184,6 +184,7 @@ const nodeTypes = {
snowflake_cortex_analyst: markRaw(SnowflakeCortexAnalystNode),
// 循环节点
loop: markRaw(LoopNode),
// 表单节点
form_basic_info: markRaw(FormBasicInfoNode),
form_database_design: markRaw(FormDatabaseDesignNode),
form_database_create: markRaw(FormDatabaseCreateNode),
@@ -191,23 +192,27 @@ const nodeTypes = {
form_list_design: markRaw(FormListDesignNode),
form_create: markRaw(FormCreateNode),
form_publish: markRaw(FormPublishNode),
// 应用管理节点
app_create: markRaw(AppCreateNode),
app_design: markRaw(AppDesignNode),
app_settings: markRaw(AppSettingsNode),
app_update: markRaw(AppUpdateNode),
// 仪表盘节点
dashboard_basic_info: markRaw(DashboardBasicInfoNode),
dashboard_design: markRaw(DashboardDesignNode),
dashboard_create: markRaw(DashboardCreateNode),
dashboard_publish: markRaw(DashboardPublishNode),
// 系统总结节点
system_summary: markRaw(SystemSummaryNode),
// 子流程节点
subflow: markRaw(SubflowNode),
// 表单数据节点
form_data_create: markRaw(FormDataNode),
form_data_read: markRaw(FormDataNode),
form_data_update: markRaw(FormDataNode),
form_data_delete: markRaw(FormDataNode),
form_data_list: markRaw(FormDataNode),
form_schema_to_llm: markRaw(FormDataNode),
// 子流程节点
subflow: markRaw(SubflowNode),
// Text-to-SQL 节点
text_to_sql: markRaw(TextToSqlNode),
// 知识库节点
@@ -715,19 +720,19 @@ const iconComponents: Record<string, any> = {
// 循环节点图标
RefreshCw,
CornerDownLeft,
// 表单节点图标
FileText,
TableProperties,
LayoutDashboard,
Settings,
FilePlus,
Upload,
ClipboardCheck,
// 表单节点图标
Send,
// 应用节点图标
LayoutDashboard,
Settings,
Save,
// 仪表盘节点图标
FilePlus,
Upload,
// 系统总结节点图标
ClipboardCheck,
// 子流程节点图标
Workflow,
// 知识库节点图标
@@ -736,8 +741,10 @@ const iconComponents: Record<string, any> = {
// 过滤后的节点分类
const filteredNodeCategories = computed(() => {
// 首先根据工作流类型过滤分类
let categories = nodeCategories.value;
// 如果是通用类型,排除表单设计、应用管理、仪表盘分组
if (workflow.value?.workflow_type === 'general') {
const excludeNames = new Set([
$t('ai-platform.workflow.editor.categories.appManage'),
@@ -279,7 +279,7 @@ const nodeColorConfig = computed(() => {
class="size-3"
/>
<span v-if="executionStatus.status === 'running'">运行中...</span>
<span v-if="executionStatus.status === 'running'">Running...</span>
<span v-else-if="executionStatus.elapsed_time !== undefined">{{ executionStatus.elapsed_time }}ms</span>
</div>
@@ -357,7 +357,7 @@ const nodeColorConfig = computed(() => {
"
ref="addButtonRef"
class="bg-primary hover:bg-primary/90 absolute -right-8 top-1/2 flex size-6 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full text-white opacity-0 shadow-md transition-opacity hover:scale-110 group-hover:opacity-100"
title="添加下一个节点"
title="{{ $t('ai-platform.workflow.nodes.common.addNextNode') }}"
@click.stop="handleClick"
>
<Plus class="pointer-events-none size-3.5" />
@@ -173,7 +173,7 @@ watch(
<XCircle class="size-3 cursor-help" />
</ElTooltip>
<XCircle v-else-if="isFailed" class="size-3" />
<span v-if="isRunning">运行中...</span>
<span v-if="isRunning">Running...</span>
<span v-else-if="executionStatus.elapsed_time !== undefined">
{{ executionStatus.elapsed_time }}ms
</span>
@@ -124,7 +124,7 @@ const removeExample = (intentIndex: number, exampleIndex: number) => {
<ElFormItem :label="$t('ai-platform.workflow.panels.common.model')">
<ElSelect
v-model="form.model_id"
:placeholder="$t('ai-platform.workflow.panels.intent.selectModelHint')"
placeholder="{{ $t('ai-platform.workflow.panels.intent.selectModelHint') }}"
>
<ElOption
v-for="m in models"
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
import { Delete as Trash2, Plus } from '@element-plus/icons-vue';
import { Plus, Trash2 } from '@vben/icons';
import { $t } from '@vben/locales';
import { ElButton, ElForm, ElInput, ElOption, ElSelect } from 'element-plus';
@@ -50,6 +50,45 @@ const handleDelete = (index: number) => {
</div>
</div>
<!-- 默认的 application_id 变量不可删除 -->
<div class="border-primary/30 bg-primary/5 rounded border p-3">
<div class="mb-2 flex items-center justify-between">
<span class="text-primary text-sm font-medium">application_id</span>
<span class="text-muted-foreground text-xs">{{
$t('ai-platform.workflow.panels.common.sysVar')
}}</span>
</div>
<div class="text-muted-foreground text-xs">
{{ $t('ai-platform.workflow.panels.start.appIdDesc') }}
</div>
</div>
<!-- 默认的 application_code 变量不可删除 -->
<div class="border-primary/30 bg-primary/5 rounded border p-3">
<div class="mb-2 flex items-center justify-between">
<span class="text-primary text-sm font-medium">application_code</span>
<span class="text-muted-foreground text-xs">{{
$t('ai-platform.workflow.panels.common.sysVar')
}}</span>
</div>
<div class="text-muted-foreground text-xs">
{{ $t('ai-platform.workflow.panels.start.appCodeDesc') }}
</div>
</div>
<!-- 默认的 form_code 变量不可删除 -->
<div class="border-primary/30 bg-primary/5 rounded border p-3">
<div class="mb-2 flex items-center justify-between">
<span class="text-primary text-sm font-medium">form_code</span>
<span class="text-muted-foreground text-xs">{{
$t('ai-platform.workflow.panels.common.sysVar')
}}</span>
</div>
<div class="text-muted-foreground text-xs">
{{ $t('ai-platform.workflow.panels.start.formCodeDesc') }}
</div>
</div>
<div class="flex items-center justify-between">
<span class="text-foreground text-sm font-medium">{{
$t('ai-platform.workflow.panels.common.customVars')
@@ -1,16 +1,32 @@
import { markRaw } from 'vue';
import AddButtonEdge from '../editor/edges/AddButtonEdge.vue';
import AppCreateNode from '../editor/nodes/AppCreateNode.vue';
import AppDesignNode from '../editor/nodes/AppDesignNode.vue';
import AppSettingsNode from '../editor/nodes/AppSettingsNode.vue';
import AppUpdateNode from '../editor/nodes/AppUpdateNode.vue';
import ChoiceNode from '../editor/nodes/ChoiceNode.vue';
import CodeNode from '../editor/nodes/CodeNode.vue';
import ConditionNode from '../editor/nodes/ConditionNode.vue';
import ConfirmNode from '../editor/nodes/ConfirmNode.vue';
import DashboardBasicInfoNode from '../editor/nodes/DashboardBasicInfoNode.vue';
import DashboardCreateNode from '../editor/nodes/DashboardCreateNode.vue';
import DashboardDesignNode from '../editor/nodes/DashboardDesignNode.vue';
import DashboardPublishNode from '../editor/nodes/DashboardPublishNode.vue';
import DbDeleteNode from '../editor/nodes/DbDeleteNode.vue';
import DbInsertNode from '../editor/nodes/DbInsertNode.vue';
import DbQueryNode from '../editor/nodes/DbQueryNode.vue';
import DbSqlNode from '../editor/nodes/DbSqlNode.vue';
import DbUpdateNode from '../editor/nodes/DbUpdateNode.vue';
import EndNode from '../editor/nodes/EndNode.vue';
import FormBasicInfoNode from '../editor/nodes/FormBasicInfoNode.vue';
import FormCreateNode from '../editor/nodes/FormCreateNode.vue';
import FormDatabaseCreateNode from '../editor/nodes/FormDatabaseCreateNode.vue';
import FormDatabaseDesignNode from '../editor/nodes/FormDatabaseDesignNode.vue';
import FormDataNode from '../editor/nodes/FormDataNode.vue';
import FormListDesignNode from '../editor/nodes/FormListDesignNode.vue';
import FormPublishNode from '../editor/nodes/FormPublishNode.vue';
import FormUIDesignNode from '../editor/nodes/FormUIDesignNode.vue';
import HttpNode from '../editor/nodes/HttpNode.vue';
import IntentNode from '../editor/nodes/IntentNode.vue';
import KnowledgeRetrievalNode from '../editor/nodes/KnowledgeRetrievalNode.vue';
@@ -24,6 +40,7 @@ import SnowflakeCortexAnalystNode from '../editor/nodes/SnowflakeCortexAnalystNo
import SnowflakeCortexLLMNode from '../editor/nodes/SnowflakeCortexLLMNode.vue';
import StartNode from '../editor/nodes/StartNode.vue';
import SubflowNode from '../editor/nodes/SubflowNode.vue';
import SystemSummaryNode from '../editor/nodes/SystemSummaryNode.vue';
import TemplateNode from '../editor/nodes/TemplateNode.vue';
import TextToSqlNode from '../editor/nodes/TextToSqlNode.vue';
@@ -50,7 +67,29 @@ export const workflowNodeTypes = {
snowflake_cortex_llm: markRaw(SnowflakeCortexLLMNode),
snowflake_cortex_analyst: markRaw(SnowflakeCortexAnalystNode),
loop: markRaw(LoopNode),
form_basic_info: markRaw(FormBasicInfoNode),
form_database_design: markRaw(FormDatabaseDesignNode),
form_database_create: markRaw(FormDatabaseCreateNode),
form_ui_design: markRaw(FormUIDesignNode),
form_list_design: markRaw(FormListDesignNode),
form_create: markRaw(FormCreateNode),
form_publish: markRaw(FormPublishNode),
app_create: markRaw(AppCreateNode),
app_design: markRaw(AppDesignNode),
app_settings: markRaw(AppSettingsNode),
app_update: markRaw(AppUpdateNode),
dashboard_basic_info: markRaw(DashboardBasicInfoNode),
dashboard_design: markRaw(DashboardDesignNode),
dashboard_create: markRaw(DashboardCreateNode),
dashboard_publish: markRaw(DashboardPublishNode),
system_summary: markRaw(SystemSummaryNode),
subflow: markRaw(SubflowNode),
form_data_create: markRaw(FormDataNode),
form_data_read: markRaw(FormDataNode),
form_data_update: markRaw(FormDataNode),
form_data_delete: markRaw(FormDataNode),
form_data_list: markRaw(FormDataNode),
form_schema_to_llm: markRaw(FormDataNode),
text_to_sql: markRaw(TextToSqlNode),
knowledge_retrieval: markRaw(KnowledgeRetrievalNode),
};