vue-agent-start 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/package.json +30 -0
  2. package/pnpm-workspace.yaml +3 -0
  3. package/src/agent-flow/adapter/backend.ts +99 -0
  4. package/src/agent-flow/components/ChatIframePanel.vue +773 -0
  5. package/src/agent-flow/components/DatasetItemCard.vue +313 -0
  6. package/src/agent-flow/components/MemoryWindow.vue +104 -0
  7. package/src/agent-flow/components/PromptEditor.vue +804 -0
  8. package/src/agent-flow/components/PromptEditorTagPanel.vue +460 -0
  9. package/src/agent-flow/components/SvgIcon.vue +32 -0
  10. package/src/agent-flow/components/ToolItemCard.vue +169 -0
  11. package/src/agent-flow/components/VariableCard.vue +161 -0
  12. package/src/agent-flow/components/VariableSelector.vue +162 -0
  13. package/src/agent-flow/components/chat-iframe-types.ts +35 -0
  14. package/src/agent-flow/components/stubs/DatasetChooser.vue +70 -0
  15. package/src/agent-flow/components/stubs/Embedding.vue +22 -0
  16. package/src/agent-flow/components/stubs/ModelSelect.vue +24 -0
  17. package/src/agent-flow/components/stubs/RestfulSelectCard.vue +24 -0
  18. package/src/agent-flow/components/stubs/ToolChooser.vue +96 -0
  19. package/src/agent-flow/components/stubs/TriggersItemCard.vue +126 -0
  20. package/src/agent-flow/components/stubs/VariableModal.vue +115 -0
  21. package/src/agent-flow/index.ts +73 -0
  22. package/src/agent-flow/stores/workflow.ts +72 -0
  23. package/src/agent-flow/utils/langUtils.ts +173 -0
  24. package/src/agent-flow/workflow/Ability.vue +65 -0
  25. package/src/agent-flow/workflow/AuthorizationItem.vue +101 -0
  26. package/src/agent-flow/workflow/ConversationVar.vue +42 -0
  27. package/src/agent-flow/workflow/CustomEdge.vue +94 -0
  28. package/src/agent-flow/workflow/EnvironmentVar.vue +40 -0
  29. package/src/agent-flow/workflow/FlowDesigner.vue +2802 -0
  30. package/src/agent-flow/workflow/Icon.vue +179 -0
  31. package/src/agent-flow/workflow/NodeConfig.vue +509 -0
  32. package/src/agent-flow/workflow/NodeConfigCard.vue +460 -0
  33. package/src/agent-flow/workflow/NodeHandle.vue +147 -0
  34. package/src/agent-flow/workflow/NodeHeaderToolbar.vue +77 -0
  35. package/src/agent-flow/workflow/NodeHoverToolbar.vue +176 -0
  36. package/src/agent-flow/workflow/OutputItemCard.vue +668 -0
  37. package/src/agent-flow/workflow/ParamTableItem.vue +200 -0
  38. package/src/agent-flow/workflow/StructTable.vue +202 -0
  39. package/src/agent-flow/workflow/VarInsertField.vue +517 -0
  40. package/src/agent-flow/workflow/VarSelectField.vue +223 -0
  41. package/src/agent-flow/workflow/VariableSelectorItem.vue +48 -0
  42. package/src/agent-flow/workflow/WfField.vue +206 -0
  43. package/src/agent-flow/workflow/_config-base.css +470 -0
  44. package/src/agent-flow/workflow/composables/useNode.js +55 -0
  45. package/src/agent-flow/workflow/index.vue +53 -0
  46. package/src/agent-flow/workflow/nodeCard/AgentNodeCard.vue +180 -0
  47. package/src/agent-flow/workflow/nodeCard/AnswerNodeCard.vue +65 -0
  48. package/src/agent-flow/workflow/nodeCard/ClassifierCard.vue +152 -0
  49. package/src/agent-flow/workflow/nodeCard/CodeNodeCard.vue +139 -0
  50. package/src/agent-flow/workflow/nodeCard/ConditionNodeCard.vue +323 -0
  51. package/src/agent-flow/workflow/nodeCard/DocumentExtractorCard.vue +83 -0
  52. package/src/agent-flow/workflow/nodeCard/EndNodeCard.vue +123 -0
  53. package/src/agent-flow/workflow/nodeCard/HttpNodeCard.vue +451 -0
  54. package/src/agent-flow/workflow/nodeCard/HumanInputCard.vue +152 -0
  55. package/src/agent-flow/workflow/nodeCard/IterationCard.vue +66 -0
  56. package/src/agent-flow/workflow/nodeCard/KnowledgeRetrievalCard.vue +48 -0
  57. package/src/agent-flow/workflow/nodeCard/LLMNodeCard.vue +206 -0
  58. package/src/agent-flow/workflow/nodeCard/ListOperatorCard.vue +188 -0
  59. package/src/agent-flow/workflow/nodeCard/ParameterExtractorCard.vue +352 -0
  60. package/src/agent-flow/workflow/nodeCard/ServiceApiNodeCard.vue +188 -0
  61. package/src/agent-flow/workflow/nodeCard/StartNodeCard.vue +216 -0
  62. package/src/agent-flow/workflow/nodeCard/VariableAssignerCard.vue +125 -0
  63. package/src/agent-flow/workflow/nodeCard/VariableNodeCard.vue +121 -0
  64. package/src/agent-flow/workflow/nodes/AgentNode.vue +122 -0
  65. package/src/agent-flow/workflow/nodes/AnswerNode.vue +99 -0
  66. package/src/agent-flow/workflow/nodes/ClassifierNode.vue +199 -0
  67. package/src/agent-flow/workflow/nodes/CodeNode.vue +152 -0
  68. package/src/agent-flow/workflow/nodes/ConditionNode.vue +232 -0
  69. package/src/agent-flow/workflow/nodes/DocumentExtractorNode.vue +96 -0
  70. package/src/agent-flow/workflow/nodes/EndNode.vue +119 -0
  71. package/src/agent-flow/workflow/nodes/FileUploadNode.vue +97 -0
  72. package/src/agent-flow/workflow/nodes/HttpNode.vue +204 -0
  73. package/src/agent-flow/workflow/nodes/HumanInputNode.vue +110 -0
  74. package/src/agent-flow/workflow/nodes/IterationNode.vue +98 -0
  75. package/src/agent-flow/workflow/nodes/KnowledgeRetrievalNode.vue +253 -0
  76. package/src/agent-flow/workflow/nodes/LLMNode.vue +134 -0
  77. package/src/agent-flow/workflow/nodes/ListOperatorNode.vue +111 -0
  78. package/src/agent-flow/workflow/nodes/LoopNode.vue +94 -0
  79. package/src/agent-flow/workflow/nodes/ParameterExtractorNode.vue +147 -0
  80. package/src/agent-flow/workflow/nodes/ServiceApiNode.vue +161 -0
  81. package/src/agent-flow/workflow/nodes/StartNode.vue +199 -0
  82. package/src/agent-flow/workflow/nodes/TemplateNode.vue +103 -0
  83. package/src/agent-flow/workflow/nodes/UserInputNode.vue +92 -0
  84. package/src/agent-flow/workflow/nodes/VariableAssignerNode.vue +145 -0
  85. package/src/agent-flow/workflow/nodes/VariableNode.vue +130 -0
  86. package/src/agent-flow/workflow/nodes/_node-base.css +338 -0
  87. package/src/agent-flow/workflow/utils/node_card_form.ts +335 -0
  88. package/src/agent-flow/workflow/utils/node_config.ts +63 -0
  89. package/src/agent-flow/workflow/utils/workflow_utils.ts +151 -0
  90. package/src/agent-studio/adapters/springAgentStart.ts +390 -0
  91. package/src/agent-studio/api/index.ts +1 -0
  92. package/src/agent-studio/api/types.ts +173 -0
  93. package/src/agent-studio/components/AgentApiDocs.vue +500 -0
  94. package/src/agent-studio/components/AgentAppsPage.vue +1601 -0
  95. package/src/agent-studio/components/AgentCardGrid.vue +259 -0
  96. package/src/agent-studio/components/AgentChatPage.vue +553 -0
  97. package/src/agent-studio/components/AgentDebugPanel.vue +350 -0
  98. package/src/agent-studio/components/AgentLogsPanel.vue +391 -0
  99. package/src/agent-studio/components/AgentMonitorPanel.vue +204 -0
  100. package/src/agent-studio/components/AgentOrchestrate.vue +505 -0
  101. package/src/agent-studio/components/AgentPromptEditor.vue +237 -0
  102. package/src/agent-studio/components/AgentStudioShell.vue +227 -0
  103. package/src/agent-studio/components/AgentToolsPanel.vue +394 -0
  104. package/src/agent-studio/components/AgentVariablesPanel.vue +205 -0
  105. package/src/agent-studio/components/ApiKeyManager.vue +251 -0
  106. package/src/agent-studio/components/AppDesignDrawer.vue +3391 -0
  107. package/src/agent-studio/components/CreateAppModal.vue +737 -0
  108. package/src/agent-studio/components/SparkChart.vue +200 -0
  109. package/src/agent-studio/components/VariableEditorModal.vue +499 -0
  110. package/src/agent-studio/composables/useAgentStudio.ts +347 -0
  111. package/src/agent-studio/index.ts +60 -0
  112. package/src/agent-studio/panels/DrawerFlowDesigner.vue +203 -0
  113. package/src/agent-studio/panels/LogAnnotationPanel.vue +490 -0
  114. package/src/agent-studio/panels/MonitorPanel.vue +535 -0
  115. package/src/agent-studio/types.ts +242 -0
  116. package/src/index.ts +155 -0
  117. package/src/knowledge-hub/adapters/springAgentStart.ts +472 -0
  118. package/src/knowledge-hub/components/AddDocumentsWizard.vue +1452 -0
  119. package/src/knowledge-hub/components/CreateDatasetWizard.vue +1723 -0
  120. package/src/knowledge-hub/components/DatasetCardGrid.vue +467 -0
  121. package/src/knowledge-hub/components/DatasetDetailDrawer.vue +888 -0
  122. package/src/knowledge-hub/components/DatasetPicker.vue +65 -0
  123. package/src/knowledge-hub/components/DatasetPickerModal.vue +526 -0
  124. package/src/knowledge-hub/components/DatasetSettingsPanel.vue +908 -0
  125. package/src/knowledge-hub/components/DatasetSidebar.vue +781 -0
  126. package/src/knowledge-hub/components/DocumentChunksView.vue +802 -0
  127. package/src/knowledge-hub/components/DocumentTable.vue +552 -0
  128. package/src/knowledge-hub/components/HitTestingPanel.vue +74 -0
  129. package/src/knowledge-hub/components/KnowledgeApp.vue +66 -0
  130. package/src/knowledge-hub/components/KnowledgeHubApp.vue +504 -0
  131. package/src/knowledge-hub/components/RecallTestingPanelV2.vue +515 -0
  132. package/src/knowledge-hub/components/RetrievalConfigPopover.vue +270 -0
  133. package/src/knowledge-hub/components/RetrievalMethodPicker.vue +547 -0
  134. package/src/knowledge-hub/components/RetrievedList.vue +24 -0
  135. package/src/knowledge-hub/components/internal/KhDialog.vue +195 -0
  136. package/src/knowledge-hub/composables/useKnowledge.ts +89 -0
  137. package/src/knowledge-hub/i18n/index.ts +2 -0
  138. package/src/knowledge-hub/i18n/messages.ts +422 -0
  139. package/src/knowledge-hub/i18n/useKhI18n.ts +107 -0
  140. package/src/knowledge-hub/index.ts +46 -0
  141. package/src/knowledge-hub/styles/index.css +4 -0
  142. package/src/knowledge-hub/styles/tokens.css +138 -0
  143. package/src/knowledge-hub/types/api.ts +213 -0
  144. package/src/knowledge-hub/types/dataset.ts +88 -0
  145. package/src/knowledge-hub/types/document.ts +45 -0
  146. package/src/knowledge-hub/types/index.ts +9 -0
  147. package/src/knowledge-hub/types/retrieval.ts +46 -0
  148. package/src/provider-hub/components/CredentialForm.vue +103 -0
  149. package/src/provider-hub/components/DefaultModelsPanel.vue +270 -0
  150. package/src/provider-hub/components/GroupedModelSelect.vue +445 -0
  151. package/src/provider-hub/components/ModelCardGrid.vue +332 -0
  152. package/src/provider-hub/components/ModelParameterDrawer.vue +739 -0
  153. package/src/provider-hub/components/ModelPickerPopover.vue +1282 -0
  154. package/src/provider-hub/components/ProviderApp.vue +159 -0
  155. package/src/provider-hub/components/ProviderCredentialModal.vue +321 -0
  156. package/src/provider-hub/components/ProviderGallery.vue +131 -0
  157. package/src/provider-hub/components/ProviderHubShell.vue +1992 -0
  158. package/src/provider-hub/components/ProviderIcon.vue +130 -0
  159. package/src/provider-hub/composables/useProviderHub.ts +358 -0
  160. package/src/provider-hub/index.ts +43 -0
  161. package/src/provider-hub/svg/MiniMax.svg +1 -0
  162. package/src/provider-hub/svg/Volcengine.svg +1 -0
  163. package/src/provider-hub/svg/Zhipu.svg +1 -0
  164. package/src/provider-hub/svg/deepseek.svg +1 -0
  165. package/src/provider-hub/svg/moonshot.svg +1 -0
  166. package/src/provider-hub/svg/openai.svg +1 -0
  167. package/src/provider-hub/svg/qwen.svg +1 -0
  168. package/src/provider-hub/svg/siliconflow.svg +1 -0
  169. package/src/provider-hub/types.ts +256 -0
