This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
<template>
<div>
<div class="output-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'CodeNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
color: #666;
margin-right: 4px;
}
.param-value {
color: #333;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<div>
<div class="output-params">
<div class="param-item">
<svg-icon :size="24" class="param-icon" name="local-db" />
<span class="param-value">{{ node.dbParams.dbName }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'DbNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
background-color: #fff;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<div>
<div class="output-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'EndNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
color: #666;
margin-right: 4px;
}
.param-value {
color: #333;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<div class="output-params"
v-if="node.method || node.httpParams.url">
<div class="param-item">
<span class="param-name">{{ node.httpParams.method }}</span>
<span class="param-value">{{ node.httpParams.url }}</span>
</div>
</div>
</template>
<script>
import common from './common.ts'
export default {
name: 'HttpNode',
mixins: [common]
}
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
overflow: hidden;
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
background-color: #fff;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<div>
<div class="output-params">
<div class="input-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
<div class="param-item">
<svg-icon :size="24" class="param-icon" name="local-llm" />
<span class="param-value">{{ node.llmParams.modelConfig.model }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'LlmNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<div>
<div class="output-params">
<div class="input-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
<div class="param-item">
<svg-icon :size="24" class="param-icon" name="local-mcp" />
<span class="param-value">{{ node.mcpParams.mcpName || node.mcpParams.mcpId }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'McpNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<div>
<div class="output-params">
<div class="input-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'NoticeNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
background-color: #fff;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,126 @@
<template>
<div class="question-node">
<!-- 输入参数展示 -->
<div class="input-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
<div class="param-item">
<svg-icon :size="24" class="param-icon" name="local-llm" />
<span class="param-value">{{ node.questionParams.modelConfig.model }}</span>
</div>
</div>
<!-- 分类列表展示 -->
<div class="node-info">
<div class="info-item">
<div class="categories-list">
<div v-for="(item, index) in node.questionParams.categories" :key="index" class="category-item">
<div class="category-header">
<span class="category-name">{{ `分类${item.name}` || `分类${index + 1}` }}</span>
<span class="category-index">{{ item.value }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'QuestionNode',
mixins: [common],
props: {
node: {
type: Object,
required: true,
},
},
};
</script>
<style lang="scss" scoped>
.question-node {
font-size: 12px;
}
.input-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
color: #666;
margin-right: 4px;
}
.node-info {
padding: 5px 10px;
box-sizing: border-box;
width: 100%;
.info-item {
width: 100%;
.categories-list {
width: 100%;
.category-item {
width: 100%;
padding: 4px 8px;
box-sizing: border-box;
background: #f8fafc;
margin-bottom: 8px;
border: 1px solid #e2e8f0;
border-radius: 4px;
.category-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
.category-name {
font-weight: 500;
color: #1e293b;
}
.category-index {
font-size: 11px;
color: #64748b;
background: #e2e8f0;
padding: 2px 6px;
border-radius: 10px;
}
}
.category-desc {
color: #64748b;
font-size: 11px;
padding: 2px 0;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<div>
<div class="output-params">
<div class="param-item">
<svg-icon :size="24" class="param-icon" name="local-db" />
<span class="param-value">{{ node.ragParams.datasetName }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'RagNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
background-color: #fff;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<div>
<div class="output-params">
<div v-for="(param, index) in node.outputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'StartNode',
mixins: [common],
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
color: #666;
margin-right: 4px;
}
.param-value {
color: #333;
font-weight: 500;
}
</style>

View File

@@ -0,0 +1,126 @@
<template>
<div class="switch-node">
<div class="output-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
<div class="node-info">
<div class="info-item">
<div class="cases-list">
<div v-for="(item, index) in node.switchParams.cases" :key="index" class="case-item">
<div class="case-header">
<span class="case-name">{{ item.name || `分支${index + 1}` }}</span>
<span class="case-index">{{ item.value }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'SwitchNode',
mixins: [common],
props: {
node: {
type: Object,
required: true,
},
},
};
</script>
<style lang="scss" scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
color: #666;
margin-right: 4px;
}
.param-value {
color: #333;
font-weight: 500;
}
.switch-node {
font-size: 12px;
}
.node-info {
padding: 5px 10px;
box-sizing: border-box;
width: 100%;
.info-item {
width: 100%;
.cases-list {
width: 100%;
.case-item {
width: 100%;
padding: 2px 8px;
box-sizing: border-box;
background: #f8fafc;
margin-bottom: 8px;
border: 1px solid #e2e8f0;
transition: all 0.2s ease;
.case-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
.case-name {
font-weight: 500;
color: #1e293b;
}
.case-index {
font-size: 11px;
color: #64748b;
background: #e2e8f0;
padding: 2px 6px;
border-radius: 10px;
}
}
.case-value {
color: #64748b;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 2px 0;
}
}
}
}
}
.empty-text {
color: #999;
font-style: italic;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<div>
<div class="output-params">
<div class="input-params">
<div v-for="(param, index) in inputParams" :key="index" class="param-item">
<svg-icon :size="24" class="param-icon" name="local-var" />
<span class="param-name">{{ param.name }}</span>
</div>
</div>
<!-- 显示文本内容预览 -->
<div v-if="node.textParams && node.textParams.content" class="text-preview">
<div class="text-content">
{{ getPreviewText(node.textParams.content) }}
</div>
</div>
</div>
</div>
</template>
<script>
import common from './common.ts';
export default {
name: 'TextNode',
mixins: [common],
methods: {
// 获取预览文本,限制长度
getPreviewText(content) {
if (!content) return '未设置文本内容';
const maxLength = 50;
return content.length > maxLength ? content.substring(0, maxLength) + '...' : content;
},
},
};
</script>
<style scoped>
/* 添加样式 */
.output-params {
padding: 8px 12px;
}
.param-item {
display: flex;
align-items: center;
margin-bottom: 4px;
padding: 3px 10px;
font-size: 13px;
color: #333;
border-radius: 4px;
font-size: 12px;
background-color: rgb(242, 244, 247);
}
.param-icon {
color: rgb(41 112 255);
font-weight: bold;
}
.param-name {
padding: 2px 5px;
background-color: #fff;
box-sizing: border-box;
margin-right: 4px;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
}
.param-value {
color: #666;
font-weight: 500;
}
.text-preview {
margin-top: 8px;
padding: 6px 8px;
background-color: #f8f9fa;
border-radius: 4px;
border-left: 3px solid #409eff;
}
.text-content {
font-size: 12px;
color: #666;
line-height: 1.4;
word-break: break-word;
}
</style>

View File

@@ -0,0 +1,18 @@
import { Node } from '../types/node';
import { PropType } from 'vue';
export default {
inject: ['parent'],
props: {
node: {
type: Object as PropType<Node>,
required: true
}
},
data() {
return {
inputParams: this.node.inputParams || [],
outputParams: this.node.outputParams || []
}
}
}

View File

@@ -0,0 +1,319 @@
import { Node } from '../types/node';
interface NodeType extends Partial<Node> {
type: string;
name: string;
canBeSource: boolean;
canBeTarget: boolean;
panel?: string;
switchParams?: {
code: string;
cases: Array<{
name: string;
value: number;
}>;
};
questionParams?: {
modelConfig: {
model: string;
max_tokens: number;
temperature: number;
top_p: number;
frequency_penalty: number;
presence_penalty: number;
stream: boolean;
};
categories: Array<{
name: string;
value: string;
}>;
};
codeParams?: {
code: string;
};
noticeParams?: {
message: string;
};
httpParams?: {
url: string;
method: string;
contentType: string;
bodyParams: any[];
paramsParams: any[];
headerParams: any[];
};
dbParams?: {
sql: string;
dbId: string;
dbName: string;
};
llmParams?: {
messages: Array<{
role: string;
content: string;
}>;
modelConfig: {
model: string;
isVision: string;
max_tokens: number;
temperature: number;
top_p: number;
frequency_penalty: number;
presence_penalty: number;
stream: boolean;
};
};
mcpParams?: {
mcpId: string;
mcpName: string;
prompt: string;
};
textParams?: {
content: string;
};
}
export const nodeTypes: NodeType[] = [
{
type: 'start',
name: '开始',
canBeSource: true,
canBeTarget: false,
panel: 'StartPanel',
},
{
type: 'switch',
name: '分支节点',
canBeSource: true,
canBeTarget: true,
switchParams: {
code: 'function main(args) {\n // 根据参数选择执行分支0 还是分支1\n return args.arg1 === "xxx" ? 0 : 1;\n}',
cases: [
{
name: '分支1',
value: 0,
},
{
name: '分支2',
value: 1,
}
],
},
outputParams: [
{
name: 'index',
type: 'String',
},
],
},
{
type: 'question',
name: '问题分类',
canBeSource: true,
canBeTarget: true,
questionParams: {
modelConfig: {
model: '',
max_tokens: 4096,
temperature: 0.7,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stream: true,
},
categories: [
{
name: '分类1',
value: '1',
},
{
name: '分类2',
value: '2',
},
],
},
outputParams: [
{
name: 'index',
type: 'String',
},
],
},
{
type: 'code',
name: '执行代码',
canBeSource: true,
canBeTarget: true,
codeParams: {
code: 'function main(args){\n return ""\n}',
},
outputParams: [
{
name: 'result',
type: 'String',
}
],
},
{
type: 'notice',
name: '消息通知',
canBeSource: true,
canBeTarget: true,
noticeParams: {
message: '',
},
outputParams: [
{
name: 'result',
type: 'Boolean',
},
],
},
{
type: 'http',
name: 'HTTP请求',
canBeSource: true,
canBeTarget: true,
httpParams: {
url: '',
method: '',
contentType: 'application/json',
bodyParams: [],
paramsParams: [],
headerParams: [],
},
outputParams: [
{
name: 'body',
type: 'Object',
},
{
name: 'status_code',
type: 'Number',
},
{
name: 'headers',
type: 'Object',
},
],
},
{
type: 'rag',
name: 'RAG知识库',
canBeSource: true,
canBeTarget: true,
ragParams: {
datasetId: 0,
datasetName: '',
prompt: '${arg1}',
onlyRecall: '1',
},
outputParams: [
{
name: 'result',
type: 'String',
},
{
name: 'ragSearched',
type: 'String',
},
],
},
{
type: 'db',
name: 'DB数据库',
canBeSource: true,
canBeTarget: true,
dbParams: {
sql: '',
dbId: '',
dbName: '',
},
outputParams: [
{
name: 'result',
type: 'String',
},
],
},
{
type: 'llm',
name: 'LLM大模型',
canBeSource: true,
canBeTarget: true,
llmParams: {
messages: [
{
role: 'user',
content: '你是一个问题总结助手。\n任务根据用户提问 ${arg1} 和系统答案 ${arg2},生成一个标准的问题答案。\n要求基于系统答案内容回答回答准确、简洁、有用。',
},
],
modelConfig: {
model: '',
isVision: '0',
max_tokens: 4096,
temperature: 0.7,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stream: true,
},
},
outputParams: [
{
name: 'content',
type: 'String',
},
],
},
{
type: 'mcp',
name: 'MCP服务',
canBeSource: true,
canBeTarget: true,
mcpParams: {
mcpId: '',
mcpName: '',
prompt: '${arg1}',
},
outputParams: [
{
name: 'result',
type: 'Object',
},
{
name: 'status',
type: 'String',
},
],
},
{
type: 'text',
name: '文本节点',
canBeSource: true,
canBeTarget: true,
textParams: {
content: '',
},
outputParams: [
{
name: 'result',
type: 'String',
},
],
},
{
type: 'end',
name: '结束',
canBeSource: false,
canBeTarget: true,
},
];
import { deepClone } from '/@/utils/other';
export const getNodeConfig = (type: string): NodeType => {
const nodeConfig = nodeTypes.find((node) => node.type === type) || nodeTypes[0];
// 深拷贝节点配置,避免多个节点共享同一个对象引用
return deepClone(nodeConfig) as NodeType;
};