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/index.vue |  240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 240 insertions(+), 0 deletions(-)

diff --git a/src/views/ai/workflow/form/index.vue b/src/views/ai/workflow/form/index.vue
new file mode 100644
index 0000000..dddb7a5
--- /dev/null
+++ b/src/views/ai/workflow/form/index.vue
@@ -0,0 +1,240 @@
+<template>
+  <ContentWrap>
+    <div class="mx-auto">
+      <!-- 澶撮儴瀵艰埅鏍� -->
+      <div
+        class="absolute top-0 left-0 right-0 h-50px bg-white border-bottom z-10 flex items-center px-20px"
+      >
+        <!-- 宸︿晶鏍囬 -->
+        <div class="w-200px flex items-center overflow-hidden">
+          <Icon icon="ep:arrow-left" class="cursor-pointer flex-shrink-0" @click="handleBack" />
+          <span class="ml-10px text-16px truncate" :title="formData.name || '鍒涘缓娴佺▼'">
+            {{ formData.name || '鍒涘缓娴佺▼' }}
+          </span>
+        </div>
+
+        <!-- 姝ラ鏉� -->
+        <div class="flex-1 flex items-center justify-center h-full">
+          <div class="w-400px flex items-center justify-between h-full">
+            <div
+              v-for="(step, index) in steps"
+              :key="index"
+              class="flex items-center cursor-pointer mx-15px relative h-full"
+              :class="[
+                currentStep === index
+                  ? 'text-[#3473ff] border-[#3473ff] border-b-2 border-b-solid'
+                  : 'text-gray-500'
+              ]"
+              @click="handleStepClick(index)"
+            >
+              <div
+                class="w-28px h-28px rounded-full flex items-center justify-center mr-8px border-2 border-solid text-15px"
+                :class="[
+                  currentStep === index
+                    ? 'bg-[#3473ff] text-white border-[#3473ff]'
+                    : 'border-gray-300 bg-white text-gray-500'
+                ]"
+              >
+                {{ index + 1 }}
+              </div>
+              <span class="text-16px font-bold whitespace-nowrap">{{ step.title }}</span>
+            </div>
+          </div>
+        </div>
+
+        <!-- 鍙充晶鎸夐挳 -->
+        <div class="w-200px flex items-center justify-end gap-2">
+          <el-button type="primary" @click="handleSave"> 淇� 瀛� </el-button>
+        </div>
+      </div>
+
+      <!-- 涓讳綋鍐呭 -->
+      <div class="mt-50px">
+        <!-- 绗竴姝ワ細鍩烘湰淇℃伅 -->
+        <div v-if="currentStep === 0" class="mx-auto w-560px">
+          <BasicInfo v-model="formData" ref="basicInfoRef" />
+        </div>
+
+        <!-- 绗簩姝ワ細宸ヤ綔娴佽璁� -->
+        <WorkflowDesign
+          v-if="currentStep === 1"
+          v-model="formData"
+          :provider="llmProvider"
+          ref="workflowDesignRef"
+        />
+      </div>
+    </div>
+  </ContentWrap>
+</template>
+
+<script setup lang="ts">
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import { CommonStatusEnum } from '@/utils/constants'
+import * as WorkflowApi from '@/api/ai/workflow'
+import BasicInfo from './BasicInfo.vue'
+import WorkflowDesign from './WorkflowDesign.vue'
+import { ModelApi } from '@/api/ai/model/model'
+import { AiModelTypeEnum } from '@/views/ai/utils/constants'
+
+const router = useRouter()
+const { delView } = useTagsViewStore()
+const route = useRoute()
+const message = useMessage()
+
+const basicInfoRef = ref()
+const workflowDesignRef = ref()
+
+const validateBasic = async () => {
+  await basicInfoRef.value?.validate()
+}
+const validateWorkflow = async () => {
+  await workflowDesignRef.value?.validate()
+}
+
+const currentStep = ref(-1)
+const steps = [
+  { title: '鍩烘湰淇℃伅', validator: validateBasic },
+  { title: '宸ヤ綔娴佽璁�', validator: validateWorkflow }
+]
+
+const formData: any = ref({
+  id: undefined,
+  name: '',
+  code: '',
+  remark: '',
+  graph: '',
+  status: CommonStatusEnum.ENABLE
+})
+const llmProvider = ref<any>([])
+const workflowData = ref<any>({})
+provide('workflowData', workflowData)
+
+/** 鍒濆鍖栨暟鎹� */
+const actionType = route.params.type as string
+const initData = async () => {
+  // 缂栬緫鎯呭喌涓嬶紝闇�瑕佸姞杞藉伐浣滄祦閰嶇疆
+  if (actionType === 'update') {
+    const workflowId = route.params.id as string
+    formData.value = await WorkflowApi.getWorkflow(workflowId)
+    workflowData.value = JSON.parse(formData.value.graph)
+  }
+
+  // 鍔犺浇妯″瀷鍒楄〃
+  const models = await ModelApi.getModelSimpleList(AiModelTypeEnum.CHAT)
+  llmProvider.value = {
+    llm: () =>
+      models.map(({ id, name }) => ({
+        value: id,
+        label: name
+      })),
+    knowledge: () => [],
+    internal: () => []
+  }
+  // TODO @lesan锛氱煡璇嗗簱锛堝彲浠ョ湅涓� knowledge锛�
+  // TODO @lesan锛氭悳绱㈠紩鎿庯紙杩欎釜涔嬪墠鏈変釜 pr 鎼炰簡锛岋紝锛屽彲鑳芥潵鎺ヤ笅锛�
+
+  // 璁剧疆褰撳墠姝ラ
+  currentStep.value = 0
+}
+
+/** 鏍¢獙鎵�鏈夋楠ゆ暟鎹槸鍚﹀畬鏁� */
+const validateAllSteps = async () => {
+  try {
+    // 鍩烘湰淇℃伅鏍¢獙
+    try {
+      await validateBasic()
+    } catch (error) {
+      currentStep.value = 0
+      throw new Error('璇峰畬鍠勫熀鏈俊鎭�')
+    }
+
+    // 宸ヤ綔娴佽璁℃牎楠�
+    try {
+      await validateWorkflow()
+    } catch (error) {
+      currentStep.value = 1
+      throw new Error('璇峰畬鍠勫伐浣滄祦淇℃伅')
+    }
+    return true
+  } catch (error) {
+    throw error
+  }
+}
+
+/** 淇濆瓨鎿嶄綔 */
+const handleSave = async () => {
+  try {
+    // 淇濆瓨鍓嶆牎楠屾墍鏈夋楠ょ殑鏁版嵁
+    await validateAllSteps()
+
+    // 鏇存柊琛ㄥ崟鏁版嵁
+    const data = {
+      ...formData.value,
+      graph: JSON.stringify(workflowData.value)
+    }
+    if (actionType === 'update') {
+      await WorkflowApi.updateWorkflow(data)
+    } else {
+      await WorkflowApi.createWorkflow(data)
+    }
+
+    // 淇濆瓨鎴愬姛锛屾彁绀哄苟璺宠浆鍒板垪琛ㄩ〉
+    message.success('淇濆瓨鎴愬姛')
+    delView(unref(router.currentRoute))
+    await router.push({ name: 'AiWorkflow' })
+  } catch (error: any) {
+    console.error('淇濆瓨澶辫触:', error)
+    message.warning(error.message || '璇峰畬鍠勬墍鏈夋楠ょ殑蹇呭~淇℃伅')
+  }
+}
+
+/** 姝ラ鍒囨崲澶勭悊 */
+const handleStepClick = async (index: number) => {
+  try {
+    if (index !== 0) {
+      await validateBasic()
+    }
+    if (index !== 1) {
+      await validateWorkflow()
+    }
+
+    // 鍒囨崲姝ラ
+    currentStep.value = index
+  } catch (error) {
+    console.error('姝ラ鍒囨崲澶辫触:', error)
+    message.warning('璇峰厛瀹屽杽褰撳墠姝ラ蹇呭~淇℃伅')
+  }
+}
+
+/** 杩斿洖鍒楄〃椤� */
+const handleBack = () => {
+  // 鍏堝垹闄ゅ綋鍓嶉〉绛�
+  delView(unref(router.currentRoute))
+  // 璺宠浆鍒板垪琛ㄩ〉
+  router.push({ name: 'AiWorkflow' })
+}
+
+/** 鍒濆鍖� */
+onMounted(async () => {
+  await initData()
+})
+</script>
+
+<!-- TODO @lesan锛氬彲浠ョ敤 cursor 鎼炴垚 unocss 鍝� -->
+<style lang="scss" scoped>
+.border-bottom {
+  border-bottom: 1px solid #dcdfe6;
+}
+
+.text-primary {
+  color: #3473ff;
+}
+
+.bg-primary {
+  background-color: #3473ff;
+}
+
+.border-primary {
+  border-color: #3473ff;
+}
+</style>

--
Gitblit v1.8.0