13
13
测试
14
14
</el-button >
15
15
</div >
16
+
17
+ <!-- 测试窗口 -->
18
+ <el-drawer v-model =" showTestDrawer" title =" 工作流测试" :modal =" false" >
19
+ <fieldset >
20
+ <legend class =" ml-15px" ><h3 >运行参数配置</h3 ></legend >
21
+ <div class =" p-20px" >
22
+ <div
23
+ class =" flex justify-around mb-10px"
24
+ v-for =" (param, index) in params4Test"
25
+ :key =" index"
26
+ >
27
+ <el-select class =" w-200px!" v-model =" param.key" placeholder =" 参数名" >
28
+ <el-option
29
+ v-for =" (value, key) in paramsOfStartNode"
30
+ :key =" key"
31
+ :label =" value?.description || key"
32
+ :value =" key"
33
+ :disabled =" !!value?.disabled"
34
+ />
35
+ </el-select >
36
+ <el-input class =" w-200px!" v-model =" param.value" placeholder =" 参数值" />
37
+ <el-button type =" danger" plain :icon =" Delete" circle @click =" removeParam(index)" />
38
+ </div >
39
+ <el-button type =" primary" plain @click =" addParam" >添加参数</el-button >
40
+ </div >
41
+ </fieldset >
42
+ <fieldset class =" mt-20px bg-#f8f9fa" >
43
+ <legend class =" ml-15px" ><h3 >运行结果</h3 ></legend >
44
+ <div class =" p-20px" >
45
+ <div v-if =" loading" > <el-text type =" primary" >执行中...</el-text ></div >
46
+ <div v-else-if =" error" >
47
+ <el-text type =" danger" >{{ error }}</el-text >
48
+ </div >
49
+ <pre v-else-if =" testResult" class =" result-content"
50
+ >{{ JSON.stringify(testResult, null, 2) }}
51
+ </pre >
52
+ <div v-else > <el-text type =" info" >点击运行查看结果</el-text > </div >
53
+ </div >
54
+ </fieldset >
55
+ <el-button class =" mt-20px w-100%" size =" large" type =" success" @click =" goRun"
56
+ >运行流程</el-button
57
+ >
58
+ </el-drawer >
16
59
</div >
17
60
</template >
18
61
19
62
<script setup lang="ts">
20
63
import Tinyflow from ' @/components/Tinyflow/Tinyflow.vue'
64
+ import * as WorkflowApi from ' @/api/ai/workflow'
65
+ import { Delete } from ' @element-plus/icons-vue'
21
66
22
67
defineProps <{
23
68
provider: any
24
69
}>()
25
70
26
71
const tinyflowRef = ref ()
27
72
const workflowData = inject (' workflowData' ) as Ref
73
+ const showTestDrawer = ref (false )
74
+ const params4Test = ref ([])
75
+ const paramsOfStartNode = ref ({})
76
+ const testResult = ref (null )
77
+ const loading = ref (false )
78
+ const error = ref (null )
28
79
80
+ /** 展示工作流测试抽屉 */
29
81
const testWorkflowModel = () => {
30
- // TODO @lesan 测试
82
+ showTestDrawer .value = ! showTestDrawer .value
83
+ }
84
+
85
+ /** 运行流程 */
86
+ const goRun = async () => {
87
+ try {
88
+ const val = tinyflowRef .value .getData ()
89
+ loading .value = true
90
+ error .value = null
91
+ testResult .value = null
92
+ // / 查找start节点
93
+ const startNode = getStartNode ()
94
+
95
+ // 获取参数定义
96
+ const parameters = startNode .data ?.parameters || []
97
+ const paramDefinitions = {}
98
+ parameters .forEach ((param ) => {
99
+ paramDefinitions [param .name ] = param .dataType
100
+ })
101
+
102
+ // 参数类型转换
103
+ const convertedParams = {}
104
+ for (const { key, value } of params4Test .value ) {
105
+ const paramKey = key .trim ()
106
+ if (! paramKey ) continue
107
+
108
+ let dataType = paramDefinitions [paramKey ]
109
+ if (! dataType ) {
110
+ dataType = ' String'
111
+ }
112
+
113
+ try {
114
+ convertedParams [paramKey ] = convertParamValue (value , dataType )
115
+ } catch (e ) {
116
+ throw new Error (` 参数 ${paramKey } 转换失败: ${e .message } ` )
117
+ }
118
+ }
119
+
120
+ const data = {
121
+ graph: JSON .stringify (val ),
122
+ params: convertedParams
123
+ }
124
+
125
+ const response = await WorkflowApi .testWorkflow (data )
126
+ testResult .value = response
127
+ } catch (err ) {
128
+ error .value = err .response ?.data ?.message || ' 运行失败,请检查参数和网络连接'
129
+ } finally {
130
+ loading .value = false
131
+ }
132
+ }
133
+
134
+ /** 监听测试抽屉的开启,获取开始节点参数列表 */
135
+ watch (showTestDrawer , (value ) => {
136
+ if (! value ) return
137
+
138
+ // / 查找start节点
139
+ const startNode = getStartNode ()
140
+
141
+ // 获取参数定义
142
+ const parameters = startNode .data ?.parameters || []
143
+ const paramDefinitions = {}
144
+
145
+ // 加入参数选项方便用户添加非必须参数
146
+ parameters .forEach ((param ) => {
147
+ paramDefinitions [param .name ] = param
148
+ })
149
+
150
+ function mergeIfRequiredButNotSet(target ) {
151
+ let needPushList = []
152
+ for (let key in paramDefinitions ) {
153
+ let param = paramDefinitions [key ]
154
+
155
+ if (param .required ) {
156
+ let item = target .find ((item ) => item .key === key )
157
+
158
+ if (! item ) {
159
+ needPushList .push ({ key: param .name , value: param .defaultValue || ' ' })
160
+ }
161
+ }
162
+ }
163
+ target .push (... needPushList )
164
+ }
165
+ // 自动装载需必填的参数
166
+ mergeIfRequiredButNotSet (params4Test .value )
167
+
168
+ paramsOfStartNode .value = paramDefinitions
169
+ })
170
+
171
+ /** 获取开始节点 */
172
+ const getStartNode = () => {
173
+ const val = tinyflowRef .value .getData ()
174
+ const startNode = val .nodes .find ((node ) => node .type === ' startNode' )
175
+ if (! startNode ) {
176
+ throw new Error (' 流程缺少开始节点' )
177
+ }
178
+ return startNode
179
+ }
180
+
181
+ /** 添加参数项 */
182
+ const addParam = () => {
183
+ params4Test .value .push ({ key: ' ' , value: ' ' })
184
+ }
185
+
186
+ /** 删除参数项 */
187
+ const removeParam = (index ) => {
188
+ params4Test .value .splice (index , 1 )
189
+ }
190
+
191
+ /** 类型转换函数 */
192
+ const convertParamValue = (value , dataType ) => {
193
+ if (value === ' ' ) return null // 空值处理
194
+
195
+ switch (dataType ) {
196
+ case ' String' :
197
+ return String (value )
198
+ case ' Number' :
199
+ const num = Number (value )
200
+ if (isNaN (num )) throw new Error (' 非数字格式' )
201
+ return num
202
+ case ' Boolean' :
203
+ if (value .toLowerCase () === ' true' ) return true
204
+ if (value .toLowerCase () === ' false' ) return false
205
+ throw new Error (' 必须为 true/false' )
206
+ case ' Object' :
207
+ case ' Array' :
208
+ try {
209
+ return JSON .parse (value )
210
+ } catch (e ) {
211
+ throw new Error (` JSON格式错误: ${e .message } ` )
212
+ }
213
+ default :
214
+ throw new Error (` 不支持的类型: ${dataType } ` )
215
+ }
31
216
}
32
217
33
218
/** 表单校验 */
@@ -47,3 +232,17 @@ defineExpose({
47
232
validate
48
233
})
49
234
</script >
235
+
236
+ <style lang="css" scoped>
237
+ .result-content {
238
+ background : white ;
239
+ padding : 12px ;
240
+ border-radius : 4px ;
241
+ max-height : 300px ;
242
+ overflow : auto ;
243
+ font-family : Monaco, Consolas, monospace ;
244
+ font-size : 14px ;
245
+ line-height : 1.5 ;
246
+ white-space : pre-wrap ;
247
+ }
248
+ </style >
0 commit comments