<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="provider"
|
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 { ApiKeyApi } from '@/api/ai/model/apiKey'
|
|
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
|
})
|
// TODO @lesan:待接入
|
const provider = 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 apiKeys = await ApiKeyApi.getApiKeySimpleList()
|
provider.value = {
|
llm: () =>
|
apiKeys.map(({ id, name }) => ({
|
value: id,
|
label: name
|
})),
|
knowledge: () => [],
|
internal: () => []
|
}
|
|
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
|
}
|
|
data.graph = JSON.stringify(workflowData.value)
|
|
if (actionType === 'update') {
|
await WorkflowApi.updateWorkflow(data)
|
} else {
|
await WorkflowApi.createWorkflow(data)
|
}
|
|
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>
|