Procházet zdrojové kódy

feat: 对接发布接口

jiaxing.liao před 1 měsícem
rodič
revize
1f238c0cc1

+ 8 - 61
apps/web/src/features/createModal/index.vue

@@ -16,31 +16,6 @@
 				/>
 				/>
 			</el-form-item>
 			</el-form-item>
 
 
-			<el-form-item :label="t('shared.createWorkflow.fields.tags')" prop="tags">
-				<div class="w-full">
-					<div class="flex gap-2 items-center">
-						<el-input-tag
-							v-model="form.tags"
-							:placeholder="t('shared.createWorkflow.placeholders.tags')"
-							:aria-label="t('shared.createWorkflow.placeholders.tags')"
-							:max="5"
-						/>
-						<span class="tag-tip shrink-0">{{ t('shared.createWorkflow.tagLimit') }}</span>
-					</div>
-				</div>
-			</el-form-item>
-
-			<el-form-item :label="t('shared.createWorkflow.fields.description')" prop="description">
-				<el-input
-					v-model="form.description"
-					type="textarea"
-					:placeholder="t('shared.createWorkflow.placeholders.description')"
-					:rows="3"
-					maxlength="200"
-					show-word-limit
-				/>
-			</el-form-item>
-
 			<el-form-item :label="t('shared.createWorkflow.fields.remark')" prop="remark">
 			<el-form-item :label="t('shared.createWorkflow.fields.remark')" prop="remark">
 				<el-input
 				<el-input
 					v-model="form.remark"
 					v-model="form.remark"
@@ -53,36 +28,10 @@
 			</el-form-item>
 			</el-form-item>
 
 
 			<el-form-item :label="t('shared.createWorkflow.fields.cover')" prop="profilePhoto">
 			<el-form-item :label="t('shared.createWorkflow.fields.cover')" prop="profilePhoto">
-				<el-input v-model="form.profilePhoto" :placeholder="t('shared.createWorkflow.placeholders.cover')" />
-			</el-form-item>
-
-			<!-- <el-form-item label="视图位置" prop="viewPort">
-				<div class="viewport-inputs">
-					<el-input-number
-						v-model="form.viewPort.x"
-						:min="-10000"
-						:max="10000"
-						:step="10"
-						size="small"
-					/>
-					<span class="sep">x</span>
-					<el-input-number
-						v-model="form.viewPort.y"
-						:min="-10000"
-						:max="10000"
-						:step="10"
-						size="small"
-					/>
-					<span class="sep">缩放</span>
-					<el-input-number
-						v-model="form.viewPort.zoom"
-						:min="0.1"
-						:max="5"
-						:step="0.1"
-						size="small"
-					/>
+				<div class="w-full">
+					<FileUpload v-model="coverFile" :fileTypes="['image']" :allowLinkInput="false" />
 				</div>
 				</div>
-			</el-form-item> -->
+			</el-form-item>
 		</el-form>
 		</el-form>
 
 
 		<template #footer>
 		<template #footer>
@@ -102,6 +51,9 @@ import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
 import { agent } from '@repo/api-service'
 import { agent } from '@repo/api-service'
 import { useI18n } from '@/composables/useI18n'
 import { useI18n } from '@/composables/useI18n'
 
 
