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