|
@@ -1,295 +0,0 @@
|
|
|
-<!--
|
|
|
|
|
- * @Author: liuJie
|
|
|
|
|
- * @Date: 2026-01-25 16:56:55
|
|
|
|
|
- * @LastEditors: liuJie
|
|
|
|
|
- * @LastEditTime: 2026-01-25 19:10:12
|
|
|
|
|
- * @Describe: 代码执行节点
|
|
|
|
|
--->
|
|
|
|
|
-<script setup lang="ts">
|
|
|
|
|
-import { Position } from '@vue-flow/core'
|
|
|
|
|
-import CanvasHandle from '../handles/CanvasHandle.vue'
|
|
|
|
|
-import { Icon } from '@repo/ui'
|
|
|
|
|
-import { computed } from 'vue'
|
|
|
|
|
-
|
|
|
|
|
-interface CodeConfig {
|
|
|
|
|
- language: 'javascript' | 'python' | 'groovy' | 'java'
|
|
|
|
|
- content: string
|
|
|
|
|
- inputVars?: string[]
|
|
|
|
|
- outputVar?: string
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-interface Environment {
|
|
|
|
|
- timeout?: number
|
|
|
|
|
- memory?: number
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-interface Props {
|
|
|
|
|
- data: {
|
|
|
|
|
- label?: string
|
|
|
|
|
- description?: string
|
|
|
|
|
- code?: CodeConfig
|
|
|
|
|
- environment?: Environment
|
|
|
|
|
- [key: string]: any
|
|
|
|
|
- }
|
|
|
|
|
- selected?: boolean
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
- selected: false
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-// 语言图标映射
|
|
|
|
|
-const languageIcons: Record<string, string> = {
|
|
|
|
|
- javascript: 'lucide:file-code',
|
|
|
|
|
- python: 'lucide:file-code-2',
|
|
|
|
|
- groovy: 'lucide:coffee',
|
|
|
|
|
- java: 'lucide:coffee'
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 语言颜色映射
|
|
|
|
|
-const languageColors: Record<string, { bg: string; text: string; badge: string }> = {
|
|
|
|
|
- javascript: { bg: '#fef3c7', text: '#f59e0b', badge: '#fbbf24' },
|
|
|
|
|
- python: { bg: '#dbeafe', text: '#3b82f6', badge: '#60a5fa' },
|
|
|
|
|
- groovy: { bg: '#e0e7ff', text: '#6366f1', badge: '#818cf8' },
|
|
|
|
|
- java: { bg: '#fecaca', text: '#dc2626', badge: '#f87171' }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const language = computed(() => props.data.code?.language || 'javascript')
|
|
|
|
|
-const languageIcon = computed(() => languageIcons[language.value] || 'lucide:file-code')
|
|
|
|
|
-const languageColor = computed(() => languageColors[language.value] || languageColors.javascript)
|
|
|
|
|
-
|
|
|
|
|
-// 获取代码预览(前3行)
|
|
|
|
|
-const codePreview = computed(() => {
|
|
|
|
|
- const code = props.data.code?.content || '// 编写代码'
|
|
|
|
|
- const lines = code.split('\n').slice(0, 3)
|
|
|
|
|
- return lines.join('\n')
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-console.log(props.data)
|
|
|
|
|
-// 代码行数
|
|
|
|
|
-const codeLines = computed(() => {
|
|
|
|
|
- const code = props.data.code?.content || ''
|
|
|
|
|
- return code.split('\n').length
|
|
|
|
|
-})
|
|
|
|
|
-</script>
|
|
|
|
|
-
|
|
|
|
|
-<template>
|
|
|
|
|
- <div
|
|
|
|
|
- class="relative min-w-[280px] transition-all duration-300 ease-out hover:-translate-y-0.5"
|
|
|
|
|
- :class="{ 'scale-105': selected }"
|
|
|
|
|
- >
|
|
|
|
|
- <!-- 节点主体 -->
|
|
|
|
|
- <div
|
|
|
|
|
- class="bg-gradient-to-br from-white to-purple-50 border-2 rounded-xl shadow-md transition-all duration-300 relative overflow-hidden"
|
|
|
|
|
- :class="
|
|
|
|
|
- selected
|
|
|
|
|
- ? 'border-purple-500 shadow-purple-200 shadow-lg'
|
|
|
|
|
- : 'border-purple-300 hover:shadow-lg hover:shadow-purple-100'
|
|
|
|
|
- "
|
|
|
|
|
- >
|
|
|
|
|
- <!-- 左侧装饰条 -->
|
|
|
|
|
- <div
|
|
|
|
|
- class="absolute left-0 top-0 bottom-0 w-1 bg-gradient-to-b from-purple-500 to-purple-400 rounded-l-xl"
|
|
|
|
|
- ></div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 头部 -->
|
|
|
|
|
- <div class="flex items-center gap-3 px-4 py-3 border-b border-purple-100">
|
|
|
|
|
- <!-- 图标 -->
|
|
|
|
|
- <div
|
|
|
|
|
- class="relative flex-shrink-0 flex items-center justify-center w-10 h-10 bg-gradient-to-br from-purple-500 to-purple-400 rounded-lg shadow-md shadow-purple-200"
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- class="absolute inset-0 bg-gradient-to-br from-white/30 to-transparent rounded-lg"
|
|
|
|
|
- ></div>
|
|
|
|
|
- <Icon icon="lucide:code-2" color="#ffffff" class="relative z-10" :size="20" />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 标题 -->
|
|
|
|
|
- <div class="flex-1 min-w-0">
|
|
|
|
|
- <div class="text-sm font-semibold text-gray-800 truncate">
|
|
|
|
|
- {{ data.label || '代码执行' }}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="data.description" class="text-xs text-gray-500 mt-0.5 truncate">
|
|
|
|
|
- {{ data.description }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 语言标签 -->
|
|
|
|
|
- <div
|
|
|
|
|
- class="flex-shrink-0 px-2 py-1 rounded text-xs font-bold uppercase"
|
|
|
|
|
- :style="{
|
|
|
|
|
- backgroundColor: languageColor?.badge || '#fef3c7',
|
|
|
|
|
- color: 'white'
|
|
|
|
|
- }"
|
|
|
|
|
- >
|
|
|
|
|
- {{ language }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 代码信息 -->
|
|
|
|
|
- <div class="px-4 py-3 space-y-3">
|
|
|
|
|
- <!-- 代码预览 -->
|
|
|
|
|
- <div class="flex items-start gap-2">
|
|
|
|
|
- <Icon
|
|
|
|
|
- :icon="languageIcon"
|
|
|
|
|
- :color="languageColor?.text || '#6b7280'"
|
|
|
|
|
- :size="14"
|
|
|
|
|
- class="flex-shrink-0 mt-0.5"
|
|
|
|
|
- />
|
|
|
|
|
- <div class="flex-1 min-w-0">
|
|
|
|
|
- <div class="flex items-center justify-between mb-1">
|
|
|
|
|
- <span class="text-xs text-gray-500">代码片段</span>
|
|
|
|
|
- <span class="text-xs text-gray-400">{{ codeLines }} 行</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="relative">
|
|
|
|
|
- <pre
|
|
|
|
|
- class="text-xs font-mono bg-gray-900 text-gray-100 px-3 py-2 rounded border border-gray-700 overflow-hidden max-h-16"
|
|
|
|
|
- >{{ codePreview }}</pre
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- class="absolute bottom-0 left-0 right-0 h-6 bg-gradient-to-t from-gray-900 to-transparent pointer-events-none"
|
|
|
|
|
- ></div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 输入变量 -->
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="data.code?.inputVars && data.code.inputVars.length > 0"
|
|
|
|
|
- class="flex items-start gap-2"
|
|
|
|
|
- >
|
|
|
|
|
- <Icon icon="lucide:import" color="#94a3b8" :size="14" class="flex-shrink-0 mt-0.5" />
|
|
|
|
|
- <div class="flex-1 min-w-0">
|
|
|
|
|
- <div class="text-xs text-gray-500 mb-1">输入变量</div>
|
|
|
|
|
- <div class="flex flex-wrap gap-1">
|
|
|
|
|
- <span
|
|
|
|
|
- v-for="varName in data.code.inputVars"
|
|
|
|
|
- :key="varName"
|
|
|
|
|
- class="inline-flex items-center gap-1 px-2 py-0.5 bg-blue-50 text-blue-700 text-xs rounded border border-blue-200 font-mono"
|
|
|
|
|
- >
|
|
|
|
|
- <Icon icon="lucide:arrow-down-to-line" :size="10" />
|
|
|
|
|
- {{ varName }}
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 输出变量 -->
|
|
|
|
|
- <div v-if="data.code?.outputVar" class="flex items-start gap-2">
|
|
|
|
|
- <Icon icon="lucide:export" color="#94a3b8" :size="14" class="flex-shrink-0 mt-0.5" />
|
|
|
|
|
- <div class="flex-1 min-w-0">
|
|
|
|
|
- <div class="text-xs text-gray-500 mb-1">输出变量</div>
|
|
|
|
|
- <div
|
|
|
|
|
- class="inline-flex items-center gap-1 px-2 py-0.5 bg-green-50 text-green-700 text-xs rounded border border-green-200 font-mono"
|
|
|
|
|
- >
|
|
|
|
|
- <Icon icon="lucide:arrow-up-from-line" :size="10" />
|
|
|
|
|
- {{ data.code.outputVar }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 执行环境 -->
|
|
|
|
|
- <div
|
|
|
|
|
- v-if="data.environment?.timeout || data.environment?.memory"
|
|
|
|
|
- class="flex items-center gap-3 pt-2 border-t border-purple-100"
|
|
|
|
|
- >
|
|
|
|
|
- <div v-if="data.environment.timeout" class="flex items-center gap-1.5">
|
|
|
|
|
- <Icon icon="lucide:timer" color="#94a3b8" :size="12" />
|
|
|
|
|
- <span class="text-xs text-gray-600">
|
|
|
|
|
- <span class="text-gray-500">超时:</span>
|
|
|
|
|
- <span class="font-medium ml-1">{{ data.environment.timeout }}ms</span>
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div v-if="data.environment.memory" class="flex items-center gap-1.5">
|
|
|
|
|
- <Icon icon="lucide:memory-stick" color="#94a3b8" :size="12" />
|
|
|
|
|
- <span class="text-xs text-gray-600">
|
|
|
|
|
- <span class="text-gray-500">内存:</span>
|
|
|
|
|
- <span class="font-medium ml-1">{{ data.environment.memory }}MB</span>
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 底部状态栏 -->
|
|
|
|
|
- <div
|
|
|
|
|
- class="flex items-center justify-between px-4 py-2 bg-purple-50/50 border-t border-purple-100"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="flex items-center gap-2">
|
|
|
|
|
- <div class="flex items-center gap-1.5">
|
|
|
|
|
- <div class="w-1.5 h-1.5 bg-purple-500 rounded-full"></div>
|
|
|
|
|
- <span class="text-xs text-gray-500">就绪</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- 运行状态 -->
|
|
|
|
|
- <div class="flex items-center gap-1 px-1.5 py-0.5 bg-purple-100 rounded">
|
|
|
|
|
- <Icon icon="lucide:zap" color="#9333ea" :size="10" />
|
|
|
|
|
- <span class="text-xs text-purple-700 font-medium">待执行</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex items-center gap-1">
|
|
|
|
|
- <Icon
|
|
|
|
|
- icon="lucide:play-circle"
|
|
|
|
|
- color="#94a3b8"
|
|
|
|
|
- :size="14"
|
|
|
|
|
- class="cursor-pointer hover:text-purple-500 transition-colors"
|
|
|
|
|
- title="运行代码"
|
|
|
|
|
- />
|
|
|
|
|
- <Icon
|
|
|
|
|
- icon="lucide:file-edit"
|
|
|
|
|
- color="#94a3b8"
|
|
|
|
|
- :size="14"
|
|
|
|
|
- class="cursor-pointer hover:text-purple-500 transition-colors"
|
|
|
|
|
- title="编辑代码"
|
|
|
|
|
- />
|
|
|
|
|
- <Icon
|
|
|
|
|
- icon="lucide:settings"
|
|
|
|
|
- color="#94a3b8"
|
|
|
|
|
- :size="14"
|
|
|
|
|
- class="cursor-pointer hover:text-purple-500 transition-colors"
|
|
|
|
|
- title="配置"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 输入连接点 -->
|
|
|
|
|
- <CanvasHandle
|
|
|
|
|
- handle-id="code-node-input"
|
|
|
|
|
- type="target"
|
|
|
|
|
- :connections-count="1"
|
|
|
|
|
- :position="Position.Left"
|
|
|
|
|
- />
|
|
|
|
|
- <!-- 输出连接点 -->
|
|
|
|
|
- <CanvasHandle
|
|
|
|
|
- handle-id="code-node-output"
|
|
|
|
|
- type="source"
|
|
|
|
|
- :connections-count="1"
|
|
|
|
|
- :position="Position.Right"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<style scoped>
|
|
|
|
|
-pre {
|
|
|
|
|
- line-height: 1.4;
|
|
|
|
|
- white-space: pre-wrap;
|
|
|
|
|
- word-wrap: break-word;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.overflow-y-auto::-webkit-scrollbar {
|
|
|
|
|
- width: 4px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.overflow-y-auto::-webkit-scrollbar-track {
|
|
|
|
|
- background: #f3e8ff;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.overflow-y-auto::-webkit-scrollbar-thumb {
|
|
|
|
|
- background: #9333ea;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
- background: #7e22ce;
|
|
|
|
|
-}
|
|
|
|
|
-</style>
|
|
|