+import FileUpload from '../fileUpload/FileUploadInput.vue'
+import type { WorkflowUploadFile } from '../fileUpload/shared'
+
 interface ViewPort {
 interface ViewPort {
 	x: number
 	x: number
 	y: number
 	y: number
@@ -110,8 +62,6 @@ interface ViewPort {
 
 
 interface CreateWorkflowForm {
 interface CreateWorkflowForm {
 	name: string
 	name: string
-	tags: string[]
-	description: string
 	remark: string
 	remark: string
 	profilePhoto: string
 	profilePhoto: string
 	viewPort: ViewPort
 	viewPort: ViewPort
@@ -133,11 +83,10 @@ const { t } = useI18n()
 const dialogVisible = ref(false)
 const dialogVisible = ref(false)
 const loading = ref(false)
 const loading = ref(false)
 const formRef = ref<FormInstance>()
 const formRef = ref<FormInstance>()
+const coverFile = ref<WorkflowUploadFile>()
 
 
 const createDefaultForm = (): CreateWorkflowForm => ({
 const createDefaultForm = (): CreateWorkflowForm => ({
 	name: '',
 	name: '',
-	tags: [],
-	description: '',
 	remark: '',
 	remark: '',
 	profilePhoto: '',
 	profilePhoto: '',
 	viewPort: {
 	viewPort: {
@@ -195,10 +144,8 @@ const handleSubmit = async () => {
 
 
 		const payload = {
 		const payload = {
 			name: form.value.name,
 			name: form.value.name,
-			tags: form.value.tags || [],
-			description: form.value.description || '',
 			remark: form.value.remark || '',
 			remark: form.value.remark || '',
-			profilePhoto: form.value.profilePhoto || '',
+			profilePhoto: coverFile.value?.id || '',
 			viewPort: form.value.viewPort
 			viewPort: form.value.viewPort
 		}
 		}
 
 

+ 488 - 74
apps/web/src/i18n/locales/en-us.ts

@@ -205,13 +205,15 @@ export default {
 				{
 				{
 					id: '1',
 					id: '1',
 					title: 'Gmail + GPT-4o-mini',
 					title: 'Gmail + GPT-4o-mini',
-					description: 'Automatically classify and summarize emails with Gmail, GPT-4o-mini, and Notion',
+					description:
+						'Automatically classify and summarize emails with Gmail, GPT-4o-mini, and Notion',
 					icon: '✉️'
 					icon: '✉️'
 				},
 				},
 				{
 				{
 					id: '2',
 					id: '2',
 					title: 'Telegram + OpenAI',
 					title: 'Telegram + OpenAI',
-					description: 'Use Telegram, OpenAI, and Google Drive to classify chats and generate PDF files',
+					description:
+						'Use Telegram, OpenAI, and Google Drive to classify chats and generate PDF files',
 					icon: '💬'
 					icon: '💬'
 				},
 				},
 				{
 				{
@@ -253,8 +255,8 @@ export default {
 				name: 'Enter workflow name',
 				name: 'Enter workflow name',
 				tags: 'Press Enter to add tags',
 				tags: 'Press Enter to add tags',
 				description: 'Optional. Briefly describe what this workflow does',
 				description: 'Optional. Briefly describe what this workflow does',
-				remark: 'Optional. Add extra notes',
-				cover: 'Optional. Cover image URL'
+				remark: 'Add notes',
+				cover: 'Cover image'
 			},
 			},
 			tagLimit: 'Up to 5 tags',
 			tagLimit: 'Up to 5 tags',
 			validation: {
 			validation: {
@@ -315,17 +317,71 @@ export default {
 				success: 'Workflow deleted'
 				success: 'Workflow deleted'
 			},
 			},
 			activities: [
 			activities: [
-				{ id: 1, icon: 'check-circle', type: 'success', text: 'Workflow “Customer Intent Detection” completed successfully', time: '5m ago' },
-				{ id: 2, icon: 'workflow', type: 'info', text: 'Created a new workflow “Daily Report Generator”', time: '1h ago' },
-				{ id: 3, icon: 'play', type: 'info', text: 'Workflow “Contract Review” started running', time: '2h ago' },
-				{ id: 4, icon: 'check-circle', type: 'success', text: 'Workflow “Lead Tagging” completed successfully', time: '3h ago' },
-				{ id: 5, icon: 'users', type: 'info', text: 'User @ZhangSan joined the team', time: 'Yesterday' }
+				{
+					id: 1,
+					icon: 'check-circle',
+					type: 'success',
+					text: 'Workflow “Customer Intent Detection” completed successfully',
+					time: '5m ago'
+				},
+				{
+					id: 2,
+					icon: 'workflow',
+					type: 'info',
+					text: 'Created a new workflow “Daily Report Generator”',
+					time: '1h ago'
+				},
+				{
+					id: 3,
+					icon: 'play',
+					type: 'info',
+					text: 'Workflow “Contract Review” started running',
+					time: '2h ago'
+				},
+				{
+					id: 4,
+					icon: 'check-circle',
+					type: 'success',
+					text: 'Workflow “Lead Tagging” completed successfully',
+					time: '3h ago'
+				},
+				{
+					id: 5,
+					icon: 'users',
+					type: 'info',
+					text: 'User @ZhangSan joined the team',
+					time: 'Yesterday'
+				}
 			],
 			],
 			templates: [
 			templates: [
-				{ id: 1, name: 'Customer Intent Detection', desc: 'Analyze customer message intent automatically', icon: 'service', category: 'Support' },
-				{ id: 2, name: 'Daily Report Generator', desc: 'Compile daily updates automatically', icon: 'efficiency', category: 'Productivity' },
-				{ id: 3, name: 'Contract Review', desc: 'Review key contract clauses with AI', icon: 'legal', category: 'Legal' },
-				{ id: 4, name: 'Lead Tagging', desc: 'Tag sales leads automatically', icon: 'growth', category: 'Marketing' }
+				{
+					id: 1,
+					name: 'Customer Intent Detection',
+					desc: 'Analyze customer message intent automatically',
+					icon: 'service',
+					category: 'Support'
+				},
+				{
+					id: 2,
+					name: 'Daily Report Generator',
+					desc: 'Compile daily updates automatically',
+					icon: 'efficiency',
+					category: 'Productivity'
+				},
+				{
+					id: 3,
+					name: 'Contract Review',
+					desc: 'Review key contract clauses with AI',
+					icon: 'legal',
+					category: 'Legal'
+				},
+				{
+					id: 4,
+					name: 'Lead Tagging',
+					desc: 'Tag sales leads automatically',
+					icon: 'growth',
+					category: 'Marketing'
+				}
 			]
 			]
 		},
 		},
 		orchestration: {
 		orchestration: {
@@ -365,21 +421,71 @@ export default {
 			open: 'Open',
 			open: 'Open',
 			viewTemplate: 'View Template',
 			viewTemplate: 'View Template',
 			recentWorkflows: [
 			recentWorkflows: [
-				{ id: '1', name: 'Customer Support Auto Routing', updatedAt: 'Today 10:12', owner: 'Zhang Wei', tag: 'Support' },
-				{ id: '2', name: 'Content Creation and Review', updatedAt: 'Yesterday 18:20', owner: 'Li Na', tag: 'Content' },
-				{ id: '3', name: 'RAG Knowledge Sync', updatedAt: 'Jan 27', owner: 'Wang Qiang', tag: 'Knowledge Base' },
-				{ id: '4', name: 'Financial Report Summary', updatedAt: 'Jan 26', owner: 'Zhao Min', tag: 'Finance' }
+				{
+					id: '1',
+					name: 'Customer Support Auto Routing',
+					updatedAt: 'Today 10:12',
+					owner: 'Zhang Wei',
+					tag: 'Support'
+				},
+				{
+					id: '2',
+					name: 'Content Creation and Review',
+					updatedAt: 'Yesterday 18:20',
+					owner: 'Li Na',
+					tag: 'Content'
+				},
+				{
+					id: '3',
+					name: 'RAG Knowledge Sync',
+					updatedAt: 'Jan 27',
+					owner: 'Wang Qiang',
+					tag: 'Knowledge Base'
+				},
+				{
+					id: '4',
+					name: 'Financial Report Summary',
+					updatedAt: 'Jan 26',
+					owner: 'Zhao Min',
+					tag: 'Finance'
+				}
 			],
 			],
 			nodeGroups: [
 			nodeGroups: [
-				{ label: 'Flow Control', tags: ['Start Node', 'Conditional Branch', 'Loop Node', 'End Node'] },
-				{ label: 'Data Operations', tags: ['HTTP Request', 'Database Query', 'Code Execution', 'Data Transformation'] },
+				{
+					label: 'Flow Control',
+					tags: ['Start Node', 'Conditional Branch', 'Loop Node', 'End Node']
+				},
+				{
+					label: 'Data Operations',
+					tags: ['HTTP Request', 'Database Query', 'Code Execution', 'Data Transformation']
+				},
 				{ label: 'Trigger Rules', tags: ['Scheduled Trigger', 'Webhook', 'Event Listener'] }
 				{ label: 'Trigger Rules', tags: ['Scheduled Trigger', 'Webhook', 'Event Listener'] }
 			],
 			],
 			templates: [
 			templates: [
-				{ id: 't1', name: 'Customer Intent Detection', desc: 'Receive message → AI intent analysis → condition check → route to support or bot', category: 'Support' },
-				{ id: 't2', name: 'Daily Summary Automation', desc: 'Scheduled trigger → query data tables → aggregate → generate report → notify team', category: 'Operations' },
-				{ id: 't3', name: 'Contract Review Assistant', desc: 'Upload contract → OCR → AI review → risk classification → report generation', category: 'Legal' },
-				{ id: 't4', name: 'Lead Tagging', desc: 'Webhook input → clean data → rule matching → tag leads → write to CRM', category: 'Growth' }
+				{
+					id: 't1',
+					name: 'Customer Intent Detection',
+					desc: 'Receive message → AI intent analysis → condition check → route to support or bot',
+					category: 'Support'
+				},
+				{
+					id: 't2',
+					name: 'Daily Summary Automation',
+					desc: 'Scheduled trigger → query data tables → aggregate → generate report → notify team',
+					category: 'Operations'
+				},
+				{
+					id: 't3',
+					name: 'Contract Review Assistant',
+					desc: 'Upload contract → OCR → AI review → risk classification → report generation',
+					category: 'Legal'
+				},
+				{
+					id: 't4',
+					name: 'Lead Tagging',
+					desc: 'Webhook input → clean data → rule matching → tag leads → write to CRM',
+					category: 'Growth'
+				}
 			]
 			]
 		},
 		},
 		execution: {
 		execution: {
@@ -420,10 +526,38 @@ export default {
 				{ label: 'P95 Duration', value: '5.9s' }
 				{ label: 'P95 Duration', value: '5.9s' }
 			],
 			],
 			executions: [
 			executions: [
-				{ workflow: 'Customer Support Auto Routing', executionId: 'EXE-20260129001', startedAt: '2026-01-29 09:12:03', duration: '2.1s', trigger: 'Schedule', status: 'success' },
-				{ workflow: 'Content Creation and Review', executionId: 'EXE-20260129002', startedAt: '2026-01-29 09:15:45', duration: '4.3s', trigger: 'Manual', status: 'running' },
-				{ workflow: 'RAG Knowledge Sync', executionId: 'EXE-20260129003', startedAt: '2026-01-29 08:58:12', duration: '3.9s', trigger: 'Webhook', status: 'failed' },
-				{ workflow: 'Financial Report Summary', executionId: 'EXE-20260129004', startedAt: '2026-01-29 08:40:30', duration: '1.6s', trigger: 'Schedule', status: 'success' }
+				{
+					workflow: 'Customer Support Auto Routing',
+					executionId: 'EXE-20260129001',
+					startedAt: '2026-01-29 09:12:03',
+					duration: '2.1s',
+					trigger: 'Schedule',
+					status: 'success'
+				},
+				{
+					workflow: 'Content Creation and Review',
+					executionId: 'EXE-20260129002',
+					startedAt: '2026-01-29 09:15:45',
+					duration: '4.3s',
+					trigger: 'Manual',
+					status: 'running'
+				},
+				{
+					workflow: 'RAG Knowledge Sync',
+					executionId: 'EXE-20260129003',
+					startedAt: '2026-01-29 08:58:12',
+					duration: '3.9s',
+					trigger: 'Webhook',
+					status: 'failed'
+				},
+				{
+					workflow: 'Financial Report Summary',
+					executionId: 'EXE-20260129004',
+					startedAt: '2026-01-29 08:40:30',
+					duration: '1.6s',
+					trigger: 'Schedule',
+					status: 'success'
+				}
 			]
 			]
 		},
 		},
 		management: {
 		management: {
@@ -461,10 +595,26 @@ export default {
 			description:
 			description:
 				'AI Agent is a powerful and flexible automation workflow platform that helps teams and individuals build intelligent business processes. We aim to make automation simple, efficient, and easy to maintain.',
 				'AI Agent is a powerful and flexible automation workflow platform that helps teams and individuals build intelligent business processes. We aim to make automation simple, efficient, and easy to maintain.',
 			features: [
 			features: [
-				{ icon: 'zap', title: 'High Performance', desc: 'An optimized execution engine for fast and reliable workflows' },
-				{ icon: 'shield', title: 'Secure and Reliable', desc: 'Enterprise-grade security to protect your data and credentials' },
-				{ icon: 'users', title: 'Team Collaboration', desc: 'Work together to build and maintain workflows' },
-				{ icon: 'code', title: 'Open and Extensible', desc: 'Custom nodes and integrations for personalized needs' }
+				{
+					icon: 'zap',
+					title: 'High Performance',
+					desc: 'An optimized execution engine for fast and reliable workflows'
+				},
+				{
+					icon: 'shield',
+					title: 'Secure and Reliable',
+					desc: 'Enterprise-grade security to protect your data and credentials'
+				},
+				{
+					icon: 'users',
+					title: 'Team Collaboration',
+					desc: 'Work together to build and maintain workflows'
+				},
+				{
+					icon: 'code',
+					title: 'Open and Extensible',
+					desc: 'Custom nodes and integrations for personalized needs'
+				}
 			]
 			]
 		},
 		},
 		userCenter: {
 		userCenter: {
@@ -491,7 +641,11 @@ export default {
 			},
 			},
 			security: {
 			security: {
 				title: 'Account Security',
 				title: 'Account Security',
-				password: { title: 'Login Password', desc: 'Rotate your password regularly to improve account security', action: 'Change' },
+				password: {
+					title: 'Login Password',
+					desc: 'Rotate your password regularly to improve account security',
+					action: 'Change'
+				},
 				twoFactor: { title: 'Two-Factor Authentication', desc: 'Disabled', action: 'Enable' },
 				twoFactor: { title: 'Two-Factor Authentication', desc: 'Disabled', action: 'Enable' },
 				boundPhone: { title: 'Bound Phone', action: 'Replace' }
 				boundPhone: { title: 'Bound Phone', action: 'Replace' }
 			}
 			}
@@ -501,11 +655,46 @@ export default {
 			searchPlaceholder: 'Search logs...',
 			searchPlaceholder: 'Search logs...',
 			levelPlaceholder: 'Log Level',
 			levelPlaceholder: 'Log Level',
 			logs: [
 			logs: [
-				{ id: 1, level: 'info', timestamp: '2026-01-28 14:23:45', workflowName: 'Data Sync Workflow', message: 'Workflow completed successfully', details: { executionTime: '2.5s', nodesExecuted: 5 } },
-				{ id: 2, level: 'warning', timestamp: '2026-01-28 14:20:12', workflowName: 'API Request Workflow', message: 'Response time exceeded threshold', details: { responseTime: '3200ms', threshold: '3000ms' } },
-				{ id: 3, level: 'error', timestamp: '2026-01-28 14:15:33', workflowName: 'Email Delivery Workflow', message: 'Email delivery failed: SMTP connection timeout', details: { error: 'Connection timeout', host: 'xxxxx.com' } },
-				{ id: 4, level: 'info', timestamp: '2026-01-28 14:10:08', workflowName: 'Data Processing Workflow', message: 'Processed 1000 records', details: { processed: 1000, failed: 0 } },
-				{ id: 5, level: 'info', timestamp: '2026-01-28 14:05:22', workflowName: 'Scheduled Workflow', message: 'Scheduled task triggered', details: { schedule: '*/5 * * * *', triggeredBy: 'cron' } }
+				{
+					id: 1,
+					level: 'info',
+					timestamp: '2026-01-28 14:23:45',
+					workflowName: 'Data Sync Workflow',
+					message: 'Workflow completed successfully',
+					details: { executionTime: '2.5s', nodesExecuted: 5 }
+				},
+				{
+					id: 2,
+					level: 'warning',
+					timestamp: '2026-01-28 14:20:12',
+					workflowName: 'API Request Workflow',
+					message: 'Response time exceeded threshold',
+					details: { responseTime: '3200ms', threshold: '3000ms' }
+				},
+				{
+					id: 3,
+					level: 'error',
+					timestamp: '2026-01-28 14:15:33',
+					workflowName: 'Email Delivery Workflow',
+					message: 'Email delivery failed: SMTP connection timeout',
+					details: { error: 'Connection timeout', host: 'xxxxx.com' }
+				},
+				{
+					id: 4,
+					level: 'info',
+					timestamp: '2026-01-28 14:10:08',
+					workflowName: 'Data Processing Workflow',
+					message: 'Processed 1000 records',
+					details: { processed: 1000, failed: 0 }
+				},
+				{
+					id: 5,
+					level: 'info',
+					timestamp: '2026-01-28 14:05:22',
+					workflowName: 'Scheduled Workflow',
+					message: 'Scheduled task triggered',
+					details: { schedule: '*/5 * * * *', triggeredBy: 'cron' }
+				}
 			]
 			]
 		},
 		},
 		modelLog: {
 		modelLog: {
@@ -542,10 +731,62 @@ export default {
 				cost: 'Cost'
 				cost: 'Cost'
 			},
 			},
 			logs: [
 			logs: [
-				{ id: 1, timestamp: '2026-01-28 14:25:33', model: 'GPT-4', workflowName: 'AI Article Generation', status: 'success', tokens: '1,250', cost: '$0.025', responseTime: '1.8s', inputTokens: 450, outputTokens: 800, prompt: 'Help me write an article about the development of AI...', response: 'The history of artificial intelligence can be traced back to...' },
-				{ id: 2, timestamp: '2026-01-28 14:23:15', model: 'Claude-3', workflowName: 'Smart Customer Service', status: 'success', tokens: '680', cost: '$0.014', responseTime: '0.9s', inputTokens: 280, outputTokens: 400, prompt: 'User asks: how do I return a product?', response: 'Hello, here is the return process...' },
-				{ id: 3, timestamp: '2026-01-28 14:20:42', model: 'GPT-4', workflowName: 'Code Review Assistant', status: 'success', tokens: '2,100', cost: '$0.042', responseTime: '2.3s', inputTokens: 1200, outputTokens: 900, prompt: 'Please review the following code...', response: 'Code review result: overall structure looks solid...' },
-				{ id: 4, timestamp: '2026-01-28 14:18:05', model: 'GPT-3.5', workflowName: 'Data Analysis', status: 'failed', tokens: '0', cost: '$0.000', responseTime: '5.0s', inputTokens: 0, outputTokens: 0, prompt: 'Analyze sales data...', response: 'Error: API rate limit exceeded' }
+				{
+					id: 1,
+					timestamp: '2026-01-28 14:25:33',
+					model: 'GPT-4',
+					workflowName: 'AI Article Generation',
+					status: 'success',
+					tokens: '1,250',
+					cost: '$0.025',
+					responseTime: '1.8s',
+					inputTokens: 450,
+					outputTokens: 800,
+					prompt: 'Help me write an article about the development of AI...',
+					response: 'The history of artificial intelligence can be traced back to...'
+				},
+				{
+					id: 2,
+					timestamp: '2026-01-28 14:23:15',
+					model: 'Claude-3',
+					workflowName: 'Smart Customer Service',
+					status: 'success',
+					tokens: '680',
+					cost: '$0.014',
+					responseTime: '0.9s',
+					inputTokens: 280,
+					outputTokens: 400,
+					prompt: 'User asks: how do I return a product?',
+					response: 'Hello, here is the return process...'
+				},
+				{
+					id: 3,
+					timestamp: '2026-01-28 14:20:42',
+					model: 'GPT-4',
+					workflowName: 'Code Review Assistant',
+					status: 'success',
+					tokens: '2,100',
+					cost: '$0.042',
+					responseTime: '2.3s',
+					inputTokens: 1200,
+					outputTokens: 900,
+					prompt: 'Please review the following code...',
+					response: 'Code review result: overall structure looks solid...'
+				},
+				{
+					id: 4,
+					timestamp: '2026-01-28 14:18:05',
+					model: 'GPT-3.5',
+					workflowName: 'Data Analysis',
+					status: 'failed',
+					tokens: '0',
+					cost: '$0.000',
+					responseTime: '5.0s',
+					inputTokens: 0,
+					outputTokens: 0,
+					prompt: 'Analyze sales data...',
+					response: 'Error: API rate limit exceeded'
+				}
 			]
 			]
 		},
 		},
 		statisticsPage: {
 		statisticsPage: {
@@ -571,43 +812,147 @@ export default {
 					chartTitle: 'Production Runs Over Time',
 					chartTitle: 'Production Runs Over Time',
 					tableTitle: 'Production Run Details',
 					tableTitle: 'Production Run Details',
 					tableData: [
 					tableData: [
-						{ name: 'Project 1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: 'Data Processing Project' },
-						{ name: 'Project 2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI Analytics Project' },
-						{ name: 'Project 3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: 'Image Recognition Project' }
+						{
+							name: 'Project 1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: 'Data Processing Project'
+						},
+						{
+							name: 'Project 2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI Analytics Project'
+						},
+						{
+							name: 'Project 3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: 'Image Recognition Project'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: 'Failed Production Runs Over Time',
 					chartTitle: 'Failed Production Runs Over Time',
 					tableTitle: 'Failed Run Details',
 					tableTitle: 'Failed Run Details',
 					tableData: [
 					tableData: [
-						{ name: 'Project 1', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '2.1s', projectName: 'Data Processing Project' },
-						{ name: 'Project 2', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '1.8s', projectName: 'AI Analytics Project' },
-						{ name: 'Project 3', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '3.3s', projectName: 'Image Recognition Project' }
+						{
+							name: 'Project 1',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '2.1s',
+							projectName: 'Data Processing Project'
+						},
+						{
+							name: 'Project 2',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '1.8s',
+							projectName: 'AI Analytics Project'
+						},
+						{
+							name: 'Project 3',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '3.3s',
+							projectName: 'Image Recognition Project'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: 'Failure Rate Over Time',
 					chartTitle: 'Failure Rate Over Time',
 					tableTitle: 'Failure Rate Details',
 					tableTitle: 'Failure Rate Details',
 					tableData: [
 					tableData: [
-						{ name: 'Project 1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: 'Data Processing Project' },
-						{ name: 'Project 2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI Analytics Project' }
+						{
+							name: 'Project 1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: 'Data Processing Project'
+						},
+						{
+							name: 'Project 2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI Analytics Project'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: 'Time Saved Over Time',
 					chartTitle: 'Time Saved Over Time',
 					tableTitle: 'Time Saved Details',
 					tableTitle: 'Time Saved Details',
 					tableData: [
 					tableData: [
-						{ name: 'Project 1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: 'Data Processing Project' },
-						{ name: 'Project 3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: 'Image Recognition Project' }
+						{
+							name: 'Project 1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: 'Data Processing Project'
+						},
+						{
+							name: 'Project 3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: 'Image Recognition Project'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: 'Average Runtime Over Time',
 					chartTitle: 'Average Runtime Over Time',
 					tableTitle: 'Runtime Details',
 					tableTitle: 'Runtime Details',
 					tableData: [
 					tableData: [
-						{ name: 'Project 2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI Analytics Project' },
-						{ name: 'Project 3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: 'Image Recognition Project' },
-						{ name: 'Project 1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: 'Data Processing Project' }
+						{
+							name: 'Project 2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI Analytics Project'
+						},
+						{
+							name: 'Project 3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: 'Image Recognition Project'
+						},
+						{
+							name: 'Project 1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: 'Data Processing Project'
+						}
 					]
 					]
 				}
 				}
 			]
 			]
@@ -626,10 +971,22 @@ export default {
 			stepsTitle: 'Getting Started',
 			stepsTitle: 'Getting Started',
 			resourcesTitle: 'More Resources',
 			resourcesTitle: 'More Resources',
 			steps: [
 			steps: [
-				{ title: 'Create a Workflow', desc: 'Click the “+” button in the sidebar and choose “Workflow” to create your first flow' },
-				{ title: 'Add Nodes', desc: 'Use start, end, HTTP request, conditional branch, code execution, data query, and more to assemble your business logic' },
-				{ title: 'Configure and Test', desc: 'Set node parameters and run tests to confirm everything works as expected' },
-				{ title: 'Deploy', desc: 'Save and activate your workflow so it can work for you automatically' }
+				{
+					title: 'Create a Workflow',
+					desc: 'Click the “+” button in the sidebar and choose “Workflow” to create your first flow'
+				},
+				{
+					title: 'Add Nodes',
+					desc: 'Use start, end, HTTP request, conditional branch, code execution, data query, and more to assemble your business logic'
+				},
+				{
+					title: 'Configure and Test',
+					desc: 'Set node parameters and run tests to confirm everything works as expected'
+				},
+				{
+					title: 'Deploy',
+					desc: 'Save and activate your workflow so it can work for you automatically'
+				}
 			],
 			],
 			resources: [
 			resources: [
 				{ icon: 'book', title: 'Read Docs', desc: 'Explore every product capability in depth' },
 				{ icon: 'book', title: 'Read Docs', desc: 'Explore every product capability in depth' },
@@ -640,19 +997,57 @@ export default {
 		docs: {
 		docs: {
 			sidebarTitle: 'Documentation',
 			sidebarTitle: 'Documentation',
 			navSections: [
 			navSections: [
-				{ title: 'Quick Start', items: [{ key: 'intro', label: 'Introduction' }, { key: 'installation', label: 'Installation' }] },
-				{ title: 'Core Concepts', items: [{ key: 'workflow', label: 'Workflow' }, { key: 'nodes', label: 'Nodes' }, { key: 'credentials', label: 'Credentials' }] },
-				{ title: 'Node Docs', items: [{ key: 'http', label: 'HTTP Node' }, { key: 'code', label: 'Code Node' }, { key: 'database', label: 'Database Node' }] }
+				{
+					title: 'Quick Start',
+					items: [
+						{ key: 'intro', label: 'Introduction' },
+						{ key: 'installation', label: 'Installation' }
+					]
+				},
+				{
+					title: 'Core Concepts',
+					items: [
+						{ key: 'workflow', label: 'Workflow' },
+						{ key: 'nodes', label: 'Nodes' },
+						{ key: 'credentials', label: 'Credentials' }
+					]
+				},
+				{
+					title: 'Node Docs',
+					items: [
+						{ key: 'http', label: 'HTTP Node' },
+						{ key: 'code', label: 'Code Node' },
+						{ key: 'database', label: 'Database Node' }
+					]
+				}
 			],
 			],
 			docMap: {
 			docMap: {
-				intro: { title: 'About AI Agent', description: 'Learn the core concepts and basic usage of AI Agent' },
-				installation: { title: 'Installation and Deployment', description: 'Install and configure AI Agent in your environment' },
-				workflow: { title: 'Workflow Concepts', description: 'Understand design patterns and best practices for workflows' },
-				nodes: { title: 'Node System', description: 'Understand how the node system works and how to use it' },
-				credentials: { title: 'Credential Management', description: 'Manage and use third-party credentials securely' },
+				intro: {
+					title: 'About AI Agent',
+					description: 'Learn the core concepts and basic usage of AI Agent'
+				},
+				installation: {
+					title: 'Installation and Deployment',
+					description: 'Install and configure AI Agent in your environment'
+				},
+				workflow: {
+					title: 'Workflow Concepts',
+					description: 'Understand design patterns and best practices for workflows'
+				},
+				nodes: {
+					title: 'Node System',
+					description: 'Understand how the node system works and how to use it'
+				},
+				credentials: {
+					title: 'Credential Management',
+					description: 'Manage and use third-party credentials securely'
+				},
 				http: { title: 'HTTP Node', description: 'Use the HTTP node to work with REST APIs' },
 				http: { title: 'HTTP Node', description: 'Use the HTTP node to work with REST APIs' },
 				code: { title: 'Code Node', description: 'Write custom code for advanced business logic' },
 				code: { title: 'Code Node', description: 'Write custom code for advanced business logic' },
-				database: { title: 'Database Node', description: 'Connect to and operate on database systems' }
+				database: {
+					title: 'Database Node',
+					description: 'Connect to and operate on database systems'
+				}
 			},
 			},
 			sections: {
 			sections: {
 				overview: 'Overview',
 				overview: 'Overview',
@@ -697,6 +1092,10 @@ export default {
 			tagPlaceholder: 'Press Enter to add tags',
 			tagPlaceholder: 'Press Enter to add tags',
 			tagButton: 'Tags',
 			tagButton: 'Tags',
 			publish: 'Publish',
 			publish: 'Publish',
+			status: {
+				published: 'Published',
+				unpublished: 'Unpublished'
+			},
 			menu: {
 			menu: {
 				description: 'Description',
 				description: 'Description',
 				reuse: 'Reuse',
 				reuse: 'Reuse',
@@ -707,8 +1106,10 @@ export default {
 				loadFailed: 'Failed to load agent workflow',
 				loadFailed: 'Failed to load agent workflow',
 				saveFailed: 'Failed to save agent',
 				saveFailed: 'Failed to save agent',
 				saved: 'Agent saved',
 				saved: 'Agent saved',
-				varsSaved: 'Variables saved'
-			}
+				varsSaved: 'Variables saved',
+				publishSuccess: 'Agent published'
+			},
+			selectPublishNode: 'Please select a node to publish'
 		},
 		},
 		nodeView: {
 		nodeView: {
 			messages: {
 			messages: {
@@ -716,7 +1117,8 @@ export default {
 				runFailed: 'Failed to run node',
 				runFailed: 'Failed to run node',
 				missingTrigger: 'No runnable trigger node was found',
 				missingTrigger: 'No runnable trigger node was found',
 				loopEndOnlyInside: 'The loop-exit node can only be added inside loop or iteration nodes',
 				loopEndOnlyInside: 'The loop-exit node can only be added inside loop or iteration nodes',
-				noNestedLoop: 'Loop and iteration nodes cannot be nested inside another loop or iteration node',
+				noNestedLoop:
+					'Loop and iteration nodes cannot be nested inside another loop or iteration node',
 				nodeAdded: 'Node added',
 				nodeAdded: 'Node added',
 				addNodeFailed: 'Failed to add node',
 				addNodeFailed: 'Failed to add node',
 				edgeCreated: 'Connection created',
 				edgeCreated: 'Connection created',
@@ -1089,10 +1491,19 @@ export default {
 			other: 'Other'
 			other: 'Other'
 		},
 		},
 		meta: {
 		meta: {
-			start: { displayName: 'User Input', description: 'Collect user input when the workflow starts' },
+			start: {
+				displayName: 'User Input',
+				description: 'Collect user input when the workflow starts'
+			},
 			end: { displayName: 'Output', description: 'Finish the workflow and output the result' },
 			end: { displayName: 'Output', description: 'Finish the workflow and output the result' },
-			'http-request': { displayName: 'HTTP Request', description: 'Fetch data through an HTTP request' },
-			'if-else': { displayName: 'Condition', description: 'Route to different branches based on conditions' },
+			'http-request': {
+				displayName: 'HTTP Request',
+				description: 'Fetch data through an HTTP request'
+			},
+			'if-else': {
+				displayName: 'Condition',
+				description: 'Route to different branches based on conditions'
+			},
 			database: { displayName: 'Database Query', description: 'Query data through a database' },
 			database: { displayName: 'Database Query', description: 'Query data through a database' },
 			code: { displayName: 'Code', description: 'Process data with code' },
 			code: { displayName: 'Code', description: 'Process data with code' },
 			iteration: { displayName: 'Iteration', description: 'Iteration node' },
 			iteration: { displayName: 'Iteration', description: 'Iteration node' },
@@ -1103,7 +1514,10 @@ export default {
 				description: 'Classify questions into predefined categories'
 				description: 'Classify questions into predefined categories'
 			},
 			},
 			'loop-end': { displayName: 'Exit Loop', description: 'Exit the current iteration or loop' },
 			'loop-end': { displayName: 'Exit Loop', description: 'Exit the current iteration or loop' },
-			'trigger-schedule': { displayName: 'Schedule Trigger', description: 'Trigger the workflow on a schedule' },
+			'trigger-schedule': {
+				displayName: 'Schedule Trigger',
+				description: 'Trigger the workflow on a schedule'
+			},
 			'trigger-webhook': {
 			'trigger-webhook': {
 				displayName: 'Webhook Trigger',
 				displayName: 'Webhook Trigger',
 				description: 'Receive third-party webhook requests and trigger the workflow'
 				description: 'Receive third-party webhook requests and trigger the workflow'

+ 354 - 44
apps/web/src/i18n/locales/zh-cn.ts

@@ -363,17 +363,53 @@ export default {
 				success: '删除成功'
 				success: '删除成功'
 			},
 			},
 			activities: [
 			activities: [
-				{ id: 1, icon: 'check-circle', type: 'success', text: '工作流“客户意图识别”执行成功', time: '5分钟前' },
-				{ id: 2, icon: 'workflow', type: 'info', text: '创建了新工作流“日报生成器”', time: '1小时前' },
+				{
+					id: 1,
+					icon: 'check-circle',
+					type: 'success',
+					text: '工作流“客户意图识别”执行成功',
+					time: '5分钟前'
+				},
+				{
+					id: 2,
+					icon: 'workflow',
+					type: 'info',
+					text: '创建了新工作流“日报生成器”',
+					time: '1小时前'
+				},
 				{ id: 3, icon: 'play', type: 'info', text: '工作流“合同审查”开始执行', time: '2小时前' },
 				{ id: 3, icon: 'play', type: 'info', text: '工作流“合同审查”开始执行', time: '2小时前' },
-				{ id: 4, icon: 'check-circle', type: 'success', text: '工作流“线索标签化”执行成功', time: '3小时前' },
+				{
+					id: 4,
+					icon: 'check-circle',
+					type: 'success',
+					text: '工作流“线索标签化”执行成功',
+					time: '3小时前'
+				},
 				{ id: 5, icon: 'users', type: 'info', text: '用户 @张三 加入了团队', time: '昨天' }
 				{ id: 5, icon: 'users', type: 'info', text: '用户 @张三 加入了团队', time: '昨天' }
 			],
 			],
 			templates: [
 			templates: [
-				{ id: 1, name: '客户意图识别', desc: '自动分析客户消息意图', icon: 'service', category: '客服' },
-				{ id: 2, name: '日报生成器', desc: '每日自动汇总工作报告', icon: 'efficiency', category: '效率' },
+				{
+					id: 1,
+					name: '客户意图识别',
+					desc: '自动分析客户消息意图',
+					icon: 'service',
+					category: '客服'
+				},
+				{
+					id: 2,
+					name: '日报生成器',
+					desc: '每日自动汇总工作报告',
+					icon: 'efficiency',
+					category: '效率'
+				},
 				{ id: 3, name: '合同审查', desc: '智能审查合同关键条款', icon: 'legal', category: '法务' },
 				{ id: 3, name: '合同审查', desc: '智能审查合同关键条款', icon: 'legal', category: '法务' },
-				{ id: 4, name: '线索标签化', desc: '自动为销售线索打标签', icon: 'growth', category: '营销' }
+				{
+					id: 4,
+					name: '线索标签化',
+					desc: '自动为销售线索打标签',
+					icon: 'growth',
+					category: '营销'
+				}
 			]
 			]
 		},
 		},
 		orchestration: {
 		orchestration: {
@@ -424,10 +460,30 @@ export default {
 				{ label: '触发规则', tags: ['定时触发', 'Webhook', '事件监听'] }
 				{ label: '触发规则', tags: ['定时触发', 'Webhook', '事件监听'] }
 			],
 			],
 			templates: [
 			templates: [
-				{ id: 't1', name: '客户意图识别', desc: '接收消息 → AI 分析意图 → 条件判断 → 自动分派客服/机器人', category: '客服' },
-				{ id: 't2', name: '日报自动汇总', desc: '定时触发 → 查询数据表 → 汇总计算 → 生成报告 → 通知团队', category: '运营' },
-				{ id: 't3', name: '合同审查助手', desc: '上传合同 → OCR 识别 → AI 审查 → 风险分类 → 生成报告', category: '法务' },
-				{ id: 't4', name: '线索打标', desc: 'Webhook 接收 → 数据清洗 → 规则匹配 → 打标签 → 写入 CRM', category: '增长' }
+				{
+					id: 't1',
+					name: '客户意图识别',
+					desc: '接收消息 → AI 分析意图 → 条件判断 → 自动分派客服/机器人',
+					category: '客服'
+				},
+				{
+					id: 't2',
+					name: '日报自动汇总',
+					desc: '定时触发 → 查询数据表 → 汇总计算 → 生成报告 → 通知团队',
+					category: '运营'
+				},
+				{
+					id: 't3',
+					name: '合同审查助手',
+					desc: '上传合同 → OCR 识别 → AI 审查 → 风险分类 → 生成报告',
+					category: '法务'
+				},
+				{
+					id: 't4',
+					name: '线索打标',
+					desc: 'Webhook 接收 → 数据清洗 → 规则匹配 → 打标签 → 写入 CRM',
+					category: '增长'
+				}
 			]
 			]
 		},
 		},
 		execution: {
 		execution: {
@@ -468,10 +524,38 @@ export default {
 				{ label: 'P95 耗时', value: '5.9s' }
 				{ label: 'P95 耗时', value: '5.9s' }
 			],
 			],
 			executions: [
 			executions: [
-				{ workflow: '客户支持自动分派', executionId: 'EXE-20260129001', startedAt: '2026-01-29 09:12:03', duration: '2.1s', trigger: '定时', status: 'success' },
-				{ workflow: '内容生成与审核', executionId: 'EXE-20260129002', startedAt: '2026-01-29 09:15:45', duration: '4.3s', trigger: '手动', status: 'running' },
-				{ workflow: 'RAG 知识库同步', executionId: 'EXE-20260129003', startedAt: '2026-01-29 08:58:12', duration: '3.9s', trigger: 'Webhook', status: 'failed' },
-				{ workflow: '财务报表汇总', executionId: 'EXE-20260129004', startedAt: '2026-01-29 08:40:30', duration: '1.6s', trigger: '定时', status: 'success' }
+				{
+					workflow: '客户支持自动分派',
+					executionId: 'EXE-20260129001',
+					startedAt: '2026-01-29 09:12:03',
+					duration: '2.1s',
+					trigger: '定时',
+					status: 'success'
+				},
+				{
+					workflow: '内容生成与审核',
+					executionId: 'EXE-20260129002',
+					startedAt: '2026-01-29 09:15:45',
+					duration: '4.3s',
+					trigger: '手动',
+					status: 'running'
+				},
+				{
+					workflow: 'RAG 知识库同步',
+					executionId: 'EXE-20260129003',
+					startedAt: '2026-01-29 08:58:12',
+					duration: '3.9s',
+					trigger: 'Webhook',
+					status: 'failed'
+				},
+				{
+					workflow: '财务报表汇总',
+					executionId: 'EXE-20260129004',
+					startedAt: '2026-01-29 08:40:30',
+					duration: '1.6s',
+					trigger: '定时',
+					status: 'success'
+				}
 			]
 			]
 		},
 		},
 		management: {
 		management: {
@@ -549,11 +633,46 @@ export default {
 			searchPlaceholder: '搜索日志...',
 			searchPlaceholder: '搜索日志...',
 			levelPlaceholder: '日志级别',
 			levelPlaceholder: '日志级别',
 			logs: [
 			logs: [
-				{ id: 1, level: 'info', timestamp: '2026-01-28 14:23:45', workflowName: '数据同步工作流', message: '工作流执行成功', details: { executionTime: '2.5s', nodesExecuted: 5 } },
-				{ id: 2, level: 'warning', timestamp: '2026-01-28 14:20:12', workflowName: 'API 调用工作流', message: '请求响应时间超过阈值', details: { responseTime: '3200ms', threshold: '3000ms' } },
-				{ id: 3, level: 'error', timestamp: '2026-01-28 14:15:33', workflowName: '邮件发送工作流', message: '邮件发送失败:SMTP 连接超时', details: { error: 'Connection timeout', host: 'xxxxx.com' } },
-				{ id: 4, level: 'info', timestamp: '2026-01-28 14:10:08', workflowName: '数据处理工作流', message: '处理了 1000 条数据记录', details: { processed: 1000, failed: 0 } },
-				{ id: 5, level: 'info', timestamp: '2026-01-28 14:05:22', workflowName: '定时任务工作流', message: '定时任务触发执行', details: { schedule: '*/5 * * * *', triggeredBy: 'cron' } }
+				{
+					id: 1,
+					level: 'info',
+					timestamp: '2026-01-28 14:23:45',
+					workflowName: '数据同步工作流',
+					message: '工作流执行成功',
+					details: { executionTime: '2.5s', nodesExecuted: 5 }
+				},
+				{
+					id: 2,
+					level: 'warning',
+					timestamp: '2026-01-28 14:20:12',
+					workflowName: 'API 调用工作流',
+					message: '请求响应时间超过阈值',
+					details: { responseTime: '3200ms', threshold: '3000ms' }
+				},
+				{
+					id: 3,
+					level: 'error',
+					timestamp: '2026-01-28 14:15:33',
+					workflowName: '邮件发送工作流',
+					message: '邮件发送失败:SMTP 连接超时',
+					details: { error: 'Connection timeout', host: 'xxxxx.com' }
+				},
+				{
+					id: 4,
+					level: 'info',
+					timestamp: '2026-01-28 14:10:08',
+					workflowName: '数据处理工作流',
+					message: '处理了 1000 条数据记录',
+					details: { processed: 1000, failed: 0 }
+				},
+				{
+					id: 5,
+					level: 'info',
+					timestamp: '2026-01-28 14:05:22',
+					workflowName: '定时任务工作流',
+					message: '定时任务触发执行',
+					details: { schedule: '*/5 * * * *', triggeredBy: 'cron' }
+				}
 			]
 			]
 		},
 		},
 		modelLog: {
 		modelLog: {
@@ -590,10 +709,62 @@ export default {
 				cost: '费用'
 				cost: '费用'
 			},
 			},
 			logs: [
 			logs: [
-				{ id: 1, timestamp: '2026-01-28 14:25:33', model: 'GPT-4', workflowName: 'AI 文章生成', status: 'success', tokens: '1,250', cost: '$0.025', responseTime: '1.8s', inputTokens: 450, outputTokens: 800, prompt: '请帮我生成一篇关于人工智能发展的文章...', response: '人工智能的发展历程可以追溯到...' },
-				{ id: 2, timestamp: '2026-01-28 14:23:15', model: 'Claude-3', workflowName: '智能客服', status: 'success', tokens: '680', cost: '$0.014', responseTime: '0.9s', inputTokens: 280, outputTokens: 400, prompt: '用户询问:如何退货?', response: '您好,退货流程如下...' },
-				{ id: 3, timestamp: '2026-01-28 14:20:42', model: 'GPT-4', workflowName: '代码审查助手', status: 'success', tokens: '2,100', cost: '$0.042', responseTime: '2.3s', inputTokens: 1200, outputTokens: 900, prompt: '请审查以下代码...', response: '代码审查结果:整体结构良好...' },
-				{ id: 4, timestamp: '2026-01-28 14:18:05', model: 'GPT-3.5', workflowName: '数据分析', status: 'failed', tokens: '0', cost: '$0.000', responseTime: '5.0s', inputTokens: 0, outputTokens: 0, prompt: '分析销售数据...', response: 'Error: API rate limit exceeded' }
+				{
+					id: 1,
+					timestamp: '2026-01-28 14:25:33',
+					model: 'GPT-4',
+					workflowName: 'AI 文章生成',
+					status: 'success',
+					tokens: '1,250',
+					cost: '$0.025',
+					responseTime: '1.8s',
+					inputTokens: 450,
+					outputTokens: 800,
+					prompt: '请帮我生成一篇关于人工智能发展的文章...',
+					response: '人工智能的发展历程可以追溯到...'
+				},
+				{
+					id: 2,
+					timestamp: '2026-01-28 14:23:15',
+					model: 'Claude-3',
+					workflowName: '智能客服',
+					status: 'success',
+					tokens: '680',
+					cost: '$0.014',
+					responseTime: '0.9s',
+					inputTokens: 280,
+					outputTokens: 400,
+					prompt: '用户询问:如何退货?',
+					response: '您好,退货流程如下...'
+				},
+				{
+					id: 3,
+					timestamp: '2026-01-28 14:20:42',
+					model: 'GPT-4',
+					workflowName: '代码审查助手',
+					status: 'success',
+					tokens: '2,100',
+					cost: '$0.042',
+					responseTime: '2.3s',
+					inputTokens: 1200,
+					outputTokens: 900,
+					prompt: '请审查以下代码...',
+					response: '代码审查结果:整体结构良好...'
+				},
+				{
+					id: 4,
+					timestamp: '2026-01-28 14:18:05',
+					model: 'GPT-3.5',
+					workflowName: '数据分析',
+					status: 'failed',
+					tokens: '0',
+					cost: '$0.000',
+					responseTime: '5.0s',
+					inputTokens: 0,
+					outputTokens: 0,
+					prompt: '分析销售数据...',
+					response: 'Error: API rate limit exceeded'
+				}
 			]
 			]
 		},
 		},
 		statisticsPage: {
 		statisticsPage: {
@@ -619,43 +790,147 @@ export default {
 					chartTitle: '生产执行 - 按时间统计',
 					chartTitle: '生产执行 - 按时间统计',
 					tableTitle: '生产执行明细',
 					tableTitle: '生产执行明细',
 					tableData: [
 					tableData: [
-						{ name: '项目1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: '数据处理项目' },
-						{ name: '项目2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI 分析项目' },
-						{ name: '项目3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: '图像识别项目' }
+						{
+							name: '项目1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: '数据处理项目'
+						},
+						{
+							name: '项目2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI 分析项目'
+						},
+						{
+							name: '项目3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: '图像识别项目'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: '生产环境执行失败 - 按时间统计',
 					chartTitle: '生产环境执行失败 - 按时间统计',
 					tableTitle: '生产环境失败执行明细',
 					tableTitle: '生产环境失败执行明细',
 					tableData: [
 					tableData: [
-						{ name: '项目1', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '2.1s', projectName: '数据处理项目' },
-						{ name: '项目2', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '1.8s', projectName: 'AI 分析项目' },
-						{ name: '项目3', totalExecutions: 1, failedExecutions: 1, failureRate: '100%', timeSaved: '0h', avgRuntime: '3.3s', projectName: '图像识别项目' }
+						{
+							name: '项目1',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '2.1s',
+							projectName: '数据处理项目'
+						},
+						{
+							name: '项目2',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '1.8s',
+							projectName: 'AI 分析项目'
+						},
+						{
+							name: '项目3',
+							totalExecutions: 1,
+							failedExecutions: 1,
+							failureRate: '100%',
+							timeSaved: '0h',
+							avgRuntime: '3.3s',
+							projectName: '图像识别项目'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: '故障率 - 按时间统计',
 					chartTitle: '故障率 - 按时间统计',
 					tableTitle: '故障率统计明细',
 					tableTitle: '故障率统计明细',
 					tableData: [
 					tableData: [
-						{ name: '项目1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: '数据处理项目' },
-						{ name: '项目2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI 分析项目' }
+						{
+							name: '项目1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: '数据处理项目'
+						},
+						{
+							name: '项目2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI 分析项目'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: '节省时间 - 按时间统计',
 					chartTitle: '节省时间 - 按时间统计',
 					tableTitle: '节省时间统计明细',
 					tableTitle: '节省时间统计明细',
 					tableData: [
 					tableData: [
-						{ name: '项目1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: '数据处理项目' },
-						{ name: '项目3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: '图像识别项目' }
+						{
+							name: '项目1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: '数据处理项目'
+						},
+						{
+							name: '项目3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: '图像识别项目'
+						}
 					]
 					]
 				},
 				},
 				{
 				{
 					chartTitle: '运行时间(平均) - 按时间统计',
 					chartTitle: '运行时间(平均) - 按时间统计',
 					tableTitle: '运行时间统计明细',
 					tableTitle: '运行时间统计明细',
 					tableData: [
 					tableData: [
-						{ name: '项目2', totalExecutions: 18, failedExecutions: 1, failureRate: '5.6%', timeSaved: '4.2h', avgRuntime: '4.8s', projectName: 'AI 分析项目' },
-						{ name: '项目3', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.3s', projectName: '图像识别项目' },
-						{ name: '项目1', totalExecutions: 12, failedExecutions: 1, failureRate: '8.3%', timeSaved: '2.5h', avgRuntime: '5.1s', projectName: '数据处理项目' }
+						{
+							name: '项目2',
+							totalExecutions: 18,
+							failedExecutions: 1,
+							failureRate: '5.6%',
+							timeSaved: '4.2h',
+							avgRuntime: '4.8s',
+							projectName: 'AI 分析项目'
+						},
+						{
+							name: '项目3',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.3s',
+							projectName: '图像识别项目'
+						},
+						{
+							name: '项目1',
+							totalExecutions: 12,
+							failedExecutions: 1,
+							failureRate: '8.3%',
+							timeSaved: '2.5h',
+							avgRuntime: '5.1s',
+							projectName: '数据处理项目'
+						}
 					]
 					]
 				}
 				}
 			]
 			]
@@ -675,7 +950,10 @@ export default {
 			resourcesTitle: '更多资源',
 			resourcesTitle: '更多资源',
 			steps: [
 			steps: [
 				{ title: '创建工作流', desc: '点击左侧菜单的“+”按钮,选择“工作流程”创建你的第一个工作流' },
 				{ title: '创建工作流', desc: '点击左侧菜单的“+”按钮,选择“工作流程”创建你的第一个工作流' },
-				{ title: '添加节点', desc: '支持多种节点类型,包括开始、结束、HTTP 请求、条件分支、代码执行、数据查询等,快速搭建自动化业务逻辑' },
+				{
+					title: '添加节点',
+					desc: '支持多种节点类型,包括开始、结束、HTTP 请求、条件分支、代码执行、数据查询等,快速搭建自动化业务逻辑'
+				},
 				{ title: '配置与测试', desc: '配置节点参数,测试运行,确保工作流按预期执行' },
 				{ title: '配置与测试', desc: '配置节点参数,测试运行,确保工作流按预期执行' },
 				{ title: '部署上线', desc: '保存并激活工作流,让它自动为你工作' }
 				{ title: '部署上线', desc: '保存并激活工作流,让它自动为你工作' }
 			],
 			],
@@ -688,13 +966,36 @@ export default {
 		docs: {
 		docs: {
 			sidebarTitle: '文档导航',
 			sidebarTitle: '文档导航',
 			navSections: [
 			navSections: [
-				{ title: '快速开始', items: [{ key: 'intro', label: '介绍' }, { key: 'installation', label: '安装部署' }] },
-				{ title: '核心概念', items: [{ key: 'workflow', label: '工作流' }, { key: 'nodes', label: '节点' }, { key: 'credentials', label: '凭证管理' }] },
-				{ title: '节点文档', items: [{ key: 'http', label: 'HTTP 节点' }, { key: 'code', label: '代码节点' }, { key: 'database', label: '数据库节点' }] }
+				{
+					title: '快速开始',
+					items: [
+						{ key: 'intro', label: '介绍' },
+						{ key: 'installation', label: '安装部署' }
+					]
+				},
+				{
+					title: '核心概念',
+					items: [
+						{ key: 'workflow', label: '工作流' },
+						{ key: 'nodes', label: '节点' },
+						{ key: 'credentials', label: '凭证管理' }
+					]
+				},
+				{
+					title: '节点文档',
+					items: [
+						{ key: 'http', label: 'HTTP 节点' },
+						{ key: 'code', label: '代码节点' },
+						{ key: 'database', label: '数据库节点' }
+					]
+				}
 			],
 			],
 			docMap: {
 			docMap: {
 				intro: { title: 'AI Agent 介绍', description: '了解 AI Agent 的核心概念和基本使用方法' },
 				intro: { title: 'AI Agent 介绍', description: '了解 AI Agent 的核心概念和基本使用方法' },
-				installation: { title: '安装与部署', description: '学习如何在你的环境中安装和配置 AI Agent' },
+				installation: {
+					title: '安装与部署',
+					description: '学习如何在你的环境中安装和配置 AI Agent'
+				},
 				workflow: { title: '工作流概念', description: '深入理解工作流的设计模式和最佳实践' },
 				workflow: { title: '工作流概念', description: '深入理解工作流的设计模式和最佳实践' },
 				nodes: { title: '节点系统', description: '掌握节点系统的工作原理和使用技巧' },
 				nodes: { title: '节点系统', description: '掌握节点系统的工作原理和使用技巧' },
 				credentials: { title: '凭证管理', description: '安全地管理和使用第三方服务凭证' },
 				credentials: { title: '凭证管理', description: '安全地管理和使用第三方服务凭证' },
@@ -741,6 +1042,10 @@ export default {
 			mockResponse: '这是一个示例 AI 回复。'
 			mockResponse: '这是一个示例 AI 回复。'
 		},
 		},
 		editor: {
 		editor: {
+			status: {
+				published: '已发布',
+				unpublished: '待发布'
+			},
 			workspace: '工作区',
 			workspace: '工作区',
 			tagPlaceholder: '按回车键添加标签',
 			tagPlaceholder: '按回车键添加标签',
 			tagButton: '标签',
 			tagButton: '标签',
@@ -755,8 +1060,10 @@ export default {
 				loadFailed: '加载智能体流程失败',
 				loadFailed: '加载智能体流程失败',
 				saveFailed: '保存智能体失败',
 				saveFailed: '保存智能体失败',
 				saved: '智能体已保存',
 				saved: '智能体已保存',
-				varsSaved: '变量已保存'
-			}
+				varsSaved: '变量已保存',
+				publishSuccess: '发布成功'
+			},
+			selectPublishNode: '请选择要发布的节点'
 		},
 		},
 		nodeView: {
 		nodeView: {
 			messages: {
 			messages: {
@@ -1098,7 +1405,10 @@ export default {
 			'question-classifier': { displayName: '问题分类', description: '将问题划分到预设分类中' },
 			'question-classifier': { displayName: '问题分类', description: '将问题划分到预设分类中' },
 			'loop-end': { displayName: '退出循环', description: '用于退出迭代或者循环' },
 			'loop-end': { displayName: '退出循环', description: '用于退出迭代或者循环' },
 			'trigger-schedule': { displayName: '定时触发', description: '基于时间配置触发工作流' },
 			'trigger-schedule': { displayName: '定时触发', description: '基于时间配置触发工作流' },
-			'trigger-webhook': { displayName: 'Webhook 触发', description: '通过 Webhook 接收第三方系统请求并触发工作流' },
+			'trigger-webhook': {
+				displayName: 'Webhook 触发',
+				description: '通过 Webhook 接收第三方系统请求并触发工作流'
+			},
 			'loop-start': { displayName: '循环开始' },
 			'loop-start': { displayName: '循环开始' },
 			'iteration-start': { displayName: '迭代开始' },
 			'iteration-start': { displayName: '迭代开始' },
 			stickyNote: { displayName: '注释', description: 'Markdown 注释块' }
 			stickyNote: { displayName: '注释', description: 'Markdown 注释块' }

+ 1 - 1
apps/web/src/views/FlowManagement.vue

@@ -87,7 +87,7 @@
 					<div class="cover">
 					<div class="cover">
 						<img
 						<img
 							v-if="row.profilePhoto"
 							v-if="row.profilePhoto"
-							:src="row.profilePhoto"
+							:src="row.profilePhoto ? `/File/GetImage?fileId=${row.profilePhoto}` : undefined"
 							:alt="row.name"
 							:alt="row.name"
 							class="cover-image"
 							class="cover-image"
 						/>
 						/>

+ 23 - 5
apps/web/src/views/editor/Editor.vue

@@ -38,15 +38,19 @@
 			</div>
 			</div>
 
 
 			<div class="right flex items-center gap-2">
 			<div class="right flex items-center gap-2">
-				<el-button type="default" size="small">{{ t('pages.editor.publish') }}</el-button>
+				<PublishBtn :workflow="workflow" @published="handlePublished" />
 				<IconButton icon="lucide:history" type="default" link></IconButton>
 				<IconButton icon="lucide:history" type="default" link></IconButton>
 				<el-dropdown placement="bottom-end" popper-class="w-120px">
 				<el-dropdown placement="bottom-end" popper-class="w-120px">
 					<IconButton icon="fluent-mdl2:more" type="default" link></IconButton>
 					<IconButton icon="fluent-mdl2:more" type="default" link></IconButton>
 					<template #dropdown>
 					<template #dropdown>
 						<el-dropdown-item>{{ t('pages.editor.menu.description') }}</el-dropdown-item>
 						<el-dropdown-item>{{ t('pages.editor.menu.description') }}</el-dropdown-item>
 						<el-dropdown-item>{{ t('pages.editor.menu.reuse') }}</el-dropdown-item>
 						<el-dropdown-item>{{ t('pages.editor.menu.reuse') }}</el-dropdown-item>
-						<el-dropdown-item @click="handleRename">{{ t('pages.editor.menu.rename') }}</el-dropdown-item>
-						<el-dropdown-item divided @click="handleDelete">{{ t('pages.editor.menu.delete') }}</el-dropdown-item>
+						<el-dropdown-item @click="handleRename">{{
+							t('pages.editor.menu.rename')
+						}}</el-dropdown-item>
+						<el-dropdown-item divided @click="handleDelete">{{
+							t('pages.editor.menu.delete')
+						}}</el-dropdown-item>
 					</template>
 					</template>
 				</el-dropdown>
 				</el-dropdown>
 			</div>
 			</div>
@@ -72,6 +76,7 @@ import { agent } from '@repo/api-service'
 
 
 import EditorFooter from '@/features/editorFooter/index.vue'
 import EditorFooter from '@/features/editorFooter/index.vue'
 import NodeView from './NodeView.vue'
 import NodeView from './NodeView.vue'
+import PublishBtn from './PublishBtn.vue'
 import { nodeMap } from '@/nodes'
 import { nodeMap } from '@/nodes'
 import { IconButton, Input } from '@repo/ui'
 import { IconButton, Input } from '@repo/ui'
 import { useI18n } from '@/composables/useI18n'
 import { useI18n } from '@/composables/useI18n'
@@ -267,7 +272,11 @@ const saveAgentMeta = async () => {
 		const response = await agent.postAgentDoEditAgent({
 		const response = await agent.postAgentDoEditAgent({
 			data: workflow.value
 			data: workflow.value
 		})
 		})
-		handleApiResult(response, t('pages.editor.messages.saved'), t('pages.editor.messages.saveFailed'))
+		handleApiResult(
+			response,
+			t('pages.editor.messages.saved'),
+			t('pages.editor.messages.saveFailed')
+		)
 	} catch (error) {
 	} catch (error) {
 		console.error('saveAgentMeta error', error)
 		console.error('saveAgentMeta error', error)
 		ElMessage.error(t('pages.editor.messages.saveFailed'))
 		ElMessage.error(t('pages.editor.messages.saveFailed'))
@@ -288,7 +297,11 @@ const saveAgentVariables = async () => {
 				type: item?.type || 'string'
 				type: item?.type || 'string'
 			}))
 			}))
 		})
 		})
-		handleApiResult(response, t('pages.editor.messages.varsSaved'), t('pages.editor.messages.saveFailed'))
+		handleApiResult(
+			response,
+			t('pages.editor.messages.varsSaved'),
+			t('pages.editor.messages.saveFailed')
+		)
 	} catch (error) {
 	} catch (error) {
 		console.error('saveAgentVariables error', error)
 		console.error('saveAgentVariables error', error)
 		ElMessage.error(t('pages.editor.messages.saveFailed'))
 		ElMessage.error(t('pages.editor.messages.saveFailed'))
@@ -375,6 +388,11 @@ const handleDelete = () => {
 	})
 	})
 }
 }
 
 
+const handlePublished = async () => {
+	if (!workflow.value?.id) return
+	await loadAgentWorkflow(workflow.value.id)
+}
+
 onBeforeUnmount(() => {
 onBeforeUnmount(() => {
 	if (saveAgentTimer.value) window.clearTimeout(saveAgentTimer.value)
 	if (saveAgentTimer.value) window.clearTimeout(saveAgentTimer.value)
 	if (saveVarsTimer.value) window.clearTimeout(saveVarsTimer.value)
 	if (saveVarsTimer.value) window.clearTimeout(saveVarsTimer.value)

+ 1 - 1
apps/web/src/views/editor/NodeView.vue

@@ -928,7 +928,7 @@ const handleViewportChange = useDebounceFn((viewport: { x: number; y: number; zo
 		agent.postAgentDoEditAgent({
 		agent.postAgentDoEditAgent({
 			data: {
 			data: {
 				...props.workflow,
 				...props.workflow,
-				viewport: viewport
+				viewPort: viewport
 			}
 			}
 		})
 		})
 	}
 	}

+ 174 - 0
apps/web/src/views/editor/PublishBtn.vue

@@ -0,0 +1,174 @@
+<template>
+	<el-popover
+		ref="popoverRef"
+		width="240px"
+		trigger="click"
+		:disabled="publishNodes.length <= 1 || isPublishing"
+	>
+		<div v-if="publishNodes.length > 1" class="publish-selector">
+			<div class="publish-selector__title">{{ t('pages.editor.selectPublishNode') }}</div>
+			<button
+				v-for="node in publishNodes"
+				:key="node.id"
+				type="button"
+				class="publish-selector__item"
+				@click="handleSelectPublishNode(node.id)"
+			>
+				<span class="publish-selector__name">{{ node.name }}</span>
+				<span class="publish-selector__type">{{ getNodeDisplayName(node.nodeType) }}</span>
+			</button>
+		</div>
+		<template #reference>
+			<el-button
+				:type="isPublished ? 'success' : 'default'"
+				size="small"
+				:disabled="!publishNodes.length"
+				:loading="isPublishing"
+				@click="handlePublishClick"
+			>
+				<Icon v-if="isPublished" icon="ix:success" class="mr-1" />
+				{{
+					isPublished ? t('pages.editor.status.published') : t('pages.editor.status.unpublished')
+				}}
+			</el-button>
+		</template>
+	</el-popover>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue'
+import { ElMessage, type PopoverInstance } from 'element-plus'
+import { agent } from '@repo/api-service'
+import { Icon } from '@repo/ui'
+
+import type { IWorkflow } from '@repo/workflow'
+
+import { useI18n } from '@/composables/useI18n'
+import { getNodeDisplayName } from '@/nodes/i18n'
+
+const props = defineProps<{
+	workflow: IWorkflow
+}>()
+
+const emit = defineEmits<{
+	(e: 'published'): void
+}>()
+
+const { t } = useI18n()
+const popoverRef = ref<PopoverInstance>()
+const isPublishing = ref(false)
+
+const PUBLISHABLE_NODE_TYPES = ['start', 'trigger-schedule', 'trigger-webhook']
+
+const isPublished = computed(() => props.workflow?.status === 'published')
+
+const publishNodes = computed(() => {
+	return (props.workflow?.nodes || [])
+		.filter((node) => {
+			const nodeType = (node as any)?.nodeType || (node as any)?.data?.nodeType
+			return PUBLISHABLE_NODE_TYPES.includes(nodeType || '')
+		})
+		.map((node) => {
+			const nodeType = ((node as any)?.nodeType || (node as any)?.data?.nodeType || '') as string
+			return {
+				id: node.id,
+				name: node.name || node.data?.title || getNodeDisplayName(nodeType) || nodeType,
+				nodeType
+			}
+		})
+})
+
+const publishAgent = async (nodeId?: string) => {
+	if (!nodeId) {
+		ElMessage.warning(t('pages.editor.messages.missingPublishNode'))
+		return
+	}
+
+	if (isPublishing.value) {
+		return
+	}
+
+	isPublishing.value = true
+
+	try {
+		const response = await agent.postAgentDoAgentPublish({
+			start_node_id: nodeId,
+			appAgentId: props.workflow.id
+		})
+
+		if (response?.isSuccess) {
+			props.workflow.status = 'published'
+			popoverRef.value?.hide()
+			ElMessage.success(t('pages.editor.messages.publishSuccess'))
+			emit('published')
+			return
+		}
+
+		if ((response as any)?.error) {
+			ElMessage.error((response as any).error)
+			return
+		}
+
+		ElMessage.error(t('pages.editor.messages.publishFailed'))
+	} catch (error) {
+		console.error('postAgentDoAgentPublish error', error)
+		ElMessage.error(t('pages.editor.messages.publishFailed'))
+	} finally {
+		isPublishing.value = false
+	}
+}
+
+const handlePublishClick = () => {
+	if (publishNodes.value.length <= 1) {
+		publishAgent(publishNodes.value[0]?.id)
+	}
+}
+
+const handleSelectPublishNode = (id: string) => {
+	publishAgent(id)
+}
+</script>
+
+<style scoped>
+.publish-selector {
+	display: flex;
+	flex-direction: column;
+	gap: 8px;
+}
+
+.publish-selector__title {
+	font-size: 13px;
+	font-weight: 600;
+	color: #344054;
+}
+
+.publish-selector__item {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	gap: 12px;
+	width: 100%;
+	padding: 10px 12px;
+	border: 1px solid #e4e7ec;
+	border-radius: 10px;
+	background: #fff;
+	cursor: pointer;
+	text-align: left;
+}
+
+.publish-selector__item:hover {
+	border-color: #2563eb;
+	background: #f8fbff;
+}
+
+.publish-selector__name {
+	font-size: 13px;
+	font-weight: 600;
+	color: #344054;
+}
+
+.publish-selector__type {
+	font-size: 12px;
+	color: #667085;
+}
+</style>

+ 74 - 0
packages/api-service/agent.openapi.json

@@ -4534,6 +4534,80 @@
 				},
 				},
 				"security": []
 				"security": []
 			}
 			}
+		},
+		"/api/agent/doAgentPublish": {
+			"post": {
+				"summary": "发布智能体",
+				"deprecated": false,
+				"description": "",
+				"tags": ["Agent"],
+				"parameters": [
+					{
+						"name": "Authorization",
+						"in": "header",
+						"description": "",
+						"example": "bpm_client_1496159371585916928",
+						"schema": {
+							"type": "string",
+							"default": "bpm_client_1496159371585916928"
+						}
+					}
+				],
+				"requestBody": {
+					"content": {
+						"application/json": {
+							"schema": {
+								"type": "object",
+								"properties": {
+									"start_node_id": {
+										"type": "string"
+									},
+									"appAgentId": {
+										"type": "string",
+										"format": "uuid"
+									}
+								},
+								"required": ["start_node_id", "appAgentId"]
+							},
+							"example": {
+								"start_node_id": "3ba96b4e-25c2-486a-be27-94ab9957aba1"
+							}
+						}
+					},
+					"required": true
+				},
+				"responses": {
+					"200": {
+						"description": "",
+						"content": {
+							"application/json": {
+								"schema": {
+									"type": "object",
+									"properties": {
+										"isSuccess": {
+											"type": "boolean"
+										},
+										"code": {
+											"type": "integer"
+										},
+										"isAuthorized": {
+											"type": "boolean"
+										}
+									},
+									"required": ["isSuccess", "code", "isAuthorized"]
+								},
+								"example": {
+									"isSuccess": true,
+									"code": 1,
+									"isAuthorized": true
+								}
+							}
+						},
+						"headers": {}
+					}
+				},
+				"security": []
+			}
 		}
 		}
 	},
 	},
 	"components": {
 	"components": {

+ 21 - 0
packages/api-service/servers/api/agent.ts

@@ -2,6 +2,27 @@
 /* eslint-disable */
 /* eslint-disable */
 import request from '@repo/api-client'
 import request from '@repo/api-client'
 
 
+/** 发布智能体 POST /api/agent/doAgentPublish */
+export async function postAgentDoAgentPublish(
+  body: {
+    start_node_id: string
+    appAgentId: string
+  },
+  options?: { [key: string]: any }
+) {
+  return request<{ isSuccess: boolean; code: number; isAuthorized: boolean }>(
+    '/api/agent/doAgentPublish',
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json'
+      },
+      data: body,
+      ...(options || {})
+    }
+  )
+}
+
 /** 删除智能体节点 POST /api/agent/doDeleteAgentNode */
 /** 删除智能体节点 POST /api/agent/doDeleteAgentNode */
 export async function postAgentDoDeleteAgentNode(
 export async function postAgentDoDeleteAgentNode(
   body: {
   body: {

+ 1 - 1
packages/workflow/src/Workflow.vue

@@ -7,7 +7,7 @@
 			:edges="edges"
 			:edges="edges"
 			:read-only="readOnly"
 			:read-only="readOnly"
 			:node-map="nodeMap"
 			:node-map="nodeMap"
-			:default-viewport="workflow?.viewport"
+			:default-viewport="workflow?.viewPort"
 			hide-child-node
 			hide-child-node
 			v-bind="$attrs"
 			v-bind="$attrs"
 		/>
 		/>