feat: 优化工作流字段化参数配置
- 开始节点固定 user_input 并区分系统入口与自定义参数 - LLM 与知识库节点切换为字段值加上游引用配置 - 单节点调试改为字段预览与上游引用输入模式
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormInstance } from 'element-plus';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { Position } from '@element-plus/icons-vue';
|
||||
import { ElButton, ElForm, ElFormItem, ElMessage } from 'element-plus';
|
||||
import { ElAlert, ElButton, ElForm, ElFormItem, ElMessage } from 'element-plus';
|
||||
|
||||
import { api } from '#/api/request';
|
||||
import ShowJson from '#/components/json/ShowJson.vue';
|
||||
import { $t } from '#/locales';
|
||||
import WorkflowFormItem from '#/views/ai/workflow/components/WorkflowFormItem.vue';
|
||||
import { buildSingleRunModel } from '../../../../../../packages/tinyflow-ui/src/utils/workflowNodeFields';
|
||||
|
||||
interface Props {
|
||||
workflowId: any;
|
||||
@@ -22,6 +23,52 @@ const singleRunForm = ref<FormInstance>();
|
||||
const runParams = ref<any>({});
|
||||
const submitLoading = ref(false);
|
||||
const result = ref<any>('');
|
||||
const singleRunModel = computed(() => buildSingleRunModel(props.node));
|
||||
const isFieldMode = computed(() => singleRunModel.value.mode === 'fields');
|
||||
const singleRunParameters = computed(() => singleRunModel.value.parameters);
|
||||
const singleRunFields = computed(() => singleRunModel.value.fields);
|
||||
const parameterDisplayNameMap = computed(() => {
|
||||
return new Map(
|
||||
singleRunParameters.value.map((parameter: any) => [
|
||||
String(parameter.name || ''),
|
||||
String(parameter.displayName || parameter.formLabel || parameter.name || ''),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
function buildFieldSegments(value: string) {
|
||||
const source = String(value || '');
|
||||
const segments: Array<{ text: string; token: boolean }> = [];
|
||||
const regex = /\{\{\s*([^{}]+?)\s*}}/g;
|
||||
let lastIndex = 0;
|
||||
|
||||
for (const match of source.matchAll(regex)) {
|
||||
const matchedText = match[0] || '';
|
||||
const tokenKey = String(match[1] || '').trim();
|
||||
const start = match.index ?? 0;
|
||||
if (start > lastIndex) {
|
||||
segments.push({
|
||||
text: source.slice(lastIndex, start),
|
||||
token: false,
|
||||
});
|
||||
}
|
||||
segments.push({
|
||||
text: parameterDisplayNameMap.value.get(tokenKey) || tokenKey,
|
||||
token: true,
|
||||
});
|
||||
lastIndex = start + matchedText.length;
|
||||
}
|
||||
|
||||
if (lastIndex < source.length) {
|
||||
segments.push({
|
||||
text: source.slice(lastIndex),
|
||||
token: false,
|
||||
});
|
||||
}
|
||||
|
||||
return segments.length > 0 ? segments : [{ text: '', token: false }];
|
||||
}
|
||||
|
||||
function submit() {
|
||||
singleRunForm.value?.validate((valid) => {
|
||||
if (valid) {
|
||||
@@ -48,9 +95,75 @@ function submit() {
|
||||
<template>
|
||||
<div>
|
||||
<ElForm label-position="top" ref="singleRunForm" :model="runParams">
|
||||
<template v-if="isFieldMode">
|
||||
<div class="single-run-section">
|
||||
<div class="single-run-section__title">字段值</div>
|
||||
<ElAlert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="当前节点字段按正式配置展示;下方只需填写这些字段引用到的上游值。"
|
||||
/>
|
||||
<div class="single-run-field-list">
|
||||
<div
|
||||
v-for="field in singleRunFields"
|
||||
:key="field.key"
|
||||
class="single-run-field-card"
|
||||
>
|
||||
<div class="single-run-field-card__label">
|
||||
{{ field.label }}
|
||||
</div>
|
||||
<div
|
||||
class="single-run-field-card__value"
|
||||
:class="{ 'is-multiline': field.multiline }"
|
||||
>
|
||||
<template v-if="field.value">
|
||||
<template
|
||||
v-for="(segment, index) in buildFieldSegments(field.value)"
|
||||
:key="`${field.key}-${index}`"
|
||||
>
|
||||
<span
|
||||
v-if="segment.token"
|
||||
class="single-run-token-chip"
|
||||
>
|
||||
{{ segment.text }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="single-run-field-card__text"
|
||||
>
|
||||
{{ segment.text }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
<span v-else class="single-run-field-card__placeholder">
|
||||
{{ field.placeholder || '未设置' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="single-run-section">
|
||||
<div class="single-run-section__title">上游引用</div>
|
||||
<ElAlert
|
||||
v-if="singleRunParameters.length === 0"
|
||||
type="success"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="当前字段没有引用上游参数,可直接运行。"
|
||||
/>
|
||||
<WorkflowFormItem
|
||||
v-else
|
||||
v-model:run-params="runParams"
|
||||
:parameters="singleRunParameters"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<WorkflowFormItem
|
||||
v-else
|
||||
v-model:run-params="runParams"
|
||||
:parameters="node?.data.parameters || []"
|
||||
:parameters="singleRunParameters"
|
||||
/>
|
||||
<ElFormItem>
|
||||
<ElButton
|
||||
@@ -68,4 +181,71 @@ function submit() {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.single-run-section + .single-run-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.single-run-section__title {
|
||||
margin-bottom: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.single-run-field-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.single-run-field-card {
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
background: var(--el-fill-color-blank);
|
||||
}
|
||||
|
||||
.single-run-field-card__label {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.single-run-field-card__value {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-height: 20px;
|
||||
line-height: 1.7;
|
||||
color: var(--el-text-color-primary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.single-run-field-card__value.is-multiline {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.single-run-field-card__text {
|
||||
white-space: inherit;
|
||||
}
|
||||
|
||||
.single-run-field-card__placeholder {
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
|
||||
.single-run-token-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
padding: 1px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--el-color-primary-light-5);
|
||||
background: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user