Merge branch 'dev' of 192.168.0.100:smart_bench/cmvr-iot-ui into dev
This commit is contained in:
commit
6558135b8e
@ -17,6 +17,14 @@ export function flowExecute(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function flowAction(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/action',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function flowExecuteTrial(data) {
|
export function flowExecuteTrial(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/executeTrial',
|
url: '/flow/executeTrial',
|
||||||
|
|||||||
46
src/api/device/microphone.js
Normal file
46
src/api/device/microphone.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 开始录音
|
||||||
|
export function startMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/start',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停录音
|
||||||
|
export function pauseMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/pause',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复录音
|
||||||
|
export function resumeMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/resume',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止录音
|
||||||
|
export function stopMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/stop',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放音频
|
||||||
|
export function playSpeaker(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Speaker/play',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { createWebHistory, createRouter } from "vue-router";
|
import { createWebHistory, createRouter } from "vue-router";
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from "@/layout";
|
import Layout from "@/layout";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: 路由配置项
|
* Note: 路由配置项
|
||||||
@ -92,7 +93,14 @@ export const constantRoutes = [
|
|||||||
name: "灵巧手示教",
|
name: "灵巧手示教",
|
||||||
meta: { title: "灵巧手详情" },
|
meta: { title: "灵巧手详情" },
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},{
|
||||||
|
path: "microphone/:id",
|
||||||
|
component: () =>
|
||||||
|
import("@/views/device/register/components/Microphone/index.vue"),
|
||||||
|
name: "麦克风示教",
|
||||||
|
meta: { title: "麦克风详情" },
|
||||||
|
hidden: true,
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -127,6 +127,34 @@ export const formatTableData = (arr, data = {}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const addNewEdge = (nodeId) => {
|
export const addNewEdge = (nodeId) => {
|
||||||
|
const { edges } = lf.getGraphData();
|
||||||
|
const ttt = edges.slice(); // 浅拷贝(比 JSON 深拷贝高效 10x+)
|
||||||
|
|
||||||
|
const edgesToDelete = ttt.filter(_edge =>
|
||||||
|
_edge.sourceNodeId === nodeId || _edge.targetNodeId === nodeId
|
||||||
|
);
|
||||||
|
|
||||||
|
edgesToDelete.forEach(edge => lf.deleteEdge(edge.id));
|
||||||
|
|
||||||
|
if (window.addNewEdgeTimer) {
|
||||||
|
clearTimeout(window.addNewEdgeTimer); // 清理上一次未执行的定时器
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addNewEdgeTimer = setTimeout(() => {
|
||||||
|
edgesToDelete.forEach(item => {
|
||||||
|
lf.addEdge({
|
||||||
|
type: "bezier",
|
||||||
|
sourceNodeId: item.sourceNodeId,
|
||||||
|
targetNodeId: item.targetNodeId,
|
||||||
|
sourceAnchorId: item.sourceAnchorId,
|
||||||
|
targetAnchorId: item.targetAnchorId
|
||||||
|
});
|
||||||
|
})
|
||||||
|
delete window.addNewEdgeTimer;
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const newEdge = (nodeId) => {
|
||||||
const { edges } = lf.getGraphData();
|
const { edges } = lf.getGraphData();
|
||||||
const arr = JSON.parse(JSON.stringify(edges))
|
const arr = JSON.parse(JSON.stringify(edges))
|
||||||
arr.forEach(_edge => {
|
arr.forEach(_edge => {
|
||||||
@ -144,6 +172,22 @@ export const addNewEdge = (nodeId) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const initNodeZoom = (modelId, nodeZoom, className, init=false) => {
|
||||||
|
const nodes = document.getElementsByClassName(modelId)
|
||||||
|
if (nodes.length > 0) {
|
||||||
|
const node = nodes[0]
|
||||||
|
const parent = node.closest(className);
|
||||||
|
if (nodeZoom) {
|
||||||
|
parent.style.width = '680px'
|
||||||
|
} else {
|
||||||
|
parent.style.width = '380px'
|
||||||
|
}
|
||||||
|
if (!init) {
|
||||||
|
addNewEdge(modelId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const getInputNumber = (nodeId) => {
|
export const getInputNumber = (nodeId) => {
|
||||||
const data = lf.getGraphData();
|
const data = lf.getGraphData();
|
||||||
let flag = false
|
let flag = false
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
|
||||||
|
|
||||||
<TableSearch
|
<TableSearch
|
||||||
:queryParams="queryParams"
|
:queryParams="queryParams"
|
||||||
:showSearch="showSearch"
|
:showSearch="showSearch"
|
||||||
|
|||||||
225
src/views/device/register/components/Microphone/index.vue
Normal file
225
src/views/device/register/components/Microphone/index.vue
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
<template>
|
||||||
|
<div class="microphone-container">
|
||||||
|
<div class="title">远程麦克风</div>
|
||||||
|
<div class="audiosList" v-if="audiosList.length > 0">
|
||||||
|
<div class="speaker-container">
|
||||||
|
<div class="speaker-title">选择扬声器</div>
|
||||||
|
<el-select v-model="speaker" size="small">
|
||||||
|
<el-option
|
||||||
|
v-for="item in speakerOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item"
|
||||||
|
:value="item"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="audioItem" v-for="item in audiosList">
|
||||||
|
<div>{{ item }}</div>
|
||||||
|
<div>
|
||||||
|
<el-button
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="VideoPlay"
|
||||||
|
@click="handlePlay(item)"
|
||||||
|
></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-container">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击开始录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'end'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="startRecording"><Microphone /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击暂停录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'recording'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="pauseRecording"><VideoPause /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击恢复录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'pause'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="recoverRecording"><Mic /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击结束录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus !== 'end'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="stopRecording"><Mute /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { Microphone, VideoPause, Mute, Mic, VideoPlay } from "@element-plus/icons-vue";
|
||||||
|
import {
|
||||||
|
startMicrophoneApi,
|
||||||
|
pauseMicrophoneApi,
|
||||||
|
resumeMicrophoneApi,
|
||||||
|
stopMicrophoneApi,
|
||||||
|
playSpeaker
|
||||||
|
} from '@/api/device/microphone'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
|
||||||
|
const terminalId = route.query.terminalId
|
||||||
|
const deviceId = route.query.deviceId
|
||||||
|
|
||||||
|
const recordStatus = ref('end');
|
||||||
|
const isRecording = ref(false)
|
||||||
|
const list = []
|
||||||
|
const audiosList = ref([])
|
||||||
|
const speaker = ref('spk1')
|
||||||
|
const speakerOptions = ref(['spk1'])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始录音
|
||||||
|
*/
|
||||||
|
const startRecording = async () => {
|
||||||
|
const fileName = new Date().getTime() + '.wav'
|
||||||
|
isRecording.value = true
|
||||||
|
const res = await startMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId,
|
||||||
|
filePath: `/home/share/record/audios/${terminalId}_${deviceId}_${fileName}`
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'recording'
|
||||||
|
list.push(`${terminalId}_${deviceId}_${fileName}`)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停录音
|
||||||
|
*/
|
||||||
|
const pauseRecording = async () => {
|
||||||
|
const res = await pauseMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'pause'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复录音
|
||||||
|
*/
|
||||||
|
const recoverRecording = async () => {
|
||||||
|
const res = await resumeMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'recording'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束录音
|
||||||
|
*/
|
||||||
|
const stopRecording = async () => {
|
||||||
|
const res = await stopMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'end'
|
||||||
|
audiosList.value.unshift(list[list.length - 1])
|
||||||
|
}
|
||||||
|
isRecording.value = false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放录音
|
||||||
|
*/
|
||||||
|
const handlePlay = async (audioPath) => {
|
||||||
|
const res = await playSpeaker({
|
||||||
|
terminalId,
|
||||||
|
deviceId: speaker.value,
|
||||||
|
audioPath: `/home/share/record/audios/${audioPath}`
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success('播放成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.microphone-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 800px;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - 125px);
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
.audiosList {
|
||||||
|
margin: 20px;
|
||||||
|
max-height: 280px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.speaker-container {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.speaker-title {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.audioItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-top: 20px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -378,6 +378,10 @@ function handleControl(row) {
|
|||||||
const fullPath = `${row.deviceModel}/${row.id}`; // 构造路由路径
|
const fullPath = `${row.deviceModel}/${row.id}`; // 构造路由路径
|
||||||
router.push({
|
router.push({
|
||||||
path: fullPath,
|
path: fullPath,
|
||||||
|
query: {
|
||||||
|
terminalId: row.idDeDeviceTerminalConfig,
|
||||||
|
deviceId: row.deviceCode
|
||||||
|
}
|
||||||
}); // 使用路由跳转
|
}); // 使用路由跳转
|
||||||
// intoControlPage(`/${row.deviceModel}`, `${row.id}`)
|
// intoControlPage(`/${row.deviceModel}`, `${row.id}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,27 +2,71 @@
|
|||||||
<div class="title__container">
|
<div class="title__container">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<img :src="icon" alt="">
|
<img :src="icon" alt="" />
|
||||||
<div class="text__container">
|
<div class="text__container">
|
||||||
<div class="text__title" v-if="showTextTitle">
|
<div class="text__title" v-if="showTextTitle">
|
||||||
<span class="text">{{ nodeName }}</span>
|
<span class="text">{{ nodeName }}</span>
|
||||||
<el-icon class="editIcon" @click="showTextTitle = false"><EditPen /></el-icon>
|
<el-icon class="editIcon" @click="showTextTitle = false"
|
||||||
|
><EditPen
|
||||||
|
/></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="input_name_container" v-else>
|
<div class="input_name_container" v-else>
|
||||||
<el-input v-model="nodeName" />
|
<el-input v-model="nodeName" />
|
||||||
<el-button class="input_name_select" circle size="small" @click="confirmNodeName">
|
<el-button
|
||||||
|
class="input_name_select"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="confirmNodeName"
|
||||||
|
>
|
||||||
<el-icon><Select /></el-icon>
|
<el-icon><Select /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button class="input_name_closeBold" circle size="small" @click="cancelNodeName">
|
<el-button
|
||||||
|
class="input_name_closeBold"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="cancelNodeName"
|
||||||
|
>
|
||||||
<el-icon><CloseBold /></el-icon>
|
<el-icon><CloseBold /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-button circle size="small" @click="deleteNode">
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="执行"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button v-if="nodeType && nodeType !=='NONE'" circle @click="execute">
|
||||||
|
<el-icon>
|
||||||
|
<VideoPlay />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="zoomState ? '缩小' : '放大'"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button v-if="showZoom" circle @click="zoom">
|
||||||
|
<el-icon>
|
||||||
|
<ZoomOut v-if="zoomState" />
|
||||||
|
<ZoomIn v-else />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="删除"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button circle @click="deleteNode">
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subTitle">{{ props.nodeDesc }}</div>
|
<div class="subTitle">{{ props.nodeDesc }}</div>
|
||||||
@ -30,7 +74,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="js">
|
<script setup lang="js">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { EditPen, Select, CloseBold, Delete } from '@element-plus/icons-vue'
|
import { EditPen, Select, CloseBold, Delete, ZoomOut, ZoomIn, VideoPlay } from '@element-plus/icons-vue'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -57,9 +101,19 @@ const props = defineProps({
|
|||||||
nodeType: {
|
nodeType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
showZoom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
zoomState: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['zoom'])
|
||||||
|
|
||||||
const showTextTitle = ref(true)
|
const showTextTitle = ref(true)
|
||||||
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
||||||
|
|
||||||
@ -98,6 +152,19 @@ const deleteNode = () => {
|
|||||||
lf.deleteNode(props.nodeId);
|
lf.deleteNode(props.nodeId);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const zoom = () => {
|
||||||
|
emits('zoom', !props.zoomState)
|
||||||
|
}
|
||||||
|
|
||||||
|
const execute = () => {
|
||||||
|
const myEvent = new CustomEvent('singleNodeExecution', {
|
||||||
|
bubbles: false, // 是否冒泡(默认 false)
|
||||||
|
cancelable: false, // 是否可被 preventDefault() 取消(默认 false)
|
||||||
|
detail: { ...props.nodeProperties } // 自定义数据(任意类型,通过 event.detail 读取)
|
||||||
|
});
|
||||||
|
document.dispatchEvent(myEvent);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.title__container {
|
.title__container {
|
||||||
@ -158,6 +225,7 @@ const deleteNode = () => {
|
|||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
border: none;
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import planSvg from './icon/plan.svg'
|
|||||||
import awakenSvg from './icon/awaken.svg'
|
import awakenSvg from './icon/awaken.svg'
|
||||||
import dialogueSvg from './icon/dialogue.svg'
|
import dialogueSvg from './icon/dialogue.svg'
|
||||||
import audioSvg from './icon/audio.svg'
|
import audioSvg from './icon/audio.svg'
|
||||||
|
import touchSvg from './icon/touch.svg'
|
||||||
|
import expressionSvg from './icon/expression.svg'
|
||||||
|
|
||||||
import { v4 as randomUUID } from 'uuid'
|
import { v4 as randomUUID } from 'uuid'
|
||||||
|
|
||||||
@ -40,6 +42,11 @@ export const lfConfig = {
|
|||||||
// foldSize: 30, // 折叠后显示的图标尺寸
|
// foldSize: 30, // 折叠后显示的图标尺寸
|
||||||
// },
|
// },
|
||||||
edgeType: "bezier",
|
edgeType: "bezier",
|
||||||
|
zoomConfig: {
|
||||||
|
min: 0.05, // 最小缩放比例(支持更小值,如 0.01,但不建议过小)
|
||||||
|
max: 3, // 最大缩放比例(可自定义)
|
||||||
|
step: 0.1 // 每次滚轮缩放的步长(默认 0.1)
|
||||||
|
},
|
||||||
style: {
|
style: {
|
||||||
anchor: {
|
anchor: {
|
||||||
show: true, // 强制全局锚点显示
|
show: true, // 强制全局锚点显示
|
||||||
@ -73,11 +80,39 @@ export const registerCustomizeNode = (lf) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deviceOptions = () => {
|
const deviceOptions = () => {
|
||||||
return ['cam1', 'cam2', 'cam3', 'cam4']
|
return [{
|
||||||
|
value: 'cam1',
|
||||||
|
label: 'cam1'
|
||||||
|
}, {
|
||||||
|
value: 'cam2',
|
||||||
|
label: 'cam2'
|
||||||
|
}, {
|
||||||
|
value: 'cam3',
|
||||||
|
label: 'cam3'
|
||||||
|
}, {
|
||||||
|
value: 'cam4',
|
||||||
|
label: 'cam4'
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
const audioOptions = () => {
|
const audioOptions = () => {
|
||||||
return ['spk1']
|
return [{
|
||||||
|
value: 'spk1',
|
||||||
|
label: 'spk1'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
const expressOptions = () => {
|
||||||
|
return [{
|
||||||
|
value: 1,
|
||||||
|
label: '高兴'
|
||||||
|
}, {
|
||||||
|
value: 2,
|
||||||
|
label: '惊讶'
|
||||||
|
}, {
|
||||||
|
value: 3,
|
||||||
|
label: '疲惫'
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const collapseList = [
|
export const collapseList = [
|
||||||
@ -90,6 +125,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "在获取相机照片时,需要先启动相机",
|
desc: "在获取相机照片时,需要先启动相机",
|
||||||
action: 'CAMERA_START',
|
action: 'CAMERA_START',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -101,6 +137,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "获取相机拍摄的照片",
|
desc: "获取相机拍摄的照片",
|
||||||
action: 'CAMERA_GETRGBIMAGE',
|
action: 'CAMERA_GETRGBIMAGE',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -113,6 +150,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "获取相机照片后,关闭该相机",
|
desc: "获取相机照片后,关闭该相机",
|
||||||
action: 'CAMERA_STOP',
|
action: 'CAMERA_STOP',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -129,6 +167,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "开启摄像头,并开始录像",
|
desc: "开启摄像头,并开始录像",
|
||||||
action: 'CAMERA_RECORDING_START',
|
action: 'CAMERA_RECORDING_START',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -140,6 +179,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "停止录像,并关闭摄像头",
|
desc: "停止录像,并关闭摄像头",
|
||||||
action: 'CAMERA_RECORDING_STOP',
|
action: 'CAMERA_RECORDING_STOP',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -224,6 +264,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "用于启动麦克风的节点",
|
desc: "用于启动麦克风的节点",
|
||||||
action: 'MICROPHONE_START',
|
action: 'MICROPHONE_START',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -235,6 +276,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "用于停止麦克风的节点",
|
desc: "用于停止麦克风的节点",
|
||||||
action: 'MICROPHONE_START',
|
action: 'MICROPHONE_START',
|
||||||
|
nodeType: 'EDGE',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
{ name: "deviceId", type: "input", input: "", componentType: 'select', selectOptions: deviceOptions(), disabled: true }
|
||||||
],
|
],
|
||||||
@ -262,6 +304,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "用于获取触控坐标的节点",
|
desc: "用于获取触控坐标的节点",
|
||||||
action: 'TOUCH_COORDINATES',
|
action: 'TOUCH_COORDINATES',
|
||||||
|
nodeType: "LLM",
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: "targetFeature", type: "input", input: "运动模式", disabled: true },
|
{ name: "targetFeature", type: "input", input: "运动模式", disabled: true },
|
||||||
{ name: "manufacturer", type: "input", input: "xiaomi", disabled: true },
|
{ name: "manufacturer", type: "input", input: "xiaomi", disabled: true },
|
||||||
@ -275,6 +318,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "将指令文本(text)处理合成语音,输出语音路径(audioPath)",
|
desc: "将指令文本(text)处理合成语音,输出语音路径(audioPath)",
|
||||||
action: 'GENERATE_ADVANCED_AUDIO',
|
action: 'GENERATE_ADVANCED_AUDIO',
|
||||||
|
nodeType: "LLM",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [{ name: 'text', type: "input", input: "", disabled: true }],
|
nodeParams: [{ name: 'text', type: "input", input: "", disabled: true }],
|
||||||
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
||||||
@ -284,6 +328,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "意图识别,输出类型(type) 1: 语音交互 2: 触控交互 3: 闲聊 4: 知识问答",
|
desc: "意图识别,输出类型(type) 1: 语音交互 2: 触控交互 3: 闲聊 4: 知识问答",
|
||||||
action: 'INTENT_RECOGNITION',
|
action: 'INTENT_RECOGNITION',
|
||||||
|
nodeType: "LLM",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [{ name: 'text', type: "input", input: "", disabled: true }],
|
nodeParams: [{ name: 'text', type: "input", input: "", disabled: true }],
|
||||||
outputParams: [{ name: 'type', type: 'string', desc: '1:语音交互 2:触控交互 3: 闲聊 4:知识问答', disabled: true}]
|
outputParams: [{ name: 'type', type: 'string', desc: '1:语音交互 2:触控交互 3: 闲聊 4:知识问答', disabled: true}]
|
||||||
@ -312,6 +357,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "唤醒语料处理,输入唤醒语料(wakeCorpus),输出语音路径(audioPath)",
|
desc: "唤醒语料处理,输入唤醒语料(wakeCorpus),输出语音路径(audioPath)",
|
||||||
action: 'VI_CORPUS_WAKE',
|
action: 'VI_CORPUS_WAKE',
|
||||||
|
nodeType: "EDGE",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [{ name: 'wakeCorpus', type: "input", input: "", disabled: true }],
|
nodeParams: [{ name: 'wakeCorpus', type: "input", input: "", disabled: true }],
|
||||||
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
||||||
@ -322,6 +368,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "测试语料-单次对话语料处理,输入单次对话语料(testCorpus),输出语音路径(audioPath)",
|
desc: "测试语料-单次对话语料处理,输入单次对话语料(testCorpus),输出语音路径(audioPath)",
|
||||||
action: 'VI_CORPUS_SINGLE',
|
action: 'VI_CORPUS_SINGLE',
|
||||||
|
nodeType: "EDGE",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [{ name: 'testCorpus', type: "input", input: "", disabled: true }],
|
nodeParams: [{ name: 'testCorpus', type: "input", input: "", disabled: true }],
|
||||||
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
||||||
@ -332,6 +379,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "测试语料-连续对话语料处理,输入连续对话语料(testCorpus),输出语音路径(audioPath)",
|
desc: "测试语料-连续对话语料处理,输入连续对话语料(testCorpus),输出语音路径(audioPath)",
|
||||||
action: 'VI_CORPUS_CONTINUOUS',
|
action: 'VI_CORPUS_CONTINUOUS',
|
||||||
|
nodeType: "EDGE",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [{ name: 'testCorpus', type: "input", input: "", disabled: true }],
|
nodeParams: [{ name: 'testCorpus', type: "input", input: "", disabled: true }],
|
||||||
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
outputParams: [{ name: 'audioPath', type: 'string', desc: '语音路径', disabled: true}]
|
||||||
@ -342,6 +390,7 @@ export const collapseList = [
|
|||||||
type: "serviceNode",
|
type: "serviceNode",
|
||||||
desc: "用于播放语料的节点,需要输入语音路径(audioPath)和播放语音的设备id(deviceId)",
|
desc: "用于播放语料的节点,需要输入语音路径(audioPath)和播放语音的设备id(deviceId)",
|
||||||
action: 'VI_PLAY_CORPUS',
|
action: 'VI_PLAY_CORPUS',
|
||||||
|
nodeType: "EDGE",
|
||||||
outputType: 'json',
|
outputType: 'json',
|
||||||
nodeParams: [
|
nodeParams: [
|
||||||
{ name: 'audioPath', type: "input", input: "", disabled: true },
|
{ name: 'audioPath', type: "input", input: "", disabled: true },
|
||||||
@ -350,4 +399,59 @@ export const collapseList = [
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
collapseTitle: "触控交互",
|
||||||
|
nodeList: [
|
||||||
|
{
|
||||||
|
icon: touchSvg,
|
||||||
|
name: "触控",
|
||||||
|
type: "serviceNode",
|
||||||
|
desc: "去触控坐标的点位",
|
||||||
|
action: 'TOUCH',
|
||||||
|
nodeType: "EDGE",
|
||||||
|
nodeParams: [
|
||||||
|
{ name: "deviceId", type: "input", input: "", disabled: true },
|
||||||
|
{ name: "touchParams", type: "input", input: "", disabled: true }
|
||||||
|
],
|
||||||
|
outputType: 'json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: expressionSvg,
|
||||||
|
name: "开始说话",
|
||||||
|
type: "serviceNode",
|
||||||
|
desc: "控制机器人说话",
|
||||||
|
action: 'BIO_HEAD_SPEAK_START',
|
||||||
|
nodeType: "EDGE",
|
||||||
|
nodeParams: [
|
||||||
|
{ name: "deviceId", type: "input", input: "", disabled: true }
|
||||||
|
],
|
||||||
|
outputType: 'json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: expressionSvg,
|
||||||
|
name: "停止说话",
|
||||||
|
type: "serviceNode",
|
||||||
|
desc: "停止机器人说话",
|
||||||
|
action: 'BIO_HEAD_SPEAK_STOP',
|
||||||
|
nodeType: "EDGE",
|
||||||
|
nodeParams: [
|
||||||
|
{ name: "deviceId", type: "input", input: "", disabled: true }
|
||||||
|
],
|
||||||
|
outputType: 'json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: expressionSvg,
|
||||||
|
name: "表情",
|
||||||
|
type: "serviceNode",
|
||||||
|
desc: "控制机器人的面部表情",
|
||||||
|
action: 'BIO_HEAD_SPECIAL_EXPRESSION',
|
||||||
|
nodeType: "EDGE",
|
||||||
|
nodeParams: [
|
||||||
|
{ name: "deviceId", type: "input", input: "", disabled: true },
|
||||||
|
{ name: "expressKey", type: "input",componentType: 'select', selectOptions: expressOptions(), disabled: true },
|
||||||
|
],
|
||||||
|
outputType: 'json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<svg t="1758526744847" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8113" width="200" height="200"><path d="M512 117.76c218.065455 0 395.636364 135.68 395.636364 302.545455s-177.570909 302.545455-395.636364 302.545454a144.058182 144.058182 0 0 0-50.501818 10.472727 791.272727 791.272727 0 0 0-162.909091 99.374546c-4.421818-128.232727-23.272727-168.96-56.087273-191.534546C162.909091 584.145455 116.363636 503.621818 116.363636 420.538182c0-167.098182 177.570909-302.545455 395.636364-302.545455m0-69.818182c-256 0-465.454545 166.632727-465.454545 372.363637 0 110.312727 59.810909 209.454545 155.22909 277.643636 23.272727 16.756364 27.694545 116.363636 27.694546 192.232727a41.192727 41.192727 0 0 0 40.494545 41.89091 40.029091 40.029091 0 0 0 23.272728-8.61091c58.414545-45.149091 141.730909-105.425455 192-124.50909a74.007273 74.007273 0 0 1 26.763636-6.05091c256 0 465.454545-166.865455 465.454545-372.363636s-209.454545-372.363636-465.454545-372.363636z" fill="#65BEE0" p-id="8114"></path><path d="M663.272727 325.818182h-302.545454a34.909091 34.909091 0 0 0 0 69.818182h302.545454a34.909091 34.909091 0 0 0 0-69.818182zM616.727273 488.727273h-209.454546a34.909091 34.909091 0 0 0 0 69.818182h209.454546a34.909091 34.909091 0 0 0 0-69.818182z" fill="#65BEE0" p-id="8115"></path></svg>
|
<svg t="1762763163012" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23408" width="200" height="200"><path d="M0 0m234.057143 0l555.885714 0q234.057143 0 234.057143 234.057143l0 555.885714q0 234.057143-234.057143 234.057143l-555.885714 0q-234.057143 0-234.057143-234.057143l0-555.885714q0-234.057143 234.057143-234.057143Z" fill="#65BEE0" p-id="23409" data-spm-anchor-id="a313x.search_index.0.i15.2cb83a81yhcKKA" class=""></path><path d="M735.319771 277.942857H376.451657A69.266286 69.266286 0 0 0 307.2 347.194514v197.953829A69.266286 69.266286 0 0 0 376.451657 614.4H446.171429s3.657143 43.885714-25.6 58.514286c0 0 72.206629-14.628571 94.6176-58.514286h220.130742A69.266286 69.266286 0 0 0 804.571429 545.148343V347.194514A69.266286 69.266286 0 0 0 735.319771 277.942857zM446.171429 482.742857a29.257143 29.257143 0 0 1-29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143-29.257143 29.257143 29.257143 0 0 1 29.257142 29.257143 29.257143 29.257143 0 0 1-29.257142 29.257143z m109.714285 0a29.257143 29.257143 0 0 1-29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143 29.257143 29.257143 29.257143 0 0 1-29.257143 29.257143z m109.714286 0a29.257143 29.257143 0 0 1-29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143 29.257143 29.257143 29.257143 0 0 1-29.257143 29.257143z" fill="#ffffff" opacity=".34" p-id="23410" data-spm-anchor-id="a313x.search_index.0.i17.2cb83a81yhcKKA" class="selected"></path><path d="M662.176914 351.085714H303.3088A69.266286 69.266286 0 0 0 234.057143 420.337371v197.953829A69.266286 69.266286 0 0 0 303.3088 687.542857H373.028571s3.657143 43.885714-25.6 58.514286c0 0 72.206629-14.628571 94.6176-58.514286h220.130743A69.266286 69.266286 0 0 0 731.428571 618.2912V420.337371A69.266286 69.266286 0 0 0 662.176914 351.085714zM373.028571 555.885714a29.257143 29.257143 0 0 1-29.257142-29.257143 29.257143 29.257143 0 0 1 29.257142-29.257142 29.257143 29.257143 0 0 1 29.257143 29.257142 29.257143 29.257143 0 0 1-29.257143 29.257143z m109.714286 0a29.257143 29.257143 0 0 1-29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143-29.257142 29.257143 29.257143 0 0 1 29.257143 29.257142 29.257143 29.257143 0 0 1-29.257143 29.257143z m109.714286 0a29.257143 29.257143 0 0 1-29.257143-29.257143 29.257143 29.257143 0 0 1 29.257143-29.257142 29.257143 29.257143 0 0 1 29.257143 29.257142 29.257143 29.257143 0 0 1-29.257143 29.257143z" fill="#ffffff" p-id="23411" data-spm-anchor-id="a313x.search_index.0.i14.2cb83a81yhcKKA" class="selected"></path></svg>
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.6 KiB |
1
src/views/flow/icon/expression.svg
Normal file
1
src/views/flow/icon/expression.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg t="1762999534829" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4760" width="200" height="200"><path d="M512 979C263.472 979 62 777.528 62 529S263.472 79 512 79s450 201.472 450 450-201.472 450-450 450zM337 479c41.421 0 75-33.579 75-75s-33.579-75-75-75-75 33.579-75 75 33.579 75 75 75z m350 0c41.421 0 75-33.579 75-75s-33.579-75-75-75-75 33.579-75 75 33.579 75 75 75zM312 629c0 110.457 89.543 200 200 200s200-89.543 200-200H312z" fill="#65BEE0" p-id="4761"></path></svg>
|
||||||
|
After Width: | Height: | Size: 520 B |
1
src/views/flow/icon/touch.svg
Normal file
1
src/views/flow/icon/touch.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg t="1762762024042" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7115" width="200" height="200"><path d="M512 512m-512 0a512 512 0 1 0 1024 0 512 512 0 1 0-1024 0Z" fill="#65BEE0" p-id="7116" data-spm-anchor-id="a313x.search_index.0.i4.2cb83a81yhcKKA" class="selected"></path><path d="M440.018824 310.452706c6.625882 0 13.703529 2.198588 20.781176 7.68 11.294118 8.884706 17.709176 22.588235 17.769412 36.954353l0.391529 108.242823 0.120471 43.248942 0.150588 31.442823s20.239059-27.648 49.935059-27.648c15.932235 0 34.484706 7.890824 54.091294 32.165647 0 0 18.191059-30.539294 47.435294-30.539294 15.36 0 33.731765 8.342588 54.091294 33.912471 0 0 17.588706-34.424471 41.562353-34.424471 8.071529 0 16.865882 3.915294 25.99153 14.486588 10.752 12.739765 16.564706 29.063529 16.564705 45.808941v230.098824s-0.722824 5.963294-7.168 14.938353a63.608471 63.608471 0 0 1-51.83247 26.352941l-239.555765 0.060235a73.396706 73.396706 0 0 1-57.313882-27.557647l-131.373177-164.111059a46.019765 46.019765 0 0 1-6.595764-46.983529c4.517647-10.390588 13.251765-19.275294 29.635764-19.275294 8.432941 0 18.763294 2.349176 31.62353 7.951059 42.736941 19.154824 58.006588 59.542588 58.006588 59.542588l0.692706-146.100706 0.210823-43.158588 0.512-105.682824c0.060235-14.546824 6.716235-28.400941 18.31153-37.255529 7.228235-5.571765 16.263529-10.149647 25.961412-10.149647zM436.705882 180.705882a165.647059 165.647059 0 0 1 123.723294 275.787294 38.068706 38.068706 0 0 1-29.455058 12.468706h-1.987765a8.794353 8.794353 0 0 1-8.734118-8.734117l-0.090353-15.450353a15.058824 15.058824 0 0 1 4.336942-10.541177l0.090352-0.090353a123.392 123.392 0 0 0 36.352-87.792941c0-33.189647-12.950588-64.391529-36.352-87.883294A123.663059 123.663059 0 0 0 436.705882 222.117647c-33.189647 0-64.391529 12.950588-87.883294 36.352a123.663059 123.663059 0 0 0-36.352 87.883294c0 33.189647 12.950588 64.391529 36.352 87.883294l0.090353 0.060236c3.162353 3.162353 4.969412 7.499294 4.909177 11.956705a21.353412 21.353412 0 0 1-36.74353 14.697412A165.647059 165.647059 0 0 1 436.705882 180.705882z" fill="#ffffff" p-id="7117" data-spm-anchor-id="a313x.search_index.0.i3.2cb83a81yhcKKA" class=""></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="node__container">
|
<div class="node__container" :class="props.model.id">
|
||||||
<NodeState :state="nodeOperatingStatus">
|
<NodeState :state="nodeOperatingStatus">
|
||||||
<template #input>
|
<template #input>
|
||||||
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
||||||
</template>
|
</template>
|
||||||
<template #output>
|
<template #output>
|
||||||
<JsonViewer v-if="props.properties.outputType === 'json'" :value="outputJsonData" copyable boxed sort theme="light" />
|
<JsonViewer
|
||||||
|
v-if="props.properties.outputType === 'json'"
|
||||||
|
:value="outputJsonData"
|
||||||
|
copyable
|
||||||
|
boxed
|
||||||
|
sort
|
||||||
|
theme="light"
|
||||||
|
/>
|
||||||
<el-image
|
<el-image
|
||||||
v-if="props.properties.outputType === 'img'"
|
v-if="props.properties.outputType === 'img'"
|
||||||
v-for="item in outputJsonData.imageUrl"
|
v-for="item in outputJsonData.imageUrl"
|
||||||
@ -16,17 +23,24 @@
|
|||||||
show-progress
|
show-progress
|
||||||
fit="fill"
|
fit="fill"
|
||||||
/>
|
/>
|
||||||
<IPlayer v-if="props.properties.outputType === 'video'" v-for="item in outputJsonData.videoUrl" :videoUrl="item" />
|
<IPlayer
|
||||||
|
v-if="props.properties.outputType === 'video'"
|
||||||
|
v-for="item in outputJsonData.videoUrl"
|
||||||
|
:videoUrl="item"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</NodeState>
|
</NodeState>
|
||||||
<NodeTitle
|
<NodeTitle
|
||||||
:icon="props.properties.icon"
|
:icon="props.properties.icon"
|
||||||
:nodeId="props.model.id"
|
:nodeId="props.model.id"
|
||||||
:nodeProperties="props.properties"
|
:nodeProperties="props.properties"
|
||||||
|
:nodeType="props.properties.nodeType || 'NONE'"
|
||||||
:nodeName="props.properties.name"
|
:nodeName="props.properties.name"
|
||||||
:nodeDesc="props.properties.desc"
|
:nodeDesc="props.properties.desc"
|
||||||
|
:zoom-state="nodeZoom"
|
||||||
|
@zoom="zoom"
|
||||||
/>
|
/>
|
||||||
<div class="input__container">
|
<div class="input__container" v-show="nodeZoom">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="tag"></div>
|
<div class="tag"></div>
|
||||||
@ -57,11 +71,14 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
:label="index === 0 ? '参数名' : ''"
|
:label="index === 0 ? '参数名' : ''"
|
||||||
:prop="`nodeParams.${index}.name`"
|
:prop="`nodeParams.${index}.name`"
|
||||||
:rules="[{ required: true, message: '请输入参数名', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{ required: true, message: '请输入参数名', trigger: 'blur' },
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
:disabled="property?.disabled || false"
|
:disabled="property?.disabled || false"
|
||||||
v-model="property.name"
|
v-model="property.name"
|
||||||
|
@keydown="handleInputKeydown"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
@ -70,33 +87,76 @@
|
|||||||
:label="index === 0 ? '参数值' : ''"
|
:label="index === 0 ? '参数值' : ''"
|
||||||
:prop="`nodeParams.${index}.type`"
|
:prop="`nodeParams.${index}.type`"
|
||||||
>
|
>
|
||||||
<el-select v-model="property.type" @change="handleTypeChange(index)">
|
<el-select
|
||||||
|
v-model="property.type"
|
||||||
|
@change="handleTypeChange(index)"
|
||||||
|
>
|
||||||
<el-option label="引用" value="quote" />
|
<el-option label="引用" value="quote" />
|
||||||
<el-option label="输入" value="input" />
|
<el-option label="输入" value="input" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="property.type === 'input'"
|
v-if="property.type === 'input'"
|
||||||
:rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
:prop="`nodeParams.${index}.input`"
|
:prop="`nodeParams.${index}.input`"
|
||||||
>
|
>
|
||||||
<el-input-number v-if="property.componentType === 'number'" v-model="property.input" :min="0" :controls="false" :step-strictly="true" placeholder="请输入" clearable />
|
<el-input-number
|
||||||
<el-select v-model="property.input" v-else-if="property.componentType === 'select'" >
|
v-if="property.componentType === 'number'"
|
||||||
<el-option v-for="item in property.selectOptions" :key="item" :label="item" :value="item" />
|
v-model="property.input"
|
||||||
|
:min="0"
|
||||||
|
:controls="false"
|
||||||
|
:step-strictly="true"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<el-select
|
||||||
|
v-model="property.input"
|
||||||
|
v-else-if="property.componentType === 'select'"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in property.selectOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-input v-else v-model="property.input" placeholder="请输入" clearable />
|
<el-input
|
||||||
|
@keydown="handleInputKeydown"
|
||||||
|
v-else
|
||||||
|
v-model="property.input"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="property.type === 'quote'"
|
v-if="property.type === 'quote'"
|
||||||
:rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
:prop="`nodeParams.${index}.quote`"
|
:prop="`nodeParams.${index}.quote`"
|
||||||
>
|
>
|
||||||
<el-cascader
|
<el-cascader
|
||||||
:ref="el => { if (el) cascaderRefs[index] = el }"
|
:ref="
|
||||||
|
(el) => {
|
||||||
|
if (el) cascaderRefs[index] = el;
|
||||||
|
}
|
||||||
|
"
|
||||||
v-model="property.quote"
|
v-model="property.quote"
|
||||||
:checkStrictly="true"
|
:checkStrictly="true"
|
||||||
:options="quoteOptions"
|
:options="quoteOptions"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@visible-change="(visible) => visibleChange(visible, index, property.quote)"
|
@visible-change="
|
||||||
|
(visible) => visibleChange(visible, index, property.quote)
|
||||||
|
"
|
||||||
@change="(value) => cascaderChange(value, index)"
|
@change="(value) => cascaderChange(value, index)"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -106,7 +166,8 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="output__container" v-if="props.properties?.outputParams?.length > 0">
|
<div class="output__container" v-show="nodeZoom">
|
||||||
|
<div v-if="props.properties?.outputParams?.length > 0">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="tag"></div>
|
<div class="tag"></div>
|
||||||
@ -146,11 +207,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from "vue";
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { getInput } from "@/utils/flow";
|
import { getInput, initNodeZoom } from "@/utils/flow";
|
||||||
import { useFlowStore } from "@/store/modules/flow";
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import { Plus } from "@element-plus/icons-vue";
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
import NodeTitle from "../../components/NodeTitle.vue";
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
@ -171,7 +233,7 @@ const flowStore = useFlowStore();
|
|||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
nodeParams: [],
|
nodeParams: [],
|
||||||
outputParams: []
|
outputParams: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = reactive({});
|
const rules = reactive({});
|
||||||
@ -189,31 +251,31 @@ const handleTypeChange = (index) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cascaderRefs = ref([])
|
const cascaderRefs = ref([]);
|
||||||
const outputRules = reactive({});
|
const outputRules = reactive({});
|
||||||
const cascaderChange = (value, index) => {
|
const cascaderChange = (value, index) => {
|
||||||
const selectedOptions = cascaderRefs.value[index].getCheckedNodes(true);
|
const selectedOptions = cascaderRefs.value[index].getCheckedNodes(true);
|
||||||
formData.nodeParams[index].quote = value
|
formData.nodeParams[index].quote = value;
|
||||||
formData.nodeParams[index].quoteType = selectedOptions[0].data.type
|
formData.nodeParams[index].quoteType = selectedOptions[0].data.type;
|
||||||
}
|
};
|
||||||
|
|
||||||
const addOutputFormItem = () => {
|
const addOutputFormItem = () => {
|
||||||
formData.outputParams.push({
|
formData.outputParams.push({
|
||||||
name: '',
|
name: "",
|
||||||
type: '',
|
type: "",
|
||||||
desc: '',
|
desc: "",
|
||||||
children: []
|
children: [],
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const dynamicForm = ref();
|
const dynamicForm = ref();
|
||||||
const outputFormRef = ref()
|
const outputFormRef = ref();
|
||||||
const setNodeProperties = async () => {
|
const setNodeProperties = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await dynamicForm.value.validate();
|
const result = await dynamicForm.value.validate();
|
||||||
let flag = true
|
let flag = true;
|
||||||
if (outputFormRef.value) {
|
if (outputFormRef.value) {
|
||||||
flag = await outputFormRef.value.validate()
|
flag = await outputFormRef.value.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && flag) {
|
if (result && flag) {
|
||||||
@ -222,6 +284,7 @@ const setNodeProperties = async () => {
|
|||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data,
|
...data,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -300,6 +363,12 @@ const deleteTopLevelItem = (fullPath) => {
|
|||||||
const lastIndex = fullPath[fullPath.length - 1];
|
const lastIndex = fullPath[fullPath.length - 1];
|
||||||
currentLevel.splice(lastIndex, 1);
|
currentLevel.splice(lastIndex, 1);
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
|
const zoom = (flag) => {
|
||||||
|
nodeZoom.value = flag
|
||||||
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@ -311,8 +380,15 @@ watch(
|
|||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option;
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (props.properties.outputParams && props.properties.outputParams.length > 0) {
|
if (
|
||||||
|
props.properties.outputParams &&
|
||||||
|
props.properties.outputParams.length > 0
|
||||||
|
) {
|
||||||
formData.outputParams = props.properties.outputParams;
|
formData.outputParams = props.properties.outputParams;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -322,6 +398,15 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleInputKeydown = (e) => {
|
||||||
|
// 阻止事件冒泡到 Logic Flow 节点,避免被其事件拦截
|
||||||
|
e.stopPropagation();
|
||||||
|
// 可选:明确放行 Ctrl+V(增强兼容性)
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === "v") {
|
||||||
|
e.returnValue = true; // 允许默认粘贴行为
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
emitter.on("changeNodeState", (data) => {
|
emitter.on("changeNodeState", (data) => {
|
||||||
if (data.nodeId === props.model.id) {
|
if (data.nodeId === props.model.id) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="node__container">
|
<div class="node__container" :class="props.model.id">
|
||||||
<keep-alive>
|
<keep-alive>
|
||||||
<NodeState :state="nodeOperatingStatus">
|
<NodeState :state="nodeOperatingStatus">
|
||||||
<template #input>
|
<template #input>
|
||||||
@ -12,12 +12,29 @@
|
|||||||
</keep-alive>
|
</keep-alive>
|
||||||
<div class="title__container">
|
<div class="title__container">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
|
<div class="left">
|
||||||
<img src="../../icon/start.svg" alt="" />
|
<img src="../../icon/start.svg" alt="" />
|
||||||
<span class="text">Start</span>
|
<span class="text">Start</span>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="nodeZoom ? '缩小' : '放大'"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button circle @click="zoom">
|
||||||
|
<el-icon>
|
||||||
|
<ZoomOut v-if="nodeZoom" />
|
||||||
|
<ZoomIn v-else />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subTitle">工作流的起始节点,用于设定启动工作流需要的信息</div>
|
<div class="subTitle">工作流的起始节点,用于设定启动工作流需要的信息</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input__container">
|
<div class="input__container" v-show="nodeZoom">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="tag"></div>
|
<div class="tag"></div>
|
||||||
@ -60,9 +77,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { watch, reactive, toRaw, ref, onMounted, onUnmounted } from "vue";
|
import { watch, reactive, toRaw, ref, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { Plus } from "@element-plus/icons-vue";
|
import { Plus, ZoomOut, ZoomIn } from "@element-plus/icons-vue";
|
||||||
import { useFlowStore } from "@/store/modules/flow";
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
|
import { initNodeZoom } from "@/utils/flow";
|
||||||
import NodeState from "../../components/NodeState.vue";
|
import NodeState from "../../components/NodeState.vue";
|
||||||
import "vue3-json-viewer/dist/index.css";
|
import "vue3-json-viewer/dist/index.css";
|
||||||
import { emitter } from "@/utils/eventBus";
|
import { emitter } from "@/utils/eventBus";
|
||||||
@ -112,6 +130,7 @@ const setNodeProperties = async () => {
|
|||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...props.properties,
|
...props.properties,
|
||||||
...data,
|
...data,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -129,6 +148,9 @@ watch(
|
|||||||
() => {
|
() => {
|
||||||
if (props.properties.inputParams && props.properties.inputParams.length > 0) {
|
if (props.properties.inputParams && props.properties.inputParams.length > 0) {
|
||||||
formData.inputParams = props.properties.inputParams;
|
formData.inputParams = props.properties.inputParams;
|
||||||
|
nextTick(() => {
|
||||||
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -200,6 +222,12 @@ const validateForm = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
|
const zoom = () => {
|
||||||
|
nodeZoom.value = !nodeZoom.value
|
||||||
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
emitter.off("changeNodeState");
|
emitter.off("changeNodeState");
|
||||||
emitter.off("contentChange");
|
emitter.off("contentChange");
|
||||||
@ -220,7 +248,9 @@ defineExpose({
|
|||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
img {
|
img {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
@ -233,6 +263,14 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
.el-button {
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.subTitle {
|
.subTitle {
|
||||||
color: #737a87;
|
color: #737a87;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="group__container" @mouseleave="setNodeProperties">
|
<div class="group__container" :class="props.model.id" @mouseleave="setNodeProperties">
|
||||||
<NodeTitle
|
<NodeTitle
|
||||||
:icon="loop"
|
:icon="loop"
|
||||||
:nodeId="props.model.id"
|
:nodeId="props.model.id"
|
||||||
:nodeProperties="props.properties"
|
:nodeProperties="props.properties"
|
||||||
:nodeName="props.properties?.name || '循环'"
|
:nodeName="props.properties?.name || '循环'"
|
||||||
nodeDesc="循环执行一系列任务,直至输出所有结果"
|
nodeDesc="循环执行一系列任务,直至输出所有结果"
|
||||||
|
:showZoom="false"
|
||||||
/>
|
/>
|
||||||
<div class="loop__container">
|
<div class="loop__container">
|
||||||
<div>
|
<div>
|
||||||
@ -24,7 +25,11 @@
|
|||||||
:label="index === 0 ? '参数名' : ''"
|
:label="index === 0 ? '参数名' : ''"
|
||||||
:prop="`nodeParams.${index}.name`"
|
:prop="`nodeParams.${index}.name`"
|
||||||
:rules="[
|
:rules="[
|
||||||
{ required: true, message: '请输入参数名', trigger: 'blur' },
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数名',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
@ -87,7 +92,8 @@
|
|||||||
:options="quoteOptions"
|
:options="quoteOptions"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@visible-change="
|
@visible-change="
|
||||||
(visible) => visibleChange(visible, index, property.quote)
|
(visible) =>
|
||||||
|
visibleChange(visible, index, property.quote)
|
||||||
"
|
"
|
||||||
@change="(value) => cascaderChange(value, index)"
|
@change="(value) => cascaderChange(value, index)"
|
||||||
/>
|
/>
|
||||||
@ -99,7 +105,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>循环体</div>
|
<div>循环体</div>
|
||||||
<div class="child__container" @drop="handleDrop" @dragover="handleDragover">
|
<div
|
||||||
|
class="child__container"
|
||||||
|
@drop="handleDrop"
|
||||||
|
@dragover="handleDragover"
|
||||||
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="node__container">
|
<div class="node__container" :class="props.model.id">
|
||||||
<NodeState :state="nodeOperatingStatus">
|
<NodeState :state="nodeOperatingStatus">
|
||||||
<template #input>
|
<template #input>
|
||||||
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
||||||
@ -25,8 +25,10 @@
|
|||||||
:nodeProperties="props.properties"
|
:nodeProperties="props.properties"
|
||||||
:nodeName="props.properties.name"
|
:nodeName="props.properties.name"
|
||||||
:nodeDesc="props.properties.desc"
|
:nodeDesc="props.properties.desc"
|
||||||
|
:zoom-state="nodeZoom"
|
||||||
|
@zoom="zoom"
|
||||||
/>
|
/>
|
||||||
<div class="input__container">
|
<div class="input__container" v-show="nodeZoom">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="tag"></div>
|
<div class="tag"></div>
|
||||||
@ -42,7 +44,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form__container">
|
<div class="form__container" v-show="nodeZoom">
|
||||||
<el-form
|
<el-form
|
||||||
:inline="true"
|
:inline="true"
|
||||||
:model="formData"
|
:model="formData"
|
||||||
@ -134,8 +136,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from "vue";
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { getInput } from "@/utils/flow";
|
import { getInput, initNodeZoom } from "@/utils/flow";
|
||||||
import { useFlowStore } from "@/store/modules/flow";
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import { Plus } from "@element-plus/icons-vue";
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
import NodeTitle from "../../components/NodeTitle.vue";
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
@ -183,6 +185,7 @@ const setNodeProperties = async () => {
|
|||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data,
|
...data,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -228,6 +231,12 @@ const addFormItem = () => {
|
|||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
|
const zoom = (flag) => {
|
||||||
|
nodeZoom.value = flag
|
||||||
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.properties,
|
() => props.properties,
|
||||||
() => {
|
() => {
|
||||||
@ -237,6 +246,9 @@ watch(
|
|||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option;
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,28 +8,55 @@
|
|||||||
<JsonViewer :value="outputJsonData" copyable boxed sort theme="light" />
|
<JsonViewer :value="outputJsonData" copyable boxed sort theme="light" />
|
||||||
</template>
|
</template>
|
||||||
</NodeState>
|
</NodeState>
|
||||||
<NodeTitle :icon="switchSvg" :nodeId="props.model.id" :nodeProperties="props.properties" :nodeName="props.properties?.name || '分支'" nodeDesc="连接多个下游分支,根据设定的条件按照顺序查找的方式来匹配运行的分支,如果匹配到某条件则只运行该条件对应的分支,否则继续匹配下一条件直至结束" />
|
<NodeTitle
|
||||||
|
:icon="switchSvg"
|
||||||
|
:nodeId="props.model.id"
|
||||||
|
:nodeProperties="props.properties"
|
||||||
|
:nodeName="props.properties?.name || '分支'"
|
||||||
|
nodeDesc="连接多个下游分支,根据设定的条件按照顺序查找的方式来匹配运行的分支,如果匹配到某条件则只运行该条件对应的分支,否则继续匹配下一条件直至结束"
|
||||||
|
/>
|
||||||
<div class="condition_title_container">
|
<div class="condition_title_container">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="space"></div>
|
<div class="space"></div>
|
||||||
<div class="title">所有条件</div>
|
<div class="title">所有条件</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-button :disabled="flowStore.disableForm" @click="addFormItem" class="addFormItem">
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
@click="addFormItem"
|
||||||
|
class="addFormItem"
|
||||||
|
>
|
||||||
<el-icon :size="20"><Plus /></el-icon>
|
<el-icon :size="20"><Plus /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-form :inline="true" :model="formData" :rules="rules" ref="dynamicForm" label-position="top" label-width="auto" :disabled="flowStore.disableForm">
|
<el-form
|
||||||
<div class="condition" v-for="(params, index) in formData.nodeParams" :id="params.id">
|
:inline="true"
|
||||||
|
:model="formData"
|
||||||
|
:rules="rules"
|
||||||
|
ref="dynamicForm"
|
||||||
|
label-position="top"
|
||||||
|
label-width="auto"
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="condition"
|
||||||
|
v-for="(params, index) in formData.nodeParams"
|
||||||
|
:id="params.id"
|
||||||
|
>
|
||||||
<div class="title__container">
|
<div class="title__container">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="space"></div>
|
<div class="space"></div>
|
||||||
<div class="title">{{ index ===0 ? 'If' : 'Else If' }}</div>
|
<div class="title">{{ index === 0 ? "If" : "Else If" }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="deleteFormItem(params.id, index)">
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="deleteFormItem(params.id, index)"
|
||||||
|
>
|
||||||
<el-icon :size="16"><Minus /></el-icon>
|
<el-icon :size="16"><Minus /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -37,7 +64,11 @@
|
|||||||
<div class="withOr">
|
<div class="withOr">
|
||||||
<div class="title">条件</div>
|
<div class="title">条件</div>
|
||||||
<div>
|
<div>
|
||||||
<el-select v-model="params.withOr" placeholder="Select" style="width: 240px">
|
<el-select
|
||||||
|
v-model="params.withOr"
|
||||||
|
placeholder="Select"
|
||||||
|
style="width: 240px"
|
||||||
|
>
|
||||||
<el-option key="and" label="AND" value="and" />
|
<el-option key="and" label="AND" value="and" />
|
||||||
<el-option key="or" label="OR" value="or" />
|
<el-option key="or" label="OR" value="or" />
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -46,20 +77,61 @@
|
|||||||
<div class="form__container">
|
<div class="form__container">
|
||||||
<el-row v-for="(property, pIndex) in params.list">
|
<el-row v-for="(property, pIndex) in params.list">
|
||||||
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
||||||
<el-form-item :label="pIndex === 0 ? '引用变量' : ''" :prop="`nodeParams.${index}.list.${pIndex}.nameType`">
|
<el-form-item
|
||||||
|
:label="pIndex === 0 ? '引用变量' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.nameType`"
|
||||||
|
>
|
||||||
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
||||||
<el-select v-model="property.nameType" @change="handleTypeChange(index, pIndex)">
|
<el-select
|
||||||
|
v-model="property.nameType"
|
||||||
|
@change="handleTypeChange(index, pIndex)"
|
||||||
|
>
|
||||||
<el-option label="引用" value="quote" />
|
<el-option label="引用" value="quote" />
|
||||||
<el-option label="输入" value="input" />
|
<el-option label="输入" value="input" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-form-item v-if="property.nameType === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.name`">
|
<el-form-item
|
||||||
<el-input v-model="property.name" placeholder="请输入" clearable />
|
v-if="property.nameType === 'input'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.name`"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="property.name"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="property.nameType === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.nameQuote`">
|
<el-form-item
|
||||||
<el-cascader v-model="property.nameQuote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
v-if="property.nameType === 'quote'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.nameQuote`"
|
||||||
|
>
|
||||||
|
<el-cascader
|
||||||
|
v-model="property.nameQuote"
|
||||||
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
|
@visible-change="visibleChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="pIndex === 0 ? '选择条件' : ''" :prop="`nodeParams.${index}.list.${pIndex}.condition`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]">
|
<el-form-item
|
||||||
|
:label="pIndex === 0 ? '选择条件' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.condition`"
|
||||||
|
:rules="[
|
||||||
|
{ required: true, message: '请输入变量名', trigger: 'blur' },
|
||||||
|
]"
|
||||||
|
>
|
||||||
<el-select v-model="property.condition">
|
<el-select v-model="property.condition">
|
||||||
<el-option label="等于" value="equal" />
|
<el-option label="等于" value="equal" />
|
||||||
<el-option label="不等于" value="notEqualTo" />
|
<el-option label="不等于" value="notEqualTo" />
|
||||||
@ -73,27 +145,71 @@
|
|||||||
<el-option label="小于等于" value="lessThanOrEqual" />
|
<el-option label="小于等于" value="lessThanOrEqual" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="pIndex === 0 ? '比较值' : ''" :prop="`nodeParams.${index}.list.${pIndex}.type`" >
|
<el-form-item
|
||||||
<el-select v-model="property.type" @change="handleTypeChange(index, pIndex)">
|
:label="pIndex === 0 ? '比较值' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.type`"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="property.type"
|
||||||
|
@change="handleTypeChange(index, pIndex)"
|
||||||
|
>
|
||||||
<el-option label="引用" value="quote" />
|
<el-option label="引用" value="quote" />
|
||||||
<el-option label="输入" value="input" />
|
<el-option label="输入" value="input" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-form-item v-if="property.type === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.input`">
|
<el-form-item
|
||||||
<el-input v-model="property.input" placeholder="请输入" clearable />
|
v-if="property.type === 'input'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.input`"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="property.input"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="property.type === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.quote`">
|
<el-form-item
|
||||||
<el-cascader v-model="property.quote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
v-if="property.type === 'quote'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.quote`"
|
||||||
|
>
|
||||||
|
<el-cascader
|
||||||
|
v-model="property.quote"
|
||||||
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
|
@visible-change="visibleChange"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="addListItem(index)">
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="addListItem(index)"
|
||||||
|
>
|
||||||
<el-icon :size="12"><Plus /></el-icon>
|
<el-icon :size="12"><Plus /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="removeListItem(index, pIndex)">
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="removeListItem(index, pIndex)"
|
||||||
|
>
|
||||||
<el-icon :size="12"><Minus /></el-icon>
|
<el-icon :size="12"><Minus /></el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -106,14 +222,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
import { nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||||
import NodeTitle from '../../components/NodeTitle.vue'
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
import NodeState from "../../components/NodeState.vue";
|
import NodeState from "../../components/NodeState.vue";
|
||||||
import switchSvg from '../../icon/switch.svg'
|
import switchSvg from "../../icon/switch.svg";
|
||||||
import { v4 as randomUUID } from 'uuid'
|
import { v4 as randomUUID } from "uuid";
|
||||||
import { useFlowStore } from '@/store/modules/flow'
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import { Plus, Minus } from '@element-plus/icons-vue'
|
import { Plus, Minus } from "@element-plus/icons-vue";
|
||||||
import { getInput, addNewEdge, removeSwitchEdge } from '@/utils/flow'
|
import { getInput, addNewEdge, removeSwitchEdge } from "@/utils/flow";
|
||||||
import { emitter } from "@/utils/eventBus";
|
import { emitter } from "@/utils/eventBus";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -123,130 +239,137 @@ const props = defineProps({
|
|||||||
nowTime: Number,
|
nowTime: Number,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['addAnchor', 'removeAnchor', 'bindRef', 'changeAnchor'])
|
const emits = defineEmits([
|
||||||
|
"addAnchor",
|
||||||
|
"removeAnchor",
|
||||||
|
"bindRef",
|
||||||
|
"changeAnchor",
|
||||||
|
]);
|
||||||
|
|
||||||
const switchRef = ref()
|
const switchRef = ref();
|
||||||
const dynamicForm = ref()
|
const dynamicForm = ref();
|
||||||
const flowStore = useFlowStore()
|
const flowStore = useFlowStore();
|
||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
nodeParams: props.properties?.conditions || []
|
nodeParams: props.properties?.conditions || [],
|
||||||
})
|
});
|
||||||
|
|
||||||
const addFormItem = () => {
|
const addFormItem = () => {
|
||||||
const rect = switchRef.value.getBoundingClientRect();
|
const rect = switchRef.value.getBoundingClientRect();
|
||||||
addCondition(rect.height - 60)
|
addCondition(rect.height - 60);
|
||||||
}
|
};
|
||||||
|
|
||||||
const deleteFormItem = (id, index) => {
|
const deleteFormItem = (id, index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
formData.nodeParams.splice(index, 1)
|
formData.nodeParams.splice(index, 1);
|
||||||
emits('removeAnchor', id)
|
emits("removeAnchor", id);
|
||||||
removeSwitchEdge(props.model.id, id)
|
removeSwitchEdge(props.model.id, id);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const quoteOptions = ref([])
|
const quoteOptions = ref([]);
|
||||||
const handleTypeChange = (pIndex, index) => {
|
const handleTypeChange = (pIndex, index) => {
|
||||||
if (formData.nodeParams[pIndex].list[index].type === 'input') {
|
if (formData.nodeParams[pIndex].list[index].type === "input") {
|
||||||
formData.nodeParams[pIndex].list[index].quote = ""
|
formData.nodeParams[pIndex].list[index].quote = "";
|
||||||
} else {
|
} else {
|
||||||
formData.nodeParams[pIndex].list[index].input = ""
|
formData.nodeParams[pIndex].list[index].input = "";
|
||||||
const option = getInput(props.model.id, false)
|
const option = getInput(props.model.id, false);
|
||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option
|
quoteOptions.value = option;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const addCondition = (height) => {
|
const addCondition = (height) => {
|
||||||
const id = randomUUID().replace(/-/g, '')
|
const id = randomUUID().replace(/-/g, "");
|
||||||
formData.nodeParams.push({
|
formData.nodeParams.push({
|
||||||
id,
|
id,
|
||||||
withOr: 'and',
|
withOr: "and",
|
||||||
list: [{
|
list: [
|
||||||
name: '',
|
{
|
||||||
nameQuote: '',
|
name: "",
|
||||||
nameType: 'input',
|
nameQuote: "",
|
||||||
type: 'input',
|
nameType: "input",
|
||||||
input: '',
|
type: "input",
|
||||||
quote: ''
|
input: "",
|
||||||
}]
|
quote: "",
|
||||||
})
|
},
|
||||||
emits('addAnchor', height, id)
|
],
|
||||||
|
});
|
||||||
|
emits("addAnchor", height, id);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
addNewEdge(props.model.id)
|
addNewEdge(props.model.id);
|
||||||
}, 50)
|
}, 50);
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const addListItem = (pIndex, cIndex) => {
|
const addListItem = (pIndex, cIndex) => {
|
||||||
formData.nodeParams[pIndex].list.push({
|
formData.nodeParams[pIndex].list.push({
|
||||||
name: '',
|
name: "",
|
||||||
nameQuote: '',
|
nameQuote: "",
|
||||||
nameType: 'input',
|
nameType: "input",
|
||||||
type: 'input',
|
type: "input",
|
||||||
input: '',
|
input: "",
|
||||||
quote: ''
|
quote: "",
|
||||||
})
|
});
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const removeListItem = (pIndex, cIndex) => {
|
const removeListItem = (pIndex, cIndex) => {
|
||||||
if (cIndex === 0) {
|
if (cIndex === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
formData.nodeParams[pIndex].list.splice(cIndex, 1)
|
formData.nodeParams[pIndex].list.splice(cIndex, 1);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const changeFormItemHeight = () => {
|
const changeFormItemHeight = () => {
|
||||||
formData.nodeParams.forEach(item => {
|
formData.nodeParams.forEach((item) => {
|
||||||
const node = document.getElementById(item.id)
|
const node = document.getElementById(item.id);
|
||||||
emits('changeAnchor', node.offsetTop, item.id)
|
emits("changeAnchor", node.offsetTop, item.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
const node = document.getElementById("".concat(props.model.id, "_else"))
|
const node = document.getElementById("".concat(props.model.id, "_else"));
|
||||||
emits('changeAnchor', node.offsetTop, "".concat(props.model.id, "_else"))
|
emits("changeAnchor", node.offsetTop, "".concat(props.model.id, "_else"));
|
||||||
}
|
};
|
||||||
|
|
||||||
const setNodeProperties = async () => {
|
const setNodeProperties = async () => {
|
||||||
try {
|
try {
|
||||||
const valid = await dynamicForm.value.validate()
|
const valid = await dynamicForm.value.validate();
|
||||||
if (valid) {
|
if (valid) {
|
||||||
const data = toRaw(formData)
|
const data = toRaw(formData);
|
||||||
const properties = lf.getProperties(props.model.id)
|
const properties = lf.getProperties(props.model.id);
|
||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data
|
...data,
|
||||||
})
|
});
|
||||||
emits('contentChange')
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dynamicForm.value.clearValidate()
|
dynamicForm.value.clearValidate();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const visibleChange = (value) => {
|
const visibleChange = (value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
const option = getInput(props.model.id)
|
const option = getInput(props.model.id);
|
||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option
|
quoteOptions.value = option;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const nodeOperatingStatus = ref("NORMAL");
|
const nodeOperatingStatus = ref("NORMAL");
|
||||||
const inputJsonData = ref({});
|
const inputJsonData = ref({});
|
||||||
@ -256,22 +379,23 @@ watch(
|
|||||||
() => props.properties,
|
() => props.properties,
|
||||||
() => {
|
() => {
|
||||||
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
||||||
formData.nodeParams = props.properties.nodeParams
|
formData.nodeParams = props.properties.nodeParams;
|
||||||
} else {
|
} else {
|
||||||
if (formData.nodeParams.length === 0) {
|
if (formData.nodeParams.length === 0) {
|
||||||
addCondition(100)
|
addCondition(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
emits('addAnchor', 280, "".concat(props.model.id, "_else"))
|
emits("addAnchor", 280, "".concat(props.model.id, "_else"));
|
||||||
|
|
||||||
emits('bindRef', dynamicForm.value)
|
emits("bindRef", dynamicForm.value);
|
||||||
|
|
||||||
emitter.on("changeNodeState", (data) => {
|
emitter.on("changeNodeState", (data) => {
|
||||||
if (data.nodeId === props.model.id) {
|
if (data.nodeId === props.model.id) {
|
||||||
@ -301,15 +425,12 @@ onMounted(() => {
|
|||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
emitter.off("changeNodeState");
|
emitter.off("changeNodeState");
|
||||||
emitter.off("contentChange");
|
emitter.off("contentChange");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.node__container {
|
.node__container {
|
||||||
@ -346,8 +467,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@ -397,7 +516,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.form__container) {
|
:deep(.form__container) {
|
||||||
|
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<div ref="topContainerRef">
|
||||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
<el-input
|
<el-input
|
||||||
@ -46,9 +47,12 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :style="containerHeight">
|
||||||
<el-table
|
<el-table
|
||||||
v-if="refreshTable"
|
v-if="refreshTable"
|
||||||
|
height="100%"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="menuList"
|
:data="menuList"
|
||||||
row-key="menuId"
|
row-key="menuId"
|
||||||
@ -82,6 +86,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 添加或修改菜单对话框 -->
|
<!-- 添加或修改菜单对话框 -->
|
||||||
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
||||||
@ -292,6 +297,10 @@
|
|||||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
||||||
import SvgIcon from "@/components/SvgIcon";
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
import IconSelect from "@/components/IconSelect";
|
import IconSelect from "@/components/IconSelect";
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<div ref="topContainerRef">
|
||||||
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
|
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input
|
<el-input
|
||||||
@ -90,9 +91,11 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :style="containerHeight">
|
||||||
<!-- 表格数据 -->
|
<!-- 表格数据 -->
|
||||||
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-table height="100%" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="角色编号" prop="roleId" width="120" />
|
<el-table-column label="角色编号" prop="roleId" width="120" />
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
@ -139,6 +142,8 @@
|
|||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 添加或修改角色配置对话框 -->
|
<!-- 添加或修改角色配置对话框 -->
|
||||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||||
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
|
||||||
@ -244,6 +249,10 @@
|
|||||||
<script setup name="Role">
|
<script setup name="Role">
|
||||||
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
|
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
|
||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu";
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu";
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
<!--用户数据-->
|
<!--用户数据-->
|
||||||
<pane size="84">
|
<pane size="84">
|
||||||
<el-col>
|
<el-col>
|
||||||
|
<div ref="topContainerRef">
|
||||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="90px">
|
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="90px">
|
||||||
<el-form-item label="用户名称啊" prop="userName">
|
<el-form-item label="用户名称啊" prop="userName">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
@ -55,8 +56,10 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
<div :style="containerHeight">
|
||||||
|
<el-table height="100%" v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
||||||
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
||||||
@ -96,6 +99,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</pane>
|
</pane>
|
||||||
</splitpanes>
|
</splitpanes>
|
||||||
@ -220,6 +224,11 @@ import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser,
|
|||||||
import { Splitpanes, Pane } from "splitpanes"
|
import { Splitpanes, Pane } from "splitpanes"
|
||||||
import "splitpanes/dist/splitpanes.css"
|
import "splitpanes/dist/splitpanes.css"
|
||||||
|
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<el-table-column prop="value" label="入参值">
|
<el-table-column prop="value" label="入参值">
|
||||||
<template #default="{ row, column, $index }">
|
<template #default="{ row, column, $index }">
|
||||||
<el-form-item v-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`formData.tableData.${pIndex}.config.${row.propPath}.value`" :rules="row.required ? [{ required: true, message: '请输入', trigger: 'blur' }] : []">
|
<el-form-item v-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`formData.tableData.${pIndex}.config${row.propPath}value`" :rules="row.required ? [{ required: true, message: '请输入', trigger: 'blur' }] : []">
|
||||||
<el-input v-if="row.type === 'string'" v-model="row.value" />
|
<el-input v-if="row.type === 'string'" v-model="row.value" />
|
||||||
<el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" />
|
<el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" />
|
||||||
<el-switch v-if="row.type === 'boolean'" v-model="row.value" />
|
<el-switch v-if="row.type === 'boolean'" v-model="row.value" />
|
||||||
|
|||||||
@ -182,6 +182,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
@click="handleSetting(row)"
|
@click="handleSetting(row)"
|
||||||
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
>配置
|
>配置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
@ -189,6 +190,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
v-if="row.status == 1"
|
v-if="row.status == 1"
|
||||||
@click="handleExecute(row)"
|
@click="handleExecute(row)"
|
||||||
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
>执行
|
>执行
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
@ -196,6 +198,7 @@
|
|||||||
v-if="row.status == 0"
|
v-if="row.status == 0"
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
@click="handleOpenDashboard(row)"
|
@click="handleOpenDashboard(row)"
|
||||||
>可视化
|
>可视化
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|||||||
@ -35,8 +35,8 @@ export default defineConfig(({mode, command}) => {
|
|||||||
//杨 http://192.168.0.10:13080
|
//杨 http://192.168.0.10:13080
|
||||||
//赵 http://10.148.108.58:13080
|
//赵 http://10.148.108.58:13080
|
||||||
// dev http://10.148.20.34:13080
|
// dev http://10.148.20.34:13080
|
||||||
// target: command === 'build' ? VITE_API_URL : 'http://10.148.20.34:13080',
|
target: VITE_API_URL,
|
||||||
target: command === 'build' ? VITE_API_URL : 'http://192.168.0.10:13080',
|
// target: command === 'build' ? VITE_API_URL : 'http://192.168.0.10:13080',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user