MaxKB/ui/src/components/ai-chat/component/knowledge-source-component/ExecutionDetailCard.vue
2025-12-05 19:15:09 +08:00

1270 lines
50 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-card class="mb-8" shadow="never" style="--el-card-padding: 12px 16px">
<div class="flex-between cursor" @click="data['show'] = !data['show']">
<div class="flex align-center">
<el-icon class="mr-8 arrow-icon" :class="data['show'] ? 'rotate-90' : ''">
<CaretRight />
</el-icon>
<component
:is="iconComponent(`${data.type}-icon`)"
class="mr-8"
:size="24"
:item="data.info"
/>
<h4>{{ data.name }}</h4>
</div>
<div class="flex align-center">
<span
class="mr-16 color-secondary"
v-if="
data.type === WorkflowType.Question ||
data.type === WorkflowType.AiChat ||
data.type === WorkflowType.ImageUnderstandNode ||
data.type === WorkflowType.ImageGenerateNode ||
data.type === WorkflowType.Application ||
data.type == WorkflowType.IntentNode ||
data.type === WorkflowType.VideoUnderstandNode
"
>{{ data?.message_tokens + data?.answer_tokens }} tokens</span
>
<span class="mr-16 color-secondary" v-if="data.status != 202"
>{{ data?.run_time?.toFixed(2) || 0.0 }} s</span
>
<el-icon class="color-success" :size="16" v-if="data.status === 200">
<CircleCheck />
</el-icon>
<el-icon class="is-loading" :size="16" v-else-if="data.status === 202">
<Loading />
</el-icon>
<el-icon class="color-danger" :size="16" v-else>
<CircleClose />
</el-icon>
</div>
</div>
<el-collapse-transition>
<div class="mt-12" v-if="data['show']">
<template v-if="data.status === 200 || data.type == WorkflowType.LoopNode">
<!-- 开始 -->
<template
v-if="data.type === WorkflowType.Start || data.type === WorkflowType.Application"
>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary"> {{ $t('chat.paragraphSource.question') }}:</span>
{{ data.question || '-' }}
</div>
<div v-for="(f, i) in data.global_fields" :key="i" class="mb-8">
<span class="color-secondary">{{ f.label }}:</span> {{ f.value }}
</div>
<div v-if="data.document_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('common.fileUpload.document') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.document_list" :key="i">
<el-card shadow="never" style="--el-card-padding: 8px" class="file cursor">
<div class="flex align-center">
<img :src="getImgUrl(f && f?.name)" alt="" width="24" />
<div class="ml-4 ellipsis" :title="f && f?.name">
{{ f && f?.name }}
</div>
</div>
</el-card>
</template>
</el-space>
</div>
<div v-if="data.image_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('common.fileUpload.image') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.image_list" :key="i">
<el-image
:src="f.url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</template>
</el-space>
</div>
<div v-if="data.audio_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('chat.executionDetails.audioFile') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.audio_list" :key="i">
<audio
:src="f.url"
controls
style="width: 300px; height: 43px"
class="border-r-6"
/>
</template>
</el-space>
</div>
<div v-if="data.video_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('common.fileUpload.image') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.video_list" :key="i">
<video
:src="f.url"
style="width: 170px; display: block"
controls
autoplay
class="border-r-6"
/>
</template>
</el-space>
</div>
<div v-if="data.other_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('common.fileUpload.document') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.other_list" :key="i">
<el-card shadow="never" style="--el-card-padding: 8px" class="file cursor">
<div class="flex align-center">
<img :src="getImgUrl(f && f?.name)" alt="" width="24" />
<div class="ml-4 ellipsis" :title="f && f?.name">
{{ f && f?.name }}
</div>
</div>
</el-card>
</template>
</el-space>
</div>
</div>
</div>
</template>
<!-- 知识库检索 -->
<template v-if="data.type == WorkflowType.SearchKnowledge">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.searchContent') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">{{ data.question || '-' }}</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.searchResult') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.paragraph_list?.length > 0">
<template
v-for="(paragraph, paragraphIndex) in arraySort(
data.paragraph_list,
'similarity',
true,
)"
:key="paragraphIndex"
>
<ParagraphCard
:data="paragraph"
:content="paragraph.content"
:index="paragraphIndex"
/>
</template>
</template>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 判断器 -->
<template v-if="data.type == WorkflowType.Condition">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.conditionResult') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.branch_name || '-' }}
</div>
</div>
</template>
<!-- AI 对话 / 问题优化 / 意图识别-->
<template
v-if="
data.type == WorkflowType.AiChat ||
data.type == WorkflowType.Question ||
data.type == WorkflowType.Application ||
data.type == WorkflowType.IntentNode
"
>
<div class="card-never border-r-6" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">{{ $t('chat.history') }}</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.history_message?.length > 0">
<p
class="mt-4 mb-4"
v-for="(history, historyIndex) in data.history_message"
:key="historyIndex"
>
<span class="color-secondary mr-4">{{ history.role }}:</span
><span>{{ history.content }}</span>
</p>
</template>
<template v-else> -</template>
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.question || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type == WorkflowType.AiChat">
<h5 class="p-8-12">
{{ $t('workflow.nodes.aiChatNode.think') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.reasoning_content || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 指定回复 -->
<template v-if="data.type === WorkflowType.Reply">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.replyContent') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-scrollbar height="150">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</el-scrollbar>
</div>
</div>
</template>
<!-- 文档内容提取 -->
<template v-if="data.type === WorkflowType.DocumentExtractNode">
<div class="card-never border-r-6">
<h5 class="p-8-12 flex align-center">
<span class="mr-4"> {{ $t('common.param.outputParam') }}</span>
<el-tooltip
effect="dark"
:content="$t('chat.executionDetails.paramOutputTooltip')"
placement="right"
>
<AppIcon iconName="app-warning" class="app-warning-icon"></AppIcon>
</el-tooltip>
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-scrollbar height="200">
<el-card
shadow="never"
style="--el-card-padding: 8px"
v-for="(file_content, index) in data.content"
:key="index"
class="mb-8"
>
<MdPreview
v-if="file_content"
ref="editorRef"
editorId="preview-only"
:modelValue="file_content"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</el-card>
</el-scrollbar>
</div>
</div>
</template>
<template v-if="data.type === WorkflowType.SpeechToTextNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<div v-if="data.audio_list?.length > 0">
<p class="mb-8 color-secondary">{{ $t('chat.executionDetails.audioFile') }}:</p>
<el-space wrap>
<template v-for="(f, i) in data.audio_list" :key="i">
<audio
:src="f.url"
controls
style="width: 300px; height: 43px"
class="border-r-6"
/>
</template>
</el-space>
</div>
</div>
</div>
</div>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-card
shadow="never"
style="--el-card-padding: 8px"
v-for="(file_content, index) in data.content"
:key="index"
class="mb-8"
>
<MdPreview
v-if="file_content"
ref="editorRef"
editorId="preview-only"
:modelValue="file_content"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</el-card>
</div>
</div>
</template>
<template v-if="data.type === WorkflowType.TextToSpeechNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="p-8-12 border-t-dashed lighter">
<p class="mb-8 color-secondary">{{ $t('chat.executionDetails.textContent') }}:</p>
<div v-if="data.content">
<MdPreview
ref="editorRef"
editorId="preview-only"
:modelValue="data.content"
style="background: none"
noImgZoomIn
/>
</div>
</div>
</div>
</div>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<p class="mb-8 color-secondary">{{ $t('chat.executionDetails.audioFile') }}:</p>
<div v-if="data.answer" v-html="data.answer"></div>
</div>
</div>
</template>
<!-- 工具库 -->
<template
v-if="data.type === WorkflowType.ToolLib || data.type === WorkflowType.ToolLibCustom"
>
<div class="card-never border-r-6 mt-8" v-if="data.index != 0">
<h5 class="p-8-12">{{ $t('chat.executionDetails.input') }}</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.params || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">{{ $t('chat.executionDetails.output') }}</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.result || '-' }}
</div>
</div>
</template>
<!-- 多路召回 -->
<template v-if="data.type == WorkflowType.RerankerNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.searchContent') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">{{ data.question || '-' }}</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.rerankerContent') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.document_list?.length > 0">
<template
v-for="(paragraph, paragraphIndex) in data.document_list"
:key="paragraphIndex"
>
<ParagraphCard
:data="paragraph.metadata"
:content="paragraph.page_content"
:index="paragraphIndex"
/>
</template>
</template>
<template v-else> -</template>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.rerankerResult') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.result_list?.length > 0">
<template
v-for="(paragraph, paragraphIndex) in data.result_list"
:key="paragraphIndex"
>
<ParagraphCard
:data="paragraph.metadata"
:content="paragraph.page_content"
:index="paragraphIndex"
:score="paragraph.metadata?.relevance_score"
/>
</template>
</template>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 表单收集 -->
<template v-if="data.type === WorkflowType.FormNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam')
}}<span style="color: #f54a45">{{
data.is_submit ? '' : `(${$t('chat.executionDetails.noSubmit')})`
}}</span>
</h5>
<div class="p-8-12 border-t-dashed lighter">
<DynamicsForm
:disabled="true"
label-position="top"
require-asterisk-position="right"
ref="dynamicsFormRef"
:render_data="data.form_field_list"
label-suffix=":"
v-model="data.form_data"
:model="data.form_data"
></DynamicsForm>
</div>
</div>
</template>
<!-- 图片理解 -->
<template v-if="data.type == WorkflowType.ImageUnderstandNode">
<div class="card-never border-r-6" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">{{ $t('chat.history') }}</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.history_message?.length > 0">
<p
class="mt-4 mb-4"
v-for="(history, historyIndex) in data.history_message"
:key="historyIndex"
>
<span class="color-secondary mr-4">{{ history.role }}:</span>
<span v-if="Array.isArray(history.content)">
<template v-for="(h, i) in history.content" :key="i">
<el-image
v-if="h.type === 'image_url'"
:src="h.image_url.url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: inline-block"
class="border-r-6 mr-8"
/>
<span v-else>{{ h.text }}<br /></span>
</template>
</span>
<span v-else>{{ history.content }}</span>
</p>
</template>
<template v-else> -</template>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
<div v-if="data.image_list?.length > 0">
<el-space wrap>
<template v-for="(f, i) in data.image_list" :key="i">
<el-image
:src="f.url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</template>
</el-space>
</div>
<div>
{{ data.question || '-' }}
</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 视频理解 -->
<template v-if="data.type == WorkflowType.VideoUnderstandNode">
<div class="card-never border-r-6" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">
{{ $t('views.application.form.roleSettings.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
{{ data.system || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8" v-if="data.type !== WorkflowType.Application">
<h5 class="p-8-12">{{ $t('chat.history') }}</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.history_message?.length > 0">
<p
class="mt-4 mb-4"
v-for="(history, historyIndex) in data.history_message"
:key="historyIndex"
>
<span class="color-secondary mr-4">{{ history.role }}:</span>
<span v-if="Array.isArray(history.content)">
<template v-for="(h, i) in history.content" :key="i">
<video
v-if="h.type === 'video_url'"
:src="h.video_url.url"
style="width: 40px; height: 40px; display: inline-block"
class="border-r-6 mr-8"
/>
<span v-else>{{ h.text }}<br /></span>
</template>
</span>
<span v-else>{{ history.content }}</span>
</p>
</template>
<template v-else> -</template>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
<div v-if="data.video_list?.length > 0">
<el-space wrap>
<template v-for="(f, i) in data.video_list" :key="i">
<video
:src="f.url"
style="width: 100px; display: block"
class="border-r-6"
autoplay
controls
/>
</template>
</el-space>
</div>
<div>
{{ data.question || '-' }}
</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 图片生成 -->
<template v-if="data.type == WorkflowType.ImageGenerateNode">
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.question || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('workflow.nodes.imageGenerateNode.negative_prompt.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.negative_prompt || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<template v-if="data.type == WorkflowType.TextToVideoGenerateNode">
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.question || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('workflow.nodes.imageGenerateNode.negative_prompt.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.negative_prompt || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<template v-if="data.type == WorkflowType.ImageToVideoGenerateNode">
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.currentChat') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.question || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('workflow.nodes.imageGenerateNode.negative_prompt.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.negative_prompt || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('workflow.nodes.imageToVideoGenerate.first_frame.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
<div v-if="typeof data.first_frame_url === 'string'">
<el-image
:src="data.first_frame_url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</div>
<div v-else-if="Array.isArray(data.first_frame_url)">
<el-space wrap>
<template v-for="(f, i) in data.first_frame_url" :key="i">
<el-image
:src="f.url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</template>
</el-space>
</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('workflow.nodes.imageToVideoGenerate.last_frame.label') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
<div v-if="typeof data.last_frame_url === 'string'">
<el-image
:src="data.last_frame_url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</div>
<div v-else-if="Array.isArray(data.last_frame_url)">
<el-space wrap>
<template v-for="(f, i) in data.last_frame_url" :key="i">
<el-image
:src="f.url"
alt=""
fit="cover"
style="width: 40px; height: 40px; display: block"
class="border-r-6"
/>
</template>
</el-space>
</div>
<div v-else>-</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{
data.type == WorkflowType.Application
? $t('common.param.outputParam')
: $t('chat.executionDetails.answer')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<MdPreview
v-if="data.answer"
ref="editorRef"
editorId="preview-only"
:modelValue="data.answer"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</div>
</div>
</template>
<!-- 变量赋值 -->
<template v-if="data.type === WorkflowType.VariableAssignNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in data.result_list" :key="i" class="mb-8">
<span class="color-secondary">{{ f.name }}:</span> {{ f.input_value }}
</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in data.result_list" :key="i" class="mb-8">
<span class="color-secondary">{{ f.name }}:</span> {{ f.output_value }}
</div>
</div>
</div>
</template>
<!-- 变量拆分 -->
<template
v-if="
data.type === WorkflowType.VariableSplittingNode ||
data.type == WorkflowType.ParameterExtractionNode
"
>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{ data.request || '-' }}
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in data.result" :key="i" class="mb-8">
<span class="color-secondary">{{ i }}:</span> {{ f }}
</div>
</div>
</div>
</template>
<!-- 变量聚合 -->
<template v-if="data.type === WorkflowType.VariableAggregationNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('workflow.nodes.variableAggregationNode.Strategy') }}
</h5>
<div class="p-8-12 border-t-dashed lighter pre-wrap">
{{
data.strategy === 'variable_to_json'
? t('workflow.nodes.variableAggregationNode.placeholder1')
: t('workflow.nodes.variableAggregationNode.placeholder')
}}
</div>
</div>
<div
class="card-never border-r-6 mt-8"
v-for="(group, groupI) in data.group_list"
:key="groupI"
>
<h5 class="p-8-12">
{{ group.label + ' ' + $t('common.param.inputParam') }}
</h5>
<el-scrollbar height="200">
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in group.variable_list" :key="i" class="mb-8">
<span class="color-secondary">{{ `${f.node_name}.${f.field}` }}:</span>
{{ f.value }}
</div>
</div>
</el-scrollbar>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<el-scrollbar height="200">
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in data.result" :key="i" class="mb-8">
<span class="color-secondary">{{ i }}:</span> {{ f }}
</div>
</div>
</el-scrollbar>
</div>
</template>
<!-- MCP 节点 -->
<template v-if="data.type === WorkflowType.McpNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('views.tool.title') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary"> {{ $t('views.tool.title') }}: </span>
{{ data.mcp_tool }}
</div>
</div>
</div>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('workflow.nodes.mcpNode.toolParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(value, name) in data.tool_params" :key="name" class="mb-8">
<span class="color-secondary">{{ name }}:</span> {{ value }}
</div>
</div>
</div>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div v-for="(f, i) in data.result" :key="i" class="mb-8">
<span class="color-secondary">result:</span> {{ f }}
</div>
</div>
</div>
</template>
<!-- 循环 节点 -->
<div class="card-never border-r-6" v-if="data.type === WorkflowType.LoopNode">
<h5 class="p-8-12">
{{ $t('workflow.nodes.loopNode.loopSetting') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary">
{{ $t('workflow.nodes.loopNode.loopType.label') }}:</span
>
{{ data.loop_type || '-' }}
</div>
<div>
<span class="color-secondary">
{{ $t('workflow.nodes.loopNode.loopArray.label') }}:</span
>
{{
data.loop_type === 'NUMBER'
? data.number
: Object.keys(data.loop_node_data) || '-'
}}
</div>
</div>
<h5 class="p-8-12">
{{ $t('workflow.nodes.loopNode.loopDetail') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<template v-if="data.type === WorkflowType.LoopNode">
<el-radio-group v-model="currentLoopNode" class="app-radio-button-group mb-8">
<template v-for="(loop, loopIndex) in data.loop_node_data" :key="loopIndex">
<el-radio-button :label="loopIndex" :value="loopIndex" />
</template>
</el-radio-group>
<template
v-for="(cLoop, cIndex) in Object.values(
data.loop_node_data?.[currentLoopNode] || [],
)"
:key="cIndex"
>
<ExecutionDetailCard :data="cLoop"></ExecutionDetailCard>
</template>
</template>
</div>
</div>
<!-- 循环开始 节点-->
<template v-if="data.type === WorkflowType.LoopStartNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary">
{{ $t('workflow.nodes.loopStartNode.loopItem') }}:</span
>
{{ data.current_item }}
</div>
<div class="mb-8">
<span class="color-secondary">
{{ $t('workflow.nodes.loopStartNode.loopIndex') }}:</span
>
{{ data.current_index }}
</div>
</div>
</div>
</template>
<!-- 循环跳过 节点-->
<template v-if="data.type === WorkflowType.LoopContinueNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary">
{{ $t('workflow.nodes.loopContinueNode.isContinue') }}:</span
>
{{ data.is_continue }}
</div>
</div>
</div>
</template>
<!-- 循环退出 节点-->
<template v-if="data.type === WorkflowType.LoopBreakNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary">
{{ $t('workflow.nodes.loopBreakNode.isBreak') }}:</span
>
{{ data.is_break }}
</div>
</div>
</div>
</template>
<!-- 文档检索 -->
<template v-if="data.type === WorkflowType.SearchDocument">
<div class="card-never border-r-6">
<h5 class="p-8-12 flex align-center">
<span class="mr-4"> {{ $t('common.param.outputParam') }}</span>
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary"> knowledge_list:</span>
{{ data.knowledge_items?.map((v: any) => v.name).join(',') }}
</div>
<div class="mb-8">
<span class="color-secondary"> document_list:</span>
{{ data.document_items?.map((v: any) => v.name).join(',') }}
</div>
</div>
</div>
</template>
<!-- 文本文件 -->
<template v-if="data.type === WorkflowType.DataSourceLocalNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
{{ data.file_list || '-' }}
</div>
</div>
</div>
</template>
<!-- 文档分段 -->
<template v-if="data.type === WorkflowType.DocumentSplitNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<div class="mb-8">
<span class="color-secondary"
>{{ $t('chat.executionDetails.paragraphRules') }}:</span
>
{{ data.split_strategy }}
</div>
<div class="mb-8">
<span class="color-secondary"
>{{ $t('workflow.nodes.documentSplitNode.chunk_length.label') }}:</span
>
{{ data.chunk_size }}
</div>
{{ data.size }}
<div class="mb-8">
<span class="color-secondary">{{ $t('common.inputContent') }}:</span>
{{ data.document_list?.map((v: any) => v.name).join(',') }}
</div>
</div>
</div>
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}{{
$t('chat.executionDetails.documentSplitTip')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-tabs v-model="currentParagraph" class="paragraph-tabs">
<template v-for="(item, index) in data.paragraph_list" :key="index">
<el-tab-pane :label="item.name" :name="index">
<template #label>
<div class="flex-center">
<span class="ml-4">{{ item?.name }}</span>
</div>
</template>
<template v-for="(paragraph, pId) in item?.paragraphs" :key="pId">
<ParagraphCard :data="paragraph" :content="paragraph.content" :index="pId">
<template #footer>
<span class="color-secondary">
{{ $t('common.character') }}{{ paragraph.content.length }}</span
>
</template>
</ParagraphCard>
</template>
</el-tab-pane>
</template>
</el-tabs>
</div>
</div>
</template>
<!-- 知识库写入 -->
<template v-if="data.type === WorkflowType.KnowledgeWriteNode">
<div class="card-never border-r-6 mt-8">
<h5 class="p-8-12">
{{ $t('chat.executionDetails.writeContent') }}{{
$t('chat.executionDetails.documentSplitTip')
}}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-tabs v-model="currentWriteContent" class="paragraph-tabs">
<template v-for="(item, index) in data.write_content" :key="index">
<el-tab-pane :label="item.name" :name="index">
<template #label>
<div class="flex-center">
<span class="ml-4">{{ item?.name }}</span>
</div>
</template>
<template v-for="(paragraph, pId) in item?.paragraphs" :key="pId">
<ParagraphCard :data="paragraph" :content="paragraph.content" :index="pId">
<template #footer>
<span class="color-secondary">
{{ $t('common.character') }}{{ paragraph.content.length }}</span
>
</template>
</ParagraphCard>
</template>
</el-tab-pane>
</template>
</el-tabs>
</div>
</div>
</template>
<!-- Web站点 -->
<template v-if="data.type === WorkflowType.DataSourceWebNode">
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.inputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<p class="mb-8 color-secondary">
{{ $t('views.document.form.selector.label') }}: {{ data.input_params.selector }}
</p>
<p class="mb-8 color-secondary">
{{ $t('views.document.form.source_url.label') }}:
{{ data.input_params.source_url }}
</p>
</div>
</div>
<div class="card-never border-r-6">
<h5 class="p-8-12">
{{ $t('common.param.outputParam') }}
</h5>
<div class="p-8-12 border-t-dashed lighter">
<el-scrollbar height="200">
<el-card
shadow="never"
style="--el-card-padding: 8px"
v-for="(file_content, index) in data.output_params"
:key="index"
class="mb-8"
>
<h4>{{ file_content.name }}</h4>
<MdPreview
v-if="file_content"
ref="editorRef"
editorId="preview-only"
:modelValue="file_content.content"
style="background: none"
noImgZoomIn
/>
<template v-else> -</template>
</el-card>
</el-scrollbar>
</div>
</div>
</template>
<slot></slot>
</template>
<template v-else>
<div class="card-never border-r-6">
<h5 class="p-8-12">{{ $t('chat.executionDetails.errMessage') }}</h5>
<div class="p-8-12 border-t-dashed lighter">{{ data.err_message || '-' }}</div>
</div>
</template>
</div>
</el-collapse-transition>
</el-card>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import ParagraphCard from '@/components/ai-chat/component/knowledge-source-component/ParagraphCard.vue'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import { iconComponent } from '@/workflow/icons/utils'
import { WorkflowType } from '@/enums/application'
import { getImgUrl } from '@/utils/common'
import { arraySort } from '@/utils/array'
import { t } from '@/locales'
const props = defineProps<{
data: any
}>()
const currentLoopNode = ref(0)
const currentParagraph = ref(0)
const currentWriteContent = ref(0)
</script>
<style lang="scss" scoped></style>