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,147 @@
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
+ parameters: [],
16
+ model: { modelName: '' },
17
+ }),
18
+ },
19
+ });
20
+
21
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
22
+
23
+ const isHovered = ref(false);
24
+
25
+ const onMouseEnter = () => (isHovered.value = true);
26
+ const onMouseLeave = () => (isHovered.value = false);
27
+ const duplicateNode = () => emit('duplicate', props.id);
28
+ const deleteNode = () => emit('delete', props.id);
29
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
30
+ emit('connection-plus-click', event, nodeId, handleId);
31
+ };
32
+
33
+ const paramCount = computed(() => props.data.parameters?.length || 0);
34
+ const params = computed(() => props.data.parameters?.slice(0, 3) || []);
35
+ const modelProvider = computed(
36
+ () => props.data.model?.provider || props.data.model?.providerName || '',
37
+ );
38
+ const modelName = computed(() => props.data.model?.modelName || '');
39
+ </script>
40
+
41
+ <template>
42
+ <div
43
+ class="wf-node parameter-extractor-node"
44
+ @mouseenter="onMouseEnter"
45
+ @mouseleave="onMouseLeave"
46
+ >
47
+ <NodeHoverToolbar
48
+ v-if="isHovered"
49
+ node-type="parameter_extractor"
50
+ @duplicate="duplicateNode"
51
+ @delete="deleteNode"
52
+ />
53
+
54
+ <div class="wf-node-header">
55
+ <div class="wf-node-icon">
56
+ <Icon name="variable" />
57
+ </div>
58
+ <div class="wf-node-info">
59
+ <div class="wf-node-title">{{ data.label }}</div>
60
+ <div class="wf-node-subtitle">
61
+ <template v-if="modelName">
62
+ <div v-if="modelProvider">{{ modelProvider }}</div>
63
+ <div>{{ modelName }}</div>
64
+ </template>
65
+ <div v-else class="wf-node-subtitle-empty">未选择模型</div>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="wf-node-content">
71
+ <div class="wf-node-description">{{ data.description }}</div>
72
+ <div v-if="paramCount > 0" class="wf-node-preview">
73
+ <div class="wf-node-preview-label">抽取参数 · {{ paramCount }} 个</div>
74
+ <div class="wf-node-preview-list">
75
+ <div v-for="p in params" :key="p.name" class="param-row">
76
+ <span class="param-name">{{ p.name }}</span>
77
+ <span class="param-type">{{ p.type || 'string' }}</span>
78
+ </div>
79
+ <div v-if="paramCount > 3" class="param-more">
80
+ +{{ paramCount - 3 }} 个更多
81
+ </div>
82
+ </div>
83
+ </div>
84
+ <div v-else class="wf-node-empty">
85
+ <span class="wf-node-empty-text">配置抽取字段</span>
86
+ </div>
87
+ </div>
88
+
89
+ <NodeHandle
90
+ :id="id"
91
+ type="target"
92
+ position="Left"
93
+ class-name="flow-node-handle-left"
94
+ :style="{ background: '#eab308', border: '2px solid #ffffff' }"
95
+ />
96
+ <NodeHandle
97
+ :id="id"
98
+ type="source"
99
+ position="Right"
100
+ :is-hovered="isHovered"
101
+ class-name="flow-node-handle-right"
102
+ :style="{ background: '#eab308', border: '2px solid #ffffff' }"
103
+ @connection-plus-click="onConnectionPlusClick"
104
+ />
105
+ </div>
106
+ </template>
107
+
108
+ <style scoped>
109
+ .parameter-extractor-node {
110
+ --wf-accent: #eab308;
111
+ --wf-accent-hover: #ca8a04;
112
+ }
113
+
114
+ .wf-node-subtitle-empty {
115
+ font-style: italic;
116
+ color: #9ca3af;
117
+ font-weight: 400;
118
+ }
119
+
120
+ .param-row {
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: space-between;
124
+ gap: 8px;
125
+ padding: 2px 6px;
126
+ font-size: 11px;
127
+ background: color-mix(in srgb, var(--wf-accent) 8%, transparent);
128
+ border-radius: 4px;
129
+ }
130
+
131
+ .param-name {
132
+ color: #1f2937;
133
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
134
+ }
135
+
136
+ .param-type {
137
+ color: color-mix(in srgb, var(--wf-accent) 85%, #000);
138
+ font-weight: 500;
139
+ }
140
+
141
+ .param-more {
142
+ padding: 2px 6px;
143
+ font-size: 10px;
144
+ font-style: italic;
145
+ color: #9ca3af;
146
+ }
147
+ </style>
@@ -0,0 +1,161 @@
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
+ method: 'GET',
16
+ url: '',
17
+ headers: [],
18
+ parameters: [],
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 headerCount = computed(() => {
36
+ const headers = props.data.headers;
37
+ if (!Array.isArray(headers)) return 0;
38
+ return headers.filter((h) => h && h.name).length;
39
+ });
40
+
41
+ const method = computed(() => (props.data.method || 'GET').toUpperCase());
42
+ const url = computed(() => props.data.url || '');
43
+
44
+ const truncateText = (text, maxLength) => {
45
+ if (!text) return '';
46
+ return text.length > maxLength
47
+ ? `${text.slice(0, Math.max(0, maxLength))}...`
48
+ : text;
49
+ };
50
+ </script>
51
+
52
+ <template>
53
+ <div
54
+ class="wf-node service-api-node"
55
+ @mouseenter="onMouseEnter"
56
+ @mouseleave="onMouseLeave"
57
+ >
58
+ <NodeHoverToolbar
59
+ v-if="isHovered"
60
+ node-type="service-api"
61
+ @duplicate="duplicateNode"
62
+ @delete="deleteNode"
63
+ />
64
+
65
+ <div class="wf-node-header">
66
+ <div class="wf-node-icon">
67
+ <Icon name="service" />
68
+ </div>
69
+ <div class="wf-node-info">
70
+ <div class="wf-node-title">{{ data.label }}</div>
71
+ <div class="wf-node-subtitle">服务接口</div>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="wf-node-content">
76
+ <div class="wf-node-description">{{ data.description }}</div>
77
+ <div class="wf-node-preview http-preview">
78
+ <div class="http-row">
79
+ <span :class="['http-method', `is-${method.toLowerCase()}`]">{{ method }}</span>
80
+ <span class="http-url" :title="url">{{ url ? truncateText(url, 30) : '未配置接口地址' }}</span>
81
+ </div>
82
+ <div v-if="headerCount > 0" class="http-row">
83
+ <span class="http-meta-label">头部</span>
84
+ <span class="http-meta-value">{{ headerCount }} 个</span>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <NodeHandle
90
+ :id="id"
91
+ type="target"
92
+ position="Left"
93
+ class-name="flow-node-handle-left"
94
+ :style="{ background: '#0ea5a4', border: '2px solid #ffffff' }"
95
+ />
96
+
97
+ <NodeHandle
98
+ :id="id"
99
+ type="source"
100
+ position="Right"
101
+ :is-hovered="isHovered"
102
+ class-name="flow-node-handle-right"
103
+ :style="{ background: '#0ea5a4', border: '2px solid #ffffff' }"
104
+ @connection-plus-click="onConnectionPlusClick"
105
+ />
106
+ </div>
107
+ </template>
108
+
109
+ <style scoped>
110
+ .service-api-node {
111
+ --wf-accent: #0ea5a4;
112
+ --wf-accent-hover: #0d9488;
113
+ }
114
+
115
+ .http-preview {
116
+ display: flex;
117
+ flex-direction: column;
118
+ gap: 6px;
119
+ }
120
+
121
+ .http-row {
122
+ display: flex;
123
+ align-items: center;
124
+ gap: 8px;
125
+ font-size: 11px;
126
+ }
127
+
128
+ .http-method {
129
+ padding: 2px 8px;
130
+ font-size: 10px;
131
+ font-weight: 700;
132
+ color: #ffffff;
133
+ background: #6b7280;
134
+ border-radius: 4px;
135
+ letter-spacing: 0.5px;
136
+ }
137
+ .http-method.is-get { background: #2563eb; }
138
+ .http-method.is-post { background: #059669; }
139
+ .http-method.is-put { background: #d97706; }
140
+ .http-method.is-delete { background: #dc2626; }
141
+ .http-method.is-patch { background: #7c3aed; }
142
+
143
+ .http-url {
144
+ flex: 1;
145
+ min-width: 0;
146
+ overflow: hidden;
147
+ color: #1f2937;
148
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
149
+ text-overflow: ellipsis;
150
+ white-space: nowrap;
151
+ }
152
+
153
+ .http-meta-label {
154
+ color: color-mix(in srgb, var(--wf-accent) 90%, #000);
155
+ font-weight: 500;
156
+ }
157
+
158
+ .http-meta-value {
159
+ color: #1f2937;
160
+ }
161
+ </style>
@@ -0,0 +1,199 @@
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
+ variables: [],
16
+ }),
17
+ },
18
+ });
19
+
20
+ const variables = computed(() =>
21
+ Array.isArray(props.data.variables) ? props.data.variables : [],
22
+ );
23
+
24
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
25
+
26
+ const isRunning = ref(false);
27
+ const isHovered = ref(false);
28
+
29
+ const onMouseEnter = () => {
30
+ isHovered.value = true;
31
+ };
32
+
33
+ const onMouseLeave = () => {
34
+ isHovered.value = false;
35
+ };
36
+
37
+ const duplicateNode = () => {
38
+ emit('duplicate', props.id);
39
+ };
40
+
41
+ const deleteNode = () => {
42
+ emit('delete', props.id);
43
+ };
44
+
45
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
46
+ emit('connection-plus-click', event, nodeId, handleId);
47
+ };
48
+ </script>
49
+
50
+ <template>
51
+ <div
52
+ class="wf-node start-node"
53
+ @mouseenter="onMouseEnter"
54
+ @mouseleave="onMouseLeave"
55
+ >
56
+ <NodeHoverToolbar
57
+ v-if="isHovered"
58
+ node-type="start"
59
+ @duplicate="duplicateNode"
60
+ @delete="deleteNode"
61
+ />
62
+
63
+ <div class="wf-node-header">
64
+ <div class="wf-node-icon">
65
+ <Icon name="start" />
66
+ </div>
67
+ <div class="wf-node-info">
68
+ <div class="wf-node-title">{{ data.label }}</div>
69
+ <div class="wf-row">
70
+ <div class="wf-node-description">{{ data.description }}</div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="wf-node-content">
76
+ <div v-if="data.triggers && data.triggers.name" class="wf-node-triggers">
77
+ <img
78
+ class="wf-node-triggers-icon"
79
+ src="https://picsum.photos/800/600?random=11"
80
+ alt=""
81
+ />
82
+ <div>{{ data.triggers.name }}</div>
83
+ <div class="wf-node-triggers-scope">全部</div>
84
+ </div>
85
+
86
+ <div v-if="variables.length > 0" class="wf-node-preview start-var-preview">
87
+ <div class="wf-node-preview-label">输入变量</div>
88
+ <div class="wf-node-preview-list">
89
+ <div
90
+ v-for="v in variables"
91
+ :key="v.id ?? v.name"
92
+ class="start-var-row"
93
+ >
94
+ <span class="start-var-left">
95
+ <span class="start-var-name">{{ v.name }}</span>
96
+ <span v-if="v.label && v.label !== v.name" class="start-var-label">
97
+ {{ v.label }}
98
+ </span>
99
+ </span>
100
+ <span class="start-var-meta">
101
+ <span class="start-var-type">{{ v.type || 'string' }}</span>
102
+ <span v-if="v.required" class="start-var-required">必填</span>
103
+ </span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <div v-if="isRunning" class="wf-node-status">
110
+ <div class="wf-node-status-indicator wf-is-running"></div>
111
+ </div>
112
+
113
+ <NodeHandle
114
+ :id="id"
115
+ type="source"
116
+ position="Right"
117
+ :is-hovered="isHovered"
118
+ class-name="flow-node-handle-right"
119
+ :style="{
120
+ background: '#10b981',
121
+ border: '2px solid #ffffff',
122
+ }"
123
+ @connection-plus-click="onConnectionPlusClick"
124
+ />
125
+ </div>
126
+ </template>
127
+
128
+ <style scoped>
129
+ .start-node {
130
+ --wf-accent: #10b981;
131
+ --wf-accent-hover: #059669;
132
+ }
133
+
134
+ .start-var-preview {
135
+ margin-top: 8px;
136
+ }
137
+
138
+ .start-var-row {
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: space-between;
142
+ gap: 8px;
143
+ padding: 2px 6px;
144
+ font-size: 11px;
145
+ background: color-mix(in srgb, var(--wf-accent) 8%, transparent);
146
+ border-radius: 4px;
147
+ }
148
+
149
+ .start-var-left {
150
+ display: inline-flex;
151
+ align-items: baseline;
152
+ gap: 6px;
153
+ min-width: 0;
154
+ overflow: hidden;
155
+ }
156
+
157
+ .start-var-name {
158
+ color: #1f2937;
159
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
160
+ overflow: hidden;
161
+ text-overflow: ellipsis;
162
+ white-space: nowrap;
163
+ }
164
+
165
+ .start-var-label {
166
+ color: #6b7280;
167
+ font-size: 10px;
168
+ overflow: hidden;
169
+ text-overflow: ellipsis;
170
+ white-space: nowrap;
171
+ }
172
+
173
+ .start-var-meta {
174
+ display: inline-flex;
175
+ align-items: center;
176
+ gap: 4px;
177
+ flex: none;
178
+ }
179
+
180
+ .start-var-type {
181
+ color: color-mix(in srgb, var(--wf-accent) 85%, #000);
182
+ font-weight: 500;
183
+ }
184
+
185
+ .start-var-required {
186
+ padding: 0 4px;
187
+ font-size: 10px;
188
+ color: #b45309;
189
+ background: #fef3c7;
190
+ border-radius: 3px;
191
+ }
192
+
193
+ .start-var-more {
194
+ padding: 2px 6px;
195
+ font-size: 10px;
196
+ font-style: italic;
197
+ color: #9ca3af;
198
+ }
199
+ </style>
@@ -0,0 +1,103 @@
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
+ template: '',
17
+ variables: [],
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
+
35
+ const truncateText = (text, maxLength) => {
36
+ if (!text) return '';
37
+ return text.length > maxLength
38
+ ? `${text.slice(0, Math.max(0, maxLength))}...`
39
+ : text;
40
+ };
41
+ </script>
42
+
43
+ <template>
44
+ <div
45
+ class="wf-node template-node"
46
+ @mouseenter="onMouseEnter"
47
+ @mouseleave="onMouseLeave"
48
+ >
49
+ <NodeHoverToolbar
50
+ v-if="isHovered"
51
+ node-type="template"
52
+ @duplicate="duplicateNode"
53
+ @delete="deleteNode"
54
+ />
55
+
56
+ <div class="wf-node-header">
57
+ <div class="wf-node-icon">
58
+ <Icon name="template" />
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 v-if="data.config?.template" class="wf-node-preview">
69
+ <div class="wf-node-preview-label">模板预览</div>
70
+ <div class="wf-node-preview-value">
71
+ {{ truncateText(data.config.template, 50) }}
72
+ </div>
73
+ </div>
74
+ <div v-else class="wf-node-empty">
75
+ <span class="wf-node-empty-text">配置转换模板</span>
76
+ </div>
77
+ </div>
78
+
79
+ <NodeHandle
80
+ :id="id"
81
+ type="target"
82
+ position="Left"
83
+ class-name="flow-node-handle-left"
84
+ :style="{ background: '#a855f7', border: '2px solid #ffffff' }"
85
+ />
86
+ <NodeHandle
87
+ :id="id"
88
+ type="source"
89
+ position="Right"
90
+ :is-hovered="isHovered"
91
+ class-name="flow-node-handle-right"
92
+ :style="{ background: '#a855f7', border: '2px solid #ffffff' }"
93
+ @connection-plus-click="onConnectionPlusClick"
94
+ />
95
+ </div>
96
+ </template>
97
+
98
+ <style scoped>
99
+ .template-node {
100
+ --wf-accent: #a855f7;
101
+ --wf-accent-hover: #9333ea;
102
+ }
103
+ </style>
@@ -0,0 +1,92 @@
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: { variable: '' },
16
+ }),
17
+ },
18
+ });
19
+
20
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
21
+
22
+ const isHovered = ref(false);
23
+
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
+ </script>
32
+
33
+ <template>
34
+ <div
35
+ class="wf-node user-input-node"
36
+ @mouseenter="onMouseEnter"
37
+ @mouseleave="onMouseLeave"
38
+ >
39
+ <NodeHoverToolbar
40
+ v-if="isHovered"
41
+ node-type="user-input"
42
+ @duplicate="duplicateNode"
43
+ @delete="deleteNode"
44
+ />
45
+
46
+ <div class="wf-node-header">
47
+ <div class="wf-node-icon">
48
+ <Icon name="user" />
49
+ </div>
50
+ <div class="wf-node-info">
51
+ <div class="wf-node-title">{{ data.label }}</div>
52
+ <div class="wf-node-subtitle">用户输入</div>
53
+ </div>
54
+ </div>
55
+
56
+ <div class="wf-node-content">
57
+ <div class="wf-node-description">{{ data.description }}</div>
58
+ <div v-if="data.config?.variable" class="wf-node-preview">
59
+ <div class="wf-node-preview-label">输入变量</div>
60
+ <div class="wf-node-preview-value">{{ data.config.variable }}</div>
61
+ </div>
62
+ <div v-else class="wf-node-empty">
63
+ <span class="wf-node-empty-text">配置输入变量</span>
64
+ </div>
65
+ </div>
66
+
67
+ <NodeHandle
68
+ :id="id"
69
+ type="target"
70
+ position="Left"
71
+ class-name="flow-node-handle-left"
72
+ :style="{ background: '#3b82f6', border: '2px solid #ffffff' }"
73
+ />
74
+
75
+ <NodeHandle
76
+ :id="id"
77
+ type="source"
78
+ position="Right"
79
+ :is-hovered="isHovered"
80
+ class-name="flow-node-handle-right"
81
+ :style="{ background: '#3b82f6', border: '2px solid #ffffff' }"
82
+ @connection-plus-click="onConnectionPlusClick"
83
+ />
84
+ </div>
85
+ </template>
86
+
87
+ <style scoped>
88
+ .user-input-node {
89
+ --wf-accent: #3b82f6;
90
+ --wf-accent-hover: #2563eb;
91
+ }
92
+ </style>