@@ -0,0 +1,119 @@
1
+ <script setup>
2
+ import { ref } from 'vue';
3
+
4
+ import NodeHandle from '@/workflow/NodeHandle.vue';
5
+ import NodeHoverToolbar from '@/workflow/NodeHoverToolbar.vue';
6
+ import workflow_utils from '@/workflow/utils/workflow_utils';
7
+
8
+ import Icon from '../Icon.vue';
9
+
10
+ const props = defineProps({
11
+ id: String,
12
+ data: {
13
+ type: Object,
14
+ default: () => ({
15
+ label: '结束',
16
+ description: '工作流结束节点',
17
+ }),
18
+ },
19
+ });
20
+
21
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
22
+
23
+ const isCompleted = ref(false);
24
+ const isHovered = ref(false);
25
+
26
+ const onMouseEnter = () => {
27
+ isHovered.value = true;
28
+ };
29
+
30
+ const onMouseLeave = () => {
31
+ isHovered.value = false;
32
+ };
33
+
34
+ const duplicateNode = () => {
35
+ emit('duplicate', props.id);
36
+ };
37
+
38
+ const deleteNode = () => {
39
+ emit('delete', props.id);
40
+ };
41
+
42
+ const getAnswerTexts = (answer) => {
43
+ const label = [];
44
+ const list = workflow_utils.splitExpressions(answer);
45
+ for (let i = 0, len = list.length; i < len; i++) {
46
+ const it = list[i];
47
+ if (it.startsWith('{{#')) {
48
+ label.push(it);
49
+ }
50
+ }
51
+ return label;
52
+ };
53
+
54
+ const getAnswerTextLabel = (variableSelector) => {
55
+ return workflow_utils.getVariableLabel(variableSelector);
56
+ };
57
+ </script>
58
+
59
+ <template>
60
+ <div
61
+ class="wf-node end-node"
62
+ @mouseenter="onMouseEnter"
63
+ @mouseleave="onMouseLeave"
64
+ >
65
+ <NodeHoverToolbar
66
+ v-if="isHovered"
67
+ node-type="end"
68
+ @duplicate="duplicateNode"
69
+ @delete="deleteNode"
70
+ />
71
+
72
+ <div class="wf-node-header">
73
+ <div class="wf-node-icon">
74
+ <Icon name="end" />
75
+ </div>
76
+ <div class="wf-node-info">
77
+ <div class="wf-node-title">{{ data.label }}</div>
78
+ <div class="wf-node-description">{{ data.description }}</div>
79
+ </div>
80
+ </div>
81
+
82
+ <div v-if="isCompleted" class="wf-node-status">
83
+ <div class="wf-node-status-indicator wf-is-completed"></div>
84
+ </div>
85
+
86
+ <div class="wf-node-content">
87
+ <div v-if="data.output && data.output.length" class="wf-node-answer-preview">
88
+ <div class="wf-node-answer-text">
89
+ <div v-for="it in data.output" :key="it.name" class="wf-node-answer-row">
90
+ <div>{{ it.name }}</div>
91
+ <div>{{ getAnswerTextLabel(it.variableSelector) }}</div>
92
+ </div>
93
+ </div>
94
+ </div>
95
+ <div v-else class="wf-node-empty">
96
+ <span class="wf-node-empty-text">尚未配置输出</span>
97
+ </div>
98
+ </div>
99
+
100
+ <NodeHandle
101
+ :id="id"
102
+ type="target"
103
+ position="Left"
104
+ :is-hovered="isHovered"
105
+ class-name="flow-node-handle-left"
106
+ :style="{
107
+ background: '#ef4444',
108
+ border: '2px solid #ffffff',
109
+ }"
110
+ />
111
+ </div>
112
+ </template>
113
+
114
+ <style scoped>
115
+ .end-node {
116
+ --wf-accent: #ef4444;
117
+ --wf-accent-hover: #dc2626;
118
+ }
119
+ </style>
@@ -0,0 +1,97 @@
1
+ <script setup>
2
+ import { ref } from 'vue';
3
+
4
+ import Icon from '../Icon.vue';
5
+ import NodeHandle from '../NodeHandle.vue';
6
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
7
+
8
+ const props = defineProps({
9
+ id: String,
10
+ data: {
11
+ type: Object,
12
+ default: () => ({
13
+ label: '文件上传',
14
+ description: '文件上传节点',
15
+ config: {
16
+ allowedTypes: ['pdf', 'txt', 'doc'],
17
+ maxSize: 10,
18
+ },
19
+ }),
20
+ },
21
+ });
22
+
23
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
24
+
25
+ const isHovered = ref(false);
26
+
27
+ const onMouseEnter = () => (isHovered.value = true);
28
+ const onMouseLeave = () => (isHovered.value = false);
29
+ const duplicateNode = () => emit('duplicate', props.id);
30
+ const deleteNode = () => emit('delete', props.id);
31
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
32
+ emit('connection-plus-click', event, nodeId, handleId);
33
+ };
34
+ </script>
35
+
36
+ <template>
37
+ <div
38
+ class="wf-node file-upload-node"
39
+ @mouseenter="onMouseEnter"
40
+ @mouseleave="onMouseLeave"
41
+ >
42
+ <NodeHoverToolbar
43
+ v-if="isHovered"
44
+ node-type="file-upload"
45
+ @duplicate="duplicateNode"
46
+ @delete="deleteNode"
47
+ />
48
+
49
+ <div class="wf-node-header">
50
+ <div class="wf-node-icon">
51
+ <Icon name="file" />
52
+ </div>
53
+ <div class="wf-node-info">
54
+ <div class="wf-node-title">{{ data.label }}</div>
55
+ <div class="wf-node-subtitle">文件上传</div>
56
+ </div>
57
+ </div>
58
+
59
+ <div class="wf-node-content">
60
+ <div class="wf-node-description">{{ data.description }}</div>
61
+ <div v-if="data.config?.allowedTypes?.length" class="wf-node-preview">
62
+ <div class="wf-node-preview-label">支持格式</div>
63
+ <div class="wf-node-preview-value">
64
+ {{ data.config.allowedTypes.join(', ') }}
65
+ </div>
66
+ </div>
67
+ <div v-else class="wf-node-empty">
68
+ <span class="wf-node-empty-text">配置文件上传</span>
69
+ </div>
70
+ </div>
71
+
72
+ <NodeHandle
73
+ :id="id"
74
+ type="target"
75
+ position="Left"
76
+ class-name="flow-node-handle-left"
77
+ :style="{ background: '#059669', border: '2px solid #ffffff' }"
78
+ />
79
+
80
+ <NodeHandle
81
+ :id="id"
82
+ type="source"
83
+ position="Right"
84
+ :is-hovered="isHovered"
85
+ class-name="flow-node-handle-right"
86
+ :style="{ background: '#059669', border: '2px solid #ffffff' }"
87
+ @connection-plus-click="onConnectionPlusClick"
88
+ />
89
+ </div>
90
+ </template>
91
+
92
+ <style scoped>
93
+ .file-upload-node {
94
+ --wf-accent: #059669;
95
+ --wf-accent-hover: #047857;
96
+ }
97
+ </style>
@@ -0,0 +1,204 @@
1
+ <script setup>
2
+ import { computed, ref } from 'vue';
3
+
4
+ import Icon from '../Icon.vue';
5
+ import NodeHandle from '../NodeHandle.vue';
6
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
7
+
8
+ const props = defineProps({
9
+ id: String,
10
+ data: {
11
+ type: Object,
12
+ default: () => ({
13
+ label: 'HTTP 请求',
14
+ description: 'HTTP 请求节点',
15
+ method: 'GET',
16
+ url: '',
17
+ headers: [],
18
+ parameters: [],
19
+ body: {},
20
+ bodyType: 'NONE',
21
+ }),
22
+ },
23
+ });
24
+
25
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
26
+
27
+ const isHovered = ref(false);
28
+
29
+ const onMouseEnter = () => (isHovered.value = true);
30
+ const onMouseLeave = () => (isHovered.value = false);
31
+ const duplicateNode = () => emit('duplicate', props.id);
32
+ const deleteNode = () => emit('delete', props.id);
33
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
34
+ emit('connection-plus-click', event, nodeId, handleId);
35
+ };
36
+
37
+ /** 有效表头计数:nodeCard 里 headers 是 [{name, value}] 数组,忽略空条目 */
38
+ const headerCount = computed(() => {
39
+ const headers = props.data.headers;
40
+ if (!Array.isArray(headers)) return 0;
41
+ return headers.filter((h) => h && h.name).length;
42
+ });
43
+
44
+ const paramCount = computed(() => {
45
+ const params = props.data.parameters;
46
+ if (!Array.isArray(params)) return 0;
47
+ return params.filter((p) => p && p.name).length;
48
+ });
49
+
50
+ const method = computed(() => (props.data.method || 'GET').toUpperCase());
51
+ const url = computed(() => props.data.url || '');
52
+ const bodyType = computed(() => (props.data.bodyType || 'NONE').toUpperCase());
53
+ const authEnabled = computed(() => {
54
+ const auth = props.data.authorization;
55
+ return !!(auth && auth.auth_type && auth.auth_type !== 'none');
56
+ });
57
+
58
+ const truncateText = (text, maxLength) => {
59
+ if (!text) return '';
60
+ return text.length > maxLength
61
+ ? `${text.slice(0, Math.max(0, maxLength))}...`
62
+ : text;
63
+ };
64
+ </script>
65
+
66
+ <template>
67
+ <div
68
+ class="wf-node http-node"
69
+ @mouseenter="onMouseEnter"
70
+ @mouseleave="onMouseLeave"
71
+ >
72
+ <NodeHoverToolbar
73
+ v-if="isHovered"
74
+ node-type="http"
75
+ @duplicate="duplicateNode"
76
+ @delete="deleteNode"
77
+ />
78
+
79
+ <div class="wf-node-header">
80
+ <div class="wf-node-icon">
81
+ <Icon name="http" />
82
+ </div>
83
+ <div class="wf-node-info">
84
+ <div class="wf-node-title">{{ data.label }}</div>
85
+ <div class="wf-node-subtitle">HTTP 请求</div>
86
+ </div>
87
+ </div>
88
+
89
+ <div class="wf-node-content">
90
+ <div class="wf-node-description">{{ data.description }}</div>
91
+ <div class="wf-node-preview http-preview">
92
+ <div class="http-row">
93
+ <span :class="['http-method', `is-${method.toLowerCase()}`]">{{ method }}</span>
94
+ <span class="http-url" :title="url">{{ url ? truncateText(url, 30) : '未配置 URL' }}</span>
95
+ <span v-if="authEnabled" class="http-auth-badge" title="已配置鉴权">🔒</span>
96
+ </div>
97
+ <div v-if="bodyType !== 'NONE'" class="http-row">
98
+ <span class="http-meta-label">Body</span>
99
+ <span class="http-meta-value http-body-type">{{ bodyType.toLowerCase().replace(/_/g, '-') }}</span>
100
+ </div>
101
+ <div v-if="headerCount > 0 || paramCount > 0" class="http-row http-meta-row">
102
+ <template v-if="headerCount > 0">
103
+ <span class="http-meta-label">Headers</span>
104
+ <span class="http-meta-value">{{ headerCount }}</span>
105
+ </template>
106
+ <template v-if="paramCount > 0">
107
+ <span class="http-meta-label">Query</span>
108
+ <span class="http-meta-value">{{ paramCount }}</span>
109
+ </template>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <NodeHandle
115
+ :id="id"
116
+ type="target"
117
+ position="Left"
118
+ class-name="flow-node-handle-left"
119
+ :style="{ background: '#06b6d4', border: '2px solid #ffffff' }"
120
+ />
121
+
122
+ <NodeHandle
123
+ :id="id"
124
+ type="source"
125
+ position="Right"
126
+ :is-hovered="isHovered"
127
+ class-name="flow-node-handle-right"
128
+ :style="{ background: '#06b6d4', border: '2px solid #ffffff' }"
129
+ @connection-plus-click="onConnectionPlusClick"
130
+ />
131
+ </div>
132
+ </template>
133
+
134
+ <style scoped>
135
+ .http-node {
136
+ --wf-accent: #06b6d4;
137
+ --wf-accent-hover: #0891b2;
138
+ }
139
+
140
+ .http-preview {
141
+ display: flex;
142
+ flex-direction: column;
143
+ gap: 6px;
144
+ }
145
+
146
+ .http-row {
147
+ display: flex;
148
+ align-items: center;
149
+ gap: 8px;
150
+ font-size: 11px;
151
+ }
152
+
153
+ .http-method {
154
+ padding: 2px 8px;
155
+ font-size: 10px;
156
+ font-weight: 700;
157
+ color: #ffffff;
158
+ background: #6b7280;
159
+ border-radius: 4px;
160
+ letter-spacing: 0.5px;
161
+ }
162
+ .http-method.is-get { background: #2563eb; }
163
+ .http-method.is-post { background: #059669; }
164
+ .http-method.is-put { background: #d97706; }
165
+ .http-method.is-delete { background: #dc2626; }
166
+ .http-method.is-patch { background: #7c3aed; }
167
+
168
+ .http-url {
169
+ flex: 1;
170
+ min-width: 0;
171
+ overflow: hidden;
172
+ color: #1f2937;
173
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
174
+ text-overflow: ellipsis;
175
+ white-space: nowrap;
176
+ }
177
+
178
+ .http-meta-label {
179
+ color: color-mix(in srgb, var(--wf-accent) 90%, #000);
180
+ font-weight: 500;
181
+ }
182
+
183
+ .http-meta-value {
184
+ color: #1f2937;
185
+ }
186
+
187
+ .http-meta-row {
188
+ gap: 12px;
189
+ }
190
+
191
+ .http-body-type {
192
+ padding: 1px 6px;
193
+ background: #eef2ff;
194
+ color: #4338ca;
195
+ border-radius: 4px;
196
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
197
+ font-size: 10px;
198
+ }
199
+
200
+ .http-auth-badge {
201
+ font-size: 10px;
202
+ opacity: 0.75;
203
+ }
204
+ </style>
@@ -0,0 +1,110 @@
1
+ <script setup>
2
+ import { computed, ref } from 'vue';
3
+
4
+ import Icon from '../Icon.vue';
5
+ import NodeHandle from '../NodeHandle.vue';
6
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
7
+
8
+ const props = defineProps({
9
+ id: String,
10
+ data: {
11
+ type: Object,
12
+ default: () => ({
13
+ label: '人工介入',
14
+ description: '暂停工作流等待人工审批或补充信息',
15
+ approvalType: 'approve',
16
+ formFields: [],
17
+ }),
18
+ },
19
+ });
20
+
21
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
22
+
23
+ const isHovered = ref(false);
24
+ const onMouseEnter = () => (isHovered.value = true);
25
+ const onMouseLeave = () => (isHovered.value = false);
26
+ const duplicateNode = () => emit('duplicate', props.id);
27
+ const deleteNode = () => emit('delete', props.id);
28
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
29
+ emit('connection-plus-click', event, nodeId, handleId);
30
+ };
31
+
32
+ const approvalLabel = computed(() =>
33
+ ({
34
+ approve: '审批(是/否)',
35
+ form: '表单填写',
36
+ text: '文本回复',
37
+ })[props.data.approvalType] || '未配置'
38
+ );
39
+
40
+ const fieldCount = computed(() => props.data.formFields?.length || 0);
41
+ </script>
42
+
43
+ <template>
44
+ <div
45
+ class="wf-node human-input-node"
46
+ @mouseenter="onMouseEnter"
47
+ @mouseleave="onMouseLeave"
48
+ >
49
+ <NodeHoverToolbar
50
+ v-if="isHovered"
51
+ node-type="human_input"
52
+ @duplicate="duplicateNode"
53
+ @delete="deleteNode"
54
+ />
55
+
56
+ <div class="wf-node-header">
57
+ <div class="wf-node-icon">
58
+ <Icon name="user" />
59
+ </div>
60
+ <div class="wf-node-info">
61
+ <div class="wf-node-title">{{ data.label }}</div>
62
+ <div class="wf-node-subtitle">等待人工响应</div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="wf-node-content">
67
+ <div class="wf-node-description">{{ data.description }}</div>
68
+ <div class="wf-node-preview">
69
+ <div class="wf-node-preview-label">介入类型</div>
70
+ <div class="wf-node-preview-value">{{ approvalLabel }}</div>
71
+ </div>
72
+ <div v-if="fieldCount > 0" class="human-field-hint">
73
+ {{ fieldCount }} 个表单字段
74
+ </div>
75
+ </div>
76
+
77
+ <NodeHandle
78
+ :id="id"
79
+ type="target"
80
+ position="Left"
81
+ class-name="flow-node-handle-left"
82
+ :style="{ background: '#f59e0b', border: '2px solid #ffffff' }"
83
+ />
84
+ <NodeHandle
85
+ :id="id"
86
+ type="source"
87
+ position="Right"
88
+ :is-hovered="isHovered"
89
+ class-name="flow-node-handle-right"
90
+ :style="{ background: '#f59e0b', border: '2px solid #ffffff' }"
91
+ @connection-plus-click="onConnectionPlusClick"
92
+ />
93
+ </div>
94
+ </template>
95
+
96
+ <style scoped>
97
+ .human-input-node {
98
+ --wf-accent: #f59e0b;
99
+ --wf-accent-hover: #d97706;
100
+ }
101
+
102
+ .human-field-hint {
103
+ margin-top: 4px;
104
+ padding: 4px 8px;
105
+ font-size: 11px;
106
+ color: #78716c;
107
+ background: #fef3c7;
108
+ border-radius: 4px;
109
+ }
110
+ </style>
@@ -0,0 +1,98 @@
1
+ <script setup>
2
+ import { computed, ref } from 'vue';
3
+
4
+ import workflow_utils from '@/workflow/utils/workflow_utils';
5
+
6
+ import Icon from '../Icon.vue';
7
+ import NodeHandle from '../NodeHandle.vue';
8
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
9
+
10
+ const props = defineProps({
11
+ id: String,
12
+ data: {
13
+ type: Object,
14
+ default: () => ({
15
+ label: '迭代',
16
+ description: '对列表变量的每一项执行子图',
17
+ iteratorVariableSelector: [],
18
+ outputVariableSelector: [],
19
+ }),
20
+ },
21
+ });
22
+
23
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
24
+
25
+ const isHovered = ref(false);
26
+
27
+ const onMouseEnter = () => (isHovered.value = true);
28
+ const onMouseLeave = () => (isHovered.value = false);
29
+ const duplicateNode = () => emit('duplicate', props.id);
30
+ const deleteNode = () => emit('delete', props.id);
31
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
32
+ emit('connection-plus-click', event, nodeId, handleId);
33
+ };
34
+
35
+ const iterVarLabel = computed(() =>
36
+ workflow_utils.getVariableLabel(props.data.iteratorVariableSelector || []),
37
+ );
38
+ </script>
39
+
40
+ <template>
41
+ <div
42
+ class="wf-node iteration-node"
43
+ @mouseenter="onMouseEnter"
44
+ @mouseleave="onMouseLeave"
45
+ >
46
+ <NodeHoverToolbar
47
+ v-if="isHovered"
48
+ node-type="iteration"
49
+ @duplicate="duplicateNode"
50
+ @delete="deleteNode"
51
+ />
52
+
53
+ <div class="wf-node-header">
54
+ <div class="wf-node-icon">
55
+ <Icon name="loop" />
56
+ </div>
57
+ <div class="wf-node-info">
58
+ <div class="wf-node-title">{{ data.label }}</div>
59
+ <div class="wf-node-subtitle">迭代子图</div>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="wf-node-content">
64
+ <div class="wf-node-description">{{ data.description }}</div>
65
+ <div v-if="iterVarLabel" class="wf-node-preview">
66
+ <div class="wf-node-preview-label">迭代变量</div>
67
+ <div class="wf-node-preview-value">{{ iterVarLabel }}</div>
68
+ </div>
69
+ <div v-else class="wf-node-empty">
70
+ <span class="wf-node-empty-text">选择要迭代的列表变量</span>
71
+ </div>
72
+ </div>
73
+
74
+ <NodeHandle
75
+ :id="id"
76
+ type="target"
77
+ position="Left"
78
+ class-name="flow-node-handle-left"
79
+ :style="{ background: '#f472b6', border: '2px solid #ffffff' }"
80
+ />
81
+ <NodeHandle
82
+ :id="id"
83
+ type="source"
84
+ position="Right"
85
+ :is-hovered="isHovered"
86
+ class-name="flow-node-handle-right"
87
+ :style="{ background: '#f472b6', border: '2px solid #ffffff' }"
88
+ @connection-plus-click="onConnectionPlusClick"
89
+ />
90
+ </div>
91
+ </template>
92
+
93
+ <style scoped>
94
+ .iteration-node {
95
+ --wf-accent: #f472b6;
96
+ --wf-accent-hover: #ec4899;
97
+ }
98
+ </style>