From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/ai/workflow/form/WorkflowDesign.vue | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 250 insertions(+), 0 deletions(-)
diff --git a/src/views/ai/workflow/form/WorkflowDesign.vue b/src/views/ai/workflow/form/WorkflowDesign.vue
new file mode 100644
index 0000000..1346f9c
--- /dev/null
+++ b/src/views/ai/workflow/form/WorkflowDesign.vue
@@ -0,0 +1,250 @@
+<template>
+ <div class="relative" style="width: 100%; height: 700px">
+ <Tinyflow
+ v-if="workflowData"
+ ref="tinyflowRef"
+ :className="'custom-class'"
+ :style="{ width: '100%', height: '100%' }"
+ :data="workflowData"
+ :provider="provider"
+ />
+ <div class="absolute top-30px right-30px">
+ <el-button @click="testWorkflowModel" type="primary" v-hasPermi="['ai:workflow:test']">
+ 娴嬭瘯
+ </el-button>
+ </div>
+
+ <!-- 娴嬭瘯绐楀彛 -->
+ <el-drawer v-model="showTestDrawer" title="宸ヤ綔娴佹祴璇�" :modal="false">
+ <fieldset>
+ <legend class="ml-15px"><h3>杩愯鍙傛暟閰嶇疆</h3></legend>
+ <div class="p-20px">
+ <div
+ class="flex justify-around mb-10px"
+ v-for="(param, index) in params4Test"
+ :key="index"
+ >
+ <el-select class="w-200px!" v-model="param.key" placeholder="鍙傛暟鍚�">
+ <el-option
+ v-for="(value, key) in paramsOfStartNode"
+ :key="key"
+ :label="value?.description || key"
+ :value="key"
+ :disabled="!!value?.disabled"
+ />
+ </el-select>
+ <el-input class="w-200px!" v-model="param.value" placeholder="鍙傛暟鍊�" />
+ <el-button type="danger" plain :icon="Delete" circle @click="removeParam(index)" />
+ </div>
+ <!-- TODO @lesan锛氭槸涓嶆槸涓嶇敤娣诲姞鍜屽垹闄ゅ弬鏁帮紝鐩存帴鎶婂繀濉拰閫夊~鍒楀嚭鏉ワ紝鐒跺悗鍔犱笂鍙傛暟鏍¢獙锛� -->
+ <el-button type="primary" plain @click="addParam">娣诲姞鍙傛暟</el-button>
+ </div>
+ </fieldset>
+ <fieldset class="mt-20px bg-#f8f9fa">
+ <legend class="ml-15px"><h3>杩愯缁撴灉</h3></legend>
+ <div class="p-20px">
+ <div v-if="loading"> <el-text type="primary">鎵ц涓�...</el-text></div>
+ <div v-else-if="error">
+ <el-text type="danger">{{ error }}</el-text>
+ </div>
+ <pre v-else-if="testResult" class="result-content"
+ >{{ JSON.stringify(testResult, null, 2) }}
+ </pre>
+ <div v-else> <el-text type="info">鐐瑰嚮杩愯鏌ョ湅缁撴灉</el-text> </div>
+ </div>
+ </fieldset>
+ <el-button class="mt-20px w-100%" size="large" type="success" @click="goRun">
+ 杩愯娴佺▼
+ </el-button>
+ </el-drawer>
+ </div>
+</template>
+
+<script setup lang="ts">
+import Tinyflow from '@/components/Tinyflow/Tinyflow.vue'
+import * as WorkflowApi from '@/api/ai/workflow'
+// TODO @lesan锛氳涓嶄娇鐢� ICon 鍝釜缁勪欢鍝�
+import { Delete } from '@element-plus/icons-vue'
+
+defineProps<{
+ provider: any
+}>()
+
+const tinyflowRef = ref()
+const workflowData = inject('workflowData') as Ref
+const showTestDrawer = ref(false)
+const params4Test = ref([])
+const paramsOfStartNode = ref({})
+const testResult = ref(null)
+const loading = ref(false)
+const error = ref(null)
+
+/** 灞曠ず宸ヤ綔娴佹祴璇曟娊灞� */
+const testWorkflowModel = () => {
+ showTestDrawer.value = !showTestDrawer.value
+}
+
+/** 杩愯娴佺▼ */
+const goRun = async () => {
+ try {
+ const val = tinyflowRef.value.getData()
+ loading.value = true
+ error.value = null
+ testResult.value = null
+ /// 鏌ユ壘start鑺傜偣
+ const startNode = getStartNode()
+
+ // 鑾峰彇鍙傛暟瀹氫箟
+ const parameters = startNode.data?.parameters || []
+ const paramDefinitions = {}
+ parameters.forEach((param) => {
+ paramDefinitions[param.name] = param.dataType
+ })
+
+ // 鍙傛暟绫诲瀷杞崲
+ const convertedParams = {}
+ for (const { key, value } of params4Test.value) {
+ const paramKey = key.trim()
+ if (!paramKey) continue
+
+ let dataType = paramDefinitions[paramKey]
+ if (!dataType) {
+ dataType = 'String'
+ }
+
+ try {
+ convertedParams[paramKey] = convertParamValue(value, dataType)
+ } catch (e) {
+ throw new Error(`鍙傛暟 ${paramKey} 杞崲澶辫触: ${e.message}`)
+ }
+ }
+
+ const data = {
+ graph: JSON.stringify(val),
+ params: convertedParams
+ }
+
+ const response = await WorkflowApi.testWorkflow(data)
+ testResult.value = response
+ } catch (err) {
+ error.value = err.response?.data?.message || '杩愯澶辫触锛岃妫�鏌ュ弬鏁板拰缃戠粶杩炴帴'
+ } finally {
+ loading.value = false
+ }
+}
+
+/** 鐩戝惉娴嬭瘯鎶藉眽鐨勫紑鍚紝鑾峰彇寮�濮嬭妭鐐瑰弬鏁板垪琛� */
+watch(showTestDrawer, (value) => {
+ if (!value) return
+
+ /// 鏌ユ壘start鑺傜偣
+ const startNode = getStartNode()
+
+ // 鑾峰彇鍙傛暟瀹氫箟
+ const parameters = startNode.data?.parameters || []
+ const paramDefinitions = {}
+
+ // 鍔犲叆鍙傛暟閫夐」鏂逛究鐢ㄦ埛娣诲姞闈炲繀椤诲弬鏁�
+ parameters.forEach((param) => {
+ paramDefinitions[param.name] = param
+ })
+
+ function mergeIfRequiredButNotSet(target) {
+ let needPushList = []
+ for (let key in paramDefinitions) {
+ let param = paramDefinitions[key]
+
+ if (param.required) {
+ let item = target.find((item) => item.key === key)
+
+ if (!item) {
+ needPushList.push({ key: param.name, value: param.defaultValue || '' })
+ }
+ }
+ }
+ target.push(...needPushList)
+ }
+ // 鑷姩瑁呰浇闇�蹇呭~鐨勫弬鏁�
+ mergeIfRequiredButNotSet(params4Test.value)
+
+ paramsOfStartNode.value = paramDefinitions
+})
+
+/** 鑾峰彇寮�濮嬭妭鐐� */
+const getStartNode = () => {
+ const val = tinyflowRef.value.getData()
+ const startNode = val.nodes.find((node) => node.type === 'startNode')
+ if (!startNode) {
+ throw new Error('娴佺▼缂哄皯寮�濮嬭妭鐐�')
+ }
+ return startNode
+}
+
+/** 娣诲姞鍙傛暟椤� */
+const addParam = () => {
+ params4Test.value.push({ key: '', value: '' })
+}
+
+/** 鍒犻櫎鍙傛暟椤� */
+const removeParam = (index) => {
+ params4Test.value.splice(index, 1)
+}
+
+/** 绫诲瀷杞崲鍑芥暟 */
+const convertParamValue = (value, dataType) => {
+ if (value === '') return null // 绌哄�煎鐞�
+
+ switch (dataType) {
+ case 'String':
+ return String(value)
+ case 'Number':
+ const num = Number(value)
+ if (isNaN(num)) throw new Error('闈炴暟瀛楁牸寮�')
+ return num
+ case 'Boolean':
+ if (value.toLowerCase() === 'true') return true
+ if (value.toLowerCase() === 'false') return false
+ throw new Error('蹇呴』涓� true/false')
+ case 'Object':
+ case 'Array':
+ try {
+ return JSON.parse(value)
+ } catch (e) {
+ throw new Error(`JSON鏍煎紡閿欒: ${e.message}`)
+ }
+ default:
+ throw new Error(`涓嶆敮鎸佺殑绫诲瀷: ${dataType}`)
+ }
+}
+
+/** 琛ㄥ崟鏍¢獙 */
+const validate = async () => {
+ try {
+ // 鑾峰彇鏈�鏂扮殑娴佺▼鏁版嵁
+ if (!workflowData.value) {
+ throw new Error('璇疯璁℃祦绋�')
+ }
+ workflowData.value = tinyflowRef.value.getData()
+ return true
+ } catch (error) {
+ throw error
+ }
+}
+defineExpose({
+ validate
+})
+</script>
+
+<style lang="css" scoped>
+.result-content {
+ background: white;
+ padding: 12px;
+ border-radius: 4px;
+ max-height: 300px;
+ overflow: auto;
+ font-family: Monaco, Consolas, monospace;
+ font-size: 14px;
+ line-height: 1.5;
+ white-space: pre-wrap;
+}
+</style>
--
Gitblit v1.8.0