Merge branch 'dev' of 192.168.0.100:smart_bench/cmvr-iot-ui into dev
This commit is contained in:
commit
6558135b8e
@ -1,55 +1,63 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
// 发布流程
|
// 发布流程
|
||||||
export function flowDeploy(data) {
|
export function flowDeploy(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/publish',
|
url: '/flow/publish',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flowExecute(data) {
|
export function flowExecute(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/execute',
|
url: '/flow/execute',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flowExecuteTrial(data) {
|
export function flowAction(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/executeTrial',
|
url: '/flow/action',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flowView(data) {
|
export function flowExecuteTrial(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/view',
|
url: '/flow/executeTrial',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flowPause(instId) {
|
export function flowView(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/flow/pause/${instId}`,
|
url: '/flow/view',
|
||||||
method: 'post'
|
method: 'post',
|
||||||
})
|
data: data
|
||||||
}
|
})
|
||||||
|
}
|
||||||
export function flowResume(instId) {
|
|
||||||
return request({
|
export function flowPause(instId) {
|
||||||
url: `/flow/resume/${instId}`,
|
return request({
|
||||||
method: 'post'
|
url: `/flow/pause/${instId}`,
|
||||||
})
|
method: 'post'
|
||||||
}
|
})
|
||||||
|
}
|
||||||
export function flowStop(instId) {
|
|
||||||
return request({
|
export function flowResume(instId) {
|
||||||
url: `/flow/stop/${instId}`,
|
return request({
|
||||||
method: 'post'
|
url: `/flow/resume/${instId}`,
|
||||||
})
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function flowStop(instId) {
|
||||||
|
return request({
|
||||||
|
url: `/flow/stop/${instId}`,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
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}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,171 +1,239 @@
|
|||||||
<template>
|
<template>
|
||||||
<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"
|
||||||
</div>
|
><EditPen
|
||||||
<div class="input_name_container" v-else>
|
/></el-icon>
|
||||||
<el-input v-model="nodeName" />
|
</div>
|
||||||
<el-button class="input_name_select" circle size="small" @click="confirmNodeName">
|
<div class="input_name_container" v-else>
|
||||||
<el-icon><Select /></el-icon>
|
<el-input v-model="nodeName" />
|
||||||
</el-button>
|
<el-button
|
||||||
<el-button class="input_name_closeBold" circle size="small" @click="cancelNodeName">
|
class="input_name_select"
|
||||||
<el-icon><CloseBold /></el-icon>
|
circle
|
||||||
</el-button>
|
size="small"
|
||||||
</div>
|
@click="confirmNodeName"
|
||||||
</div>
|
>
|
||||||
</div>
|
<el-icon><Select /></el-icon>
|
||||||
<div class="right">
|
</el-button>
|
||||||
<el-button circle size="small" @click="deleteNode">
|
<el-button
|
||||||
<el-icon><Delete /></el-icon>
|
class="input_name_closeBold"
|
||||||
</el-button>
|
circle
|
||||||
</div>
|
size="small"
|
||||||
</div>
|
@click="cancelNodeName"
|
||||||
<div class="subTitle">{{ props.nodeDesc }}</div>
|
>
|
||||||
</div>
|
<el-icon><CloseBold /></el-icon>
|
||||||
</template>
|
</el-button>
|
||||||
<script setup lang="js">
|
</div>
|
||||||
import { ref } from 'vue'
|
</div>
|
||||||
import { EditPen, Select, CloseBold, Delete } from '@element-plus/icons-vue'
|
</div>
|
||||||
import { ElMessageBox } from 'element-plus'
|
<div class="right">
|
||||||
|
<el-tooltip
|
||||||
const props = defineProps({
|
class="box-item"
|
||||||
icon: {
|
effect="dark"
|
||||||
type: String,
|
content="执行"
|
||||||
default: ''
|
placement="top"
|
||||||
},
|
>
|
||||||
nodeId: {
|
<el-button v-if="nodeType && nodeType !=='NONE'" circle @click="execute">
|
||||||
type: String,
|
<el-icon>
|
||||||
default: ''
|
<VideoPlay />
|
||||||
},
|
</el-icon>
|
||||||
nodeProperties: {
|
</el-button>
|
||||||
type: Object,
|
</el-tooltip>
|
||||||
default: () => {}
|
<el-tooltip
|
||||||
},
|
class="box-item"
|
||||||
nodeDesc: {
|
effect="dark"
|
||||||
type: String,
|
:content="zoomState ? '缩小' : '放大'"
|
||||||
default: ''
|
placement="top"
|
||||||
},
|
>
|
||||||
nodeName: {
|
<el-button v-if="showZoom" circle @click="zoom">
|
||||||
type: String,
|
<el-icon>
|
||||||
default: ''
|
<ZoomOut v-if="zoomState" />
|
||||||
},
|
<ZoomIn v-else />
|
||||||
nodeType: {
|
</el-icon>
|
||||||
type: String,
|
</el-button>
|
||||||
default: ''
|
</el-tooltip>
|
||||||
}
|
<el-tooltip
|
||||||
})
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
const showTextTitle = ref(true)
|
content="删除"
|
||||||
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
placement="top"
|
||||||
|
>
|
||||||
const confirmNodeName = () => {
|
<el-button circle @click="deleteNode">
|
||||||
const properties = lf.getProperties(props.nodeId)
|
<el-icon><Delete /></el-icon>
|
||||||
lf.setProperties(props.nodeId, {
|
</el-button>
|
||||||
...properties,
|
</el-tooltip>
|
||||||
name: nodeName.value
|
</div>
|
||||||
})
|
</div>
|
||||||
showTextTitle.value = true
|
<div class="subTitle">{{ props.nodeDesc }}</div>
|
||||||
}
|
</div>
|
||||||
|
</template>
|
||||||
const cancelNodeName = () => {
|
<script setup lang="js">
|
||||||
nodeName.value = props.nodeProperties?.name || props.nodeName
|
import { ref } from 'vue'
|
||||||
showTextTitle.value = true
|
import { EditPen, Select, CloseBold, Delete, ZoomOut, ZoomIn, VideoPlay } from '@element-plus/icons-vue'
|
||||||
}
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
const deleteNode = () => {
|
const props = defineProps({
|
||||||
ElMessageBox.confirm(
|
icon: {
|
||||||
'是否删除该节点?',
|
type: String,
|
||||||
'警告',
|
default: ''
|
||||||
{
|
},
|
||||||
confirmButtonText: '确定',
|
nodeId: {
|
||||||
cancelButtonText: '取消',
|
type: String,
|
||||||
type: 'warning',
|
default: ''
|
||||||
}
|
},
|
||||||
)
|
nodeProperties: {
|
||||||
.then(() => {
|
type: Object,
|
||||||
if (props.nodeType === 'selectArea') {
|
default: () => {}
|
||||||
const children = lf.getNodeModelById(props.nodeId).children
|
},
|
||||||
lf.getNodeModelById(props.nodeId).children = []
|
nodeDesc: {
|
||||||
children.forEach(item => {
|
type: String,
|
||||||
lf.getNodeModelById(item).draggable = true
|
default: ''
|
||||||
})
|
},
|
||||||
}
|
nodeName: {
|
||||||
lf.deleteNode(props.nodeId);
|
type: String,
|
||||||
})
|
default: ''
|
||||||
}
|
},
|
||||||
</script>
|
nodeType: {
|
||||||
<style lang="scss" scoped>
|
type: String,
|
||||||
.title__container {
|
default: ''
|
||||||
.title {
|
},
|
||||||
display: flex;
|
showZoom: {
|
||||||
align-items: center;
|
type: Boolean,
|
||||||
justify-content: space-between;
|
default: true
|
||||||
|
},
|
||||||
.left {
|
zoomState: {
|
||||||
display: flex;
|
type: Boolean,
|
||||||
|
default: false
|
||||||
img {
|
}
|
||||||
width: 24px;
|
})
|
||||||
height: 24px;
|
|
||||||
}
|
const emits = defineEmits(['zoom'])
|
||||||
|
|
||||||
.text__container {
|
const showTextTitle = ref(true)
|
||||||
.text__title {
|
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
const confirmNodeName = () => {
|
||||||
|
const properties = lf.getProperties(props.nodeId)
|
||||||
.text {
|
lf.setProperties(props.nodeId, {
|
||||||
font-size: 16px;
|
...properties,
|
||||||
font-weight: bold;
|
name: nodeName.value
|
||||||
margin: 0 12px;
|
})
|
||||||
}
|
showTextTitle.value = true
|
||||||
|
}
|
||||||
.editIcon {
|
|
||||||
cursor: pointer;
|
const cancelNodeName = () => {
|
||||||
}
|
nodeName.value = props.nodeProperties?.name || props.nodeName
|
||||||
}
|
showTextTitle.value = true
|
||||||
|
}
|
||||||
.input_name_container {
|
|
||||||
display: flex;
|
const deleteNode = () => {
|
||||||
align-items: center;
|
ElMessageBox.confirm(
|
||||||
|
'是否删除该节点?',
|
||||||
.el-input {
|
'警告',
|
||||||
margin-left: 12px;
|
{
|
||||||
}
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
.input_name_select {
|
type: 'warning',
|
||||||
color: #00b42a;
|
}
|
||||||
margin-left: 4px;
|
)
|
||||||
border: none;
|
.then(() => {
|
||||||
}
|
if (props.nodeType === 'selectArea') {
|
||||||
|
const children = lf.getNodeModelById(props.nodeId).children
|
||||||
.input_name_closeBold {
|
lf.getNodeModelById(props.nodeId).children = []
|
||||||
color: #f53f3f;
|
children.forEach(item => {
|
||||||
margin-left: 4px;
|
lf.getNodeModelById(item).draggable = true
|
||||||
border: none;
|
})
|
||||||
}
|
}
|
||||||
}
|
lf.deleteNode(props.nodeId);
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
const zoom = () => {
|
||||||
cursor: pointer;
|
emits('zoom', !props.zoomState)
|
||||||
|
}
|
||||||
.el-button {
|
|
||||||
border: none;
|
const execute = () => {
|
||||||
}
|
const myEvent = new CustomEvent('singleNodeExecution', {
|
||||||
}
|
bubbles: false, // 是否冒泡(默认 false)
|
||||||
}
|
cancelable: false, // 是否可被 preventDefault() 取消(默认 false)
|
||||||
|
detail: { ...props.nodeProperties } // 自定义数据(任意类型,通过 event.detail 读取)
|
||||||
.subTitle {
|
});
|
||||||
color: #737a87;
|
document.dispatchEvent(myEvent);
|
||||||
font-size: 12px;
|
}
|
||||||
margin: 8px 0;
|
</script>
|
||||||
}
|
<style lang="scss" scoped>
|
||||||
}
|
.title__container {
|
||||||
</style>
|
.title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text__container {
|
||||||
|
.text__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editIcon {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_name_container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_name_select {
|
||||||
|
color: #00b42a;
|
||||||
|
margin-left: 4px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input_name_closeBold {
|
||||||
|
color: #f53f3f;
|
||||||
|
margin-left: 4px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subTitle {
|
||||||
|
color: #737a87;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -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,32 +1,46 @@
|
|||||||
<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
|
||||||
<el-image
|
v-if="props.properties.outputType === 'json'"
|
||||||
v-if="props.properties.outputType === 'img'"
|
:value="outputJsonData"
|
||||||
v-for="item in outputJsonData.imageUrl"
|
copyable
|
||||||
style="width: 60px; height: 60px"
|
boxed
|
||||||
:src="item"
|
sort
|
||||||
:preview-src-list="outputJsonData.imageUrl"
|
theme="light"
|
||||||
:preview-teleported="true"
|
/>
|
||||||
show-progress
|
<el-image
|
||||||
fit="fill"
|
v-if="props.properties.outputType === 'img'"
|
||||||
|
v-for="item in outputJsonData.imageUrl"
|
||||||
|
style="width: 60px; height: 60px"
|
||||||
|
:src="item"
|
||||||
|
:preview-src-list="outputJsonData.imageUrl"
|
||||||
|
:preview-teleported="true"
|
||||||
|
show-progress
|
||||||
|
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"
|
||||||
</el-select>
|
:min="0"
|
||||||
<el-input v-else v-model="property.input" placeholder="请输入" clearable />
|
: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-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,51 +166,53 @@
|
|||||||
</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 class="title">
|
<div v-if="props.properties?.outputParams?.length > 0">
|
||||||
<div class="left">
|
<div class="title">
|
||||||
<div class="tag"></div>
|
<div class="left">
|
||||||
<div class="text">输出</div>
|
<div class="tag"></div>
|
||||||
|
<div class="text">输出</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
@click="addOutputFormItem"
|
||||||
|
class="addFormItem"
|
||||||
|
>
|
||||||
|
<el-icon :size="20"><Plus /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right" >
|
|
||||||
<el-button
|
|
||||||
:disabled="flowStore.disableForm"
|
|
||||||
@click="addOutputFormItem"
|
|
||||||
class="addFormItem"
|
|
||||||
>
|
|
||||||
<el-icon :size="20"><Plus /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form__container">
|
<div class="form__container">
|
||||||
<el-form
|
<el-form
|
||||||
:inline="true"
|
:inline="true"
|
||||||
:model="formData"
|
:model="formData"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
label-width="auto"
|
label-width="auto"
|
||||||
:rules="outputRules"
|
:rules="outputRules"
|
||||||
ref="outputFormRef"
|
ref="outputFormRef"
|
||||||
>
|
>
|
||||||
<FormItemRecursive
|
<FormItemRecursive
|
||||||
formType="output"
|
formType="output"
|
||||||
:current-list="formData.outputParams"
|
:current-list="formData.outputParams"
|
||||||
prop-path="outputParams"
|
prop-path="outputParams"
|
||||||
:depth="0"
|
:depth="0"
|
||||||
:is-first-level="true"
|
:is-first-level="true"
|
||||||
:endDepth="2"
|
:endDepth="2"
|
||||||
:parent-path="[]"
|
:parent-path="[]"
|
||||||
@delete-item="deleteTopLevelItem"
|
@delete-item="deleteTopLevelItem"
|
||||||
/>
|
/>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</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,39 +251,40 @@ 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) {
|
||||||
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,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -286,20 +349,26 @@ const addFormItem = () => {
|
|||||||
|
|
||||||
// 删除顶层表单项
|
// 删除顶层表单项
|
||||||
const deleteTopLevelItem = (fullPath) => {
|
const deleteTopLevelItem = (fullPath) => {
|
||||||
// 从顶层数据开始查找
|
// 从顶层数据开始查找
|
||||||
let currentLevel = formData.outputParams;
|
let currentLevel = formData.outputParams;
|
||||||
|
|
||||||
// 遍历路径(除最后一个索引,因为最后一个是要删除的项)
|
// 遍历路径(除最后一个索引,因为最后一个是要删除的项)
|
||||||
for (let i = 0; i < fullPath.length - 1; i++) {
|
for (let i = 0; i < fullPath.length - 1; i++) {
|
||||||
const index = fullPath[i];
|
const index = fullPath[i];
|
||||||
// 进入下一层级
|
// 进入下一层级
|
||||||
currentLevel = currentLevel[index].children;
|
currentLevel = currentLevel[index].children;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 最后一个索引是当前层级要删除的项
|
// 最后一个索引是当前层级要删除的项
|
||||||
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) {
|
||||||
@ -499,13 +584,13 @@ defineExpose({
|
|||||||
|
|
||||||
:deep(.el-row) {
|
:deep(.el-row) {
|
||||||
align-items: end;
|
align-items: end;
|
||||||
|
|
||||||
.el-input {
|
.el-input {
|
||||||
--el-input-width: 148px;
|
--el-input-width: 148px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select {
|
.el-select {
|
||||||
--el-select-width: 148px;
|
--el-select-width: 148px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-cascader {
|
.el-cascader {
|
||||||
|
|||||||
@ -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">
|
||||||
<img src="../../icon/start.svg" alt="" />
|
<div class="left">
|
||||||
<span class="text">Start</span>
|
<img src="../../icon/start.svg" alt="" />
|
||||||
|
<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,16 +248,26 @@ defineExpose({
|
|||||||
.title {
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
img {
|
.left {
|
||||||
width: 24px;
|
img {
|
||||||
height: 24px;
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.right {
|
||||||
font-size: 16px;
|
.el-button {
|
||||||
font-weight: bold;
|
border: none;
|
||||||
margin-left: 12px;
|
font-size: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,107 +1,117 @@
|
|||||||
<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>
|
||||||
<el-form
|
<el-form
|
||||||
:inline="true"
|
:inline="true"
|
||||||
:model="formData"
|
:model="formData"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
ref="dynamicForm"
|
ref="dynamicForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
label-width="auto"
|
label-width="auto"
|
||||||
:disabled="flowStore.disableForm"
|
:disabled="flowStore.disableForm"
|
||||||
>
|
>
|
||||||
<div v-for="(property, index) in formData.nodeParams" :key="index">
|
<div v-for="(property, index) in formData.nodeParams" :key="index">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-form-item
|
|
||||||
:label="index === 0 ? '参数名' : ''"
|
|
||||||
:prop="`nodeParams.${index}.name`"
|
|
||||||
:rules="[
|
|
||||||
{ required: true, message: '请输入参数名', trigger: 'blur' },
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
:disabled="index === 0"
|
|
||||||
v-model="property.name"
|
|
||||||
placeholder="请输入"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item
|
|
||||||
:label="index === 0 ? '参数值' : ''"
|
|
||||||
:prop="`nodeParams.${index}.type`"
|
|
||||||
>
|
|
||||||
<el-select
|
|
||||||
v-model="property.type"
|
|
||||||
@change="handleTypeChange(index)"
|
|
||||||
>
|
|
||||||
<el-option label="引用" value="quote" />
|
|
||||||
<el-option label="输入" value="input" />
|
|
||||||
</el-select>
|
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="property.type === 'input'"
|
:label="index === 0 ? '参数名' : ''"
|
||||||
|
:prop="`nodeParams.${index}.name`"
|
||||||
:rules="[
|
:rules="[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入参数值',
|
message: '请输入参数名',
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
:prop="`nodeParams.${index}.input`"
|
|
||||||
>
|
>
|
||||||
<el-input-number
|
<el-input
|
||||||
v-model="property.input"
|
:disabled="index === 0"
|
||||||
:min="0"
|
v-model="property.name"
|
||||||
:controls="false"
|
|
||||||
:step-strictly="true"
|
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="property.type === 'quote'"
|
:label="index === 0 ? '参数值' : ''"
|
||||||
:rules="[
|
:prop="`nodeParams.${index}.type`"
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请选择参数值',
|
|
||||||
trigger: 'blur',
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
:prop="`nodeParams.${index}.quote`"
|
|
||||||
>
|
>
|
||||||
<el-cascader
|
<el-select
|
||||||
:ref="
|
v-model="property.type"
|
||||||
(el) => {
|
@change="handleTypeChange(index)"
|
||||||
if (el) cascaderRefs[index] = el;
|
>
|
||||||
}
|
<el-option label="引用" value="quote" />
|
||||||
"
|
<el-option label="输入" value="input" />
|
||||||
v-model="property.quote"
|
</el-select>
|
||||||
:checkStrictly="true"
|
<el-form-item
|
||||||
:options="quoteOptions"
|
v-if="property.type === 'input'"
|
||||||
placeholder="请选择"
|
:rules="[
|
||||||
@visible-change="
|
{
|
||||||
(visible) => visibleChange(visible, index, property.quote)
|
required: true,
|
||||||
"
|
message: '请输入参数值',
|
||||||
@change="(value) => cascaderChange(value, index)"
|
trigger: 'blur',
|
||||||
/>
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.input`"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
v-model="property.input"
|
||||||
|
:min="0"
|
||||||
|
:controls="false"
|
||||||
|
:step-strictly="true"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="property.type === 'quote'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.quote`"
|
||||||
|
>
|
||||||
|
<el-cascader
|
||||||
|
:ref="
|
||||||
|
(el) => {
|
||||||
|
if (el) cascaderRefs[index] = el;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
v-model="property.quote"
|
||||||
|
:checkStrictly="true"
|
||||||
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
|
@visible-change="
|
||||||
|
(visible) =>
|
||||||
|
visibleChange(visible, index, property.quote)
|
||||||
|
"
|
||||||
|
@change="(value) => cascaderChange(value, index)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-row>
|
</div>
|
||||||
</div>
|
</el-form>
|
||||||
</el-form>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>循环体</div>
|
||||||
|
<div
|
||||||
|
class="child__container"
|
||||||
|
@drop="handleDrop"
|
||||||
|
@dragover="handleDragover"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div>循环体</div>
|
|
||||||
<div class="child__container" @drop="handleDrop" @dragover="handleDragover">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@ -1,425 +1,437 @@
|
|||||||
<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"
|
||||||
style="width: 60px; height: 60px"
|
style="width: 60px; height: 60px"
|
||||||
:src="item"
|
:src="item"
|
||||||
:preview-src-list="outputJsonData.imageUrl"
|
:preview-src-list="outputJsonData.imageUrl"
|
||||||
:preview-teleported="true"
|
:preview-teleported="true"
|
||||||
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"
|
||||||
:nodeName="props.properties.name"
|
:nodeName="props.properties.name"
|
||||||
:nodeDesc="props.properties.desc"
|
:nodeDesc="props.properties.desc"
|
||||||
/>
|
:zoom-state="nodeZoom"
|
||||||
<div class="input__container">
|
@zoom="zoom"
|
||||||
<div class="title">
|
/>
|
||||||
<div class="left">
|
<div class="input__container" v-show="nodeZoom">
|
||||||
<div class="tag"></div>
|
<div class="title">
|
||||||
<div class="text">输入</div>
|
<div class="left">
|
||||||
</div>
|
<div class="tag"></div>
|
||||||
<div class="right" v-if="properties.properties?.canAddFormItem">
|
<div class="text">输入</div>
|
||||||
<el-button
|
</div>
|
||||||
:disabled="flowStore.disableForm"
|
<div class="right" v-if="properties.properties?.canAddFormItem">
|
||||||
@click="addFormItem"
|
<el-button
|
||||||
class="addFormItem"
|
:disabled="flowStore.disableForm"
|
||||||
>
|
@click="addFormItem"
|
||||||
<el-icon :size="20"><Plus /></el-icon>
|
class="addFormItem"
|
||||||
</el-button>
|
>
|
||||||
</div>
|
<el-icon :size="20"><Plus /></el-icon>
|
||||||
</div>
|
</el-button>
|
||||||
<div class="form__container">
|
</div>
|
||||||
<el-form
|
</div>
|
||||||
:inline="true"
|
<div class="form__container" v-show="nodeZoom">
|
||||||
:model="formData"
|
<el-form
|
||||||
:rules="rules"
|
:inline="true"
|
||||||
ref="dynamicForm"
|
:model="formData"
|
||||||
label-position="top"
|
:rules="rules"
|
||||||
label-width="auto"
|
ref="dynamicForm"
|
||||||
:disabled="flowStore.disableForm"
|
label-position="top"
|
||||||
>
|
label-width="auto"
|
||||||
<div v-for="(property, index) in formData.nodeParams" :key="index">
|
:disabled="flowStore.disableForm"
|
||||||
<el-row>
|
>
|
||||||
<el-form-item
|
<div v-for="(property, index) in formData.nodeParams" :key="index">
|
||||||
:label="index === 0 ? '参数名' : ''"
|
<el-row>
|
||||||
:prop="`nodeParams.${index}.name`"
|
<el-form-item
|
||||||
:rules="[{ required: true, message: '请输入参数名', trigger: 'blur' }]"
|
:label="index === 0 ? '参数名' : ''"
|
||||||
>
|
:prop="`nodeParams.${index}.name`"
|
||||||
<el-input
|
:rules="[{ required: true, message: '请输入参数名', trigger: 'blur' }]"
|
||||||
:disabled="property?.disabled || false"
|
>
|
||||||
v-model="property.name"
|
<el-input
|
||||||
placeholder="请输入"
|
:disabled="property?.disabled || false"
|
||||||
clearable
|
v-model="property.name"
|
||||||
/>
|
placeholder="请输入"
|
||||||
</el-form-item>
|
clearable
|
||||||
<el-form-item
|
/>
|
||||||
:label="index === 0 ? '参数值' : ''"
|
</el-form-item>
|
||||||
:prop="`nodeParams.${index}.type`"
|
<el-form-item
|
||||||
>
|
:label="index === 0 ? '参数值' : ''"
|
||||||
<el-select v-model="property.type" @change="handleTypeChange(index)">
|
:prop="`nodeParams.${index}.type`"
|
||||||
<el-option label="引用" value="quote" />
|
>
|
||||||
<el-option label="输入" value="input" />
|
<el-select v-model="property.type" @change="handleTypeChange(index)">
|
||||||
</el-select>
|
<el-option label="引用" value="quote" />
|
||||||
<el-form-item
|
<el-option label="输入" value="input" />
|
||||||
v-if="property.type === 'input'"
|
</el-select>
|
||||||
:rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]"
|
<el-form-item
|
||||||
:prop="`nodeParams.${index}.input`"
|
v-if="property.type === 'input'"
|
||||||
>
|
:rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]"
|
||||||
<el-input-number v-if="property.componentType === 'number'" v-model="property.input" :min="0" :controls="false" :step-strictly="true" placeholder="请输入" clearable />
|
:prop="`nodeParams.${index}.input`"
|
||||||
<el-select v-model="property.input" v-else-if="property.componentType === 'select'" >
|
>
|
||||||
<el-option v-for="item in property.selectOptions" :key="item" :label="item" :value="item" />
|
<el-input-number v-if="property.componentType === 'number'" v-model="property.input" :min="0" :controls="false" :step-strictly="true" placeholder="请输入" clearable />
|
||||||
</el-select>
|
<el-select v-model="property.input" v-else-if="property.componentType === 'select'" >
|
||||||
<el-input v-else v-model="property.input" placeholder="请输入" clearable />
|
<el-option v-for="item in property.selectOptions" :key="item" :label="item" :value="item" />
|
||||||
</el-form-item>
|
</el-select>
|
||||||
<el-form-item
|
<el-input v-else v-model="property.input" placeholder="请输入" clearable />
|
||||||
v-if="property.type === 'quote'"
|
</el-form-item>
|
||||||
:rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]"
|
<el-form-item
|
||||||
:prop="`nodeParams.${index}.quote`"
|
v-if="property.type === 'quote'"
|
||||||
>
|
:rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]"
|
||||||
<el-cascader
|
:prop="`nodeParams.${index}.quote`"
|
||||||
v-model="property.quote"
|
>
|
||||||
:options="quoteOptions"
|
<el-cascader
|
||||||
placeholder="请选择"
|
v-model="property.quote"
|
||||||
@visible-change="visibleChange"
|
:options="quoteOptions"
|
||||||
/>
|
placeholder="请选择"
|
||||||
</el-form-item>
|
@visible-change="visibleChange"
|
||||||
</el-form-item>
|
/>
|
||||||
</el-row>
|
</el-form-item>
|
||||||
</div>
|
</el-form-item>
|
||||||
</el-form>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-form>
|
||||||
<div class="output__container" v-if="props.properties?.outputParams?.length > 0">
|
</div>
|
||||||
<div class="title">
|
</div>
|
||||||
<div class="tag"></div>
|
<div class="output__container" v-if="props.properties?.outputParams?.length > 0">
|
||||||
<div class="text">输出</div>
|
<div class="title">
|
||||||
</div>
|
<div class="tag"></div>
|
||||||
|
<div class="text">输出</div>
|
||||||
<div class="form__container">
|
</div>
|
||||||
<el-form
|
|
||||||
:inline="true"
|
<div class="form__container">
|
||||||
label-position="top"
|
<el-form
|
||||||
label-width="auto"
|
:inline="true"
|
||||||
:disabled="true"
|
label-position="top"
|
||||||
>
|
label-width="auto"
|
||||||
<el-row v-for="(item, index) in props.properties.outputParams">
|
:disabled="true"
|
||||||
<el-form-item label="参数名" >
|
>
|
||||||
<el-input :value="item.name" />
|
<el-row v-for="(item, index) in props.properties.outputParams">
|
||||||
</el-form-item>
|
<el-form-item label="参数名" >
|
||||||
<el-form-item label="参数类型" >
|
<el-input :value="item.name" />
|
||||||
<el-input :value="item.type" />
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="参数类型" >
|
||||||
<el-form-item label="描述" >
|
<el-input :value="item.type" />
|
||||||
<el-input :value="item.desc" />
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="描述" >
|
||||||
</el-row>
|
<el-input :value="item.desc" />
|
||||||
</el-form>
|
</el-form-item>
|
||||||
</div>
|
</el-row>
|
||||||
</div>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
</div>
|
||||||
<script setup>
|
</template>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from "vue";
|
|
||||||
import { getInput } from "@/utils/flow";
|
<script setup>
|
||||||
import { useFlowStore } from "@/store/modules/flow";
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { Plus } from "@element-plus/icons-vue";
|
import { getInput, initNodeZoom } from "@/utils/flow";
|
||||||
import NodeTitle from "../../components/NodeTitle.vue";
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import NodeState from "../../components/NodeState.vue";
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
import "vue3-json-viewer/dist/index.css";
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
import { emitter } from "@/utils/eventBus";
|
import NodeState from "../../components/NodeState.vue";
|
||||||
import IPlayer from "@/views/device/register/components/LogicFlow/IPlayer/index.vue";
|
import "vue3-json-viewer/dist/index.css";
|
||||||
|
import { emitter } from "@/utils/eventBus";
|
||||||
const props = defineProps({
|
import IPlayer from "@/views/device/register/components/LogicFlow/IPlayer/index.vue";
|
||||||
model: Object,
|
|
||||||
properties: Object,
|
const props = defineProps({
|
||||||
});
|
model: Object,
|
||||||
|
properties: Object,
|
||||||
const emits = defineEmits(["contentChange"]);
|
});
|
||||||
|
|
||||||
const flowStore = useFlowStore();
|
const emits = defineEmits(["contentChange"]);
|
||||||
|
|
||||||
const formData = reactive({
|
const flowStore = useFlowStore();
|
||||||
nodeParams: [],
|
|
||||||
});
|
const formData = reactive({
|
||||||
|
nodeParams: [],
|
||||||
const rules = reactive({});
|
});
|
||||||
|
|
||||||
const quoteOptions = ref([]);
|
const rules = reactive({});
|
||||||
const handleTypeChange = (index) => {
|
|
||||||
if (formData.nodeParams[index].type === "input") {
|
const quoteOptions = ref([]);
|
||||||
formData.nodeParams[index].quote = "";
|
const handleTypeChange = (index) => {
|
||||||
} else {
|
if (formData.nodeParams[index].type === "input") {
|
||||||
formData.nodeParams[index].input = "";
|
formData.nodeParams[index].quote = "";
|
||||||
const option = getInput(props.model.id);
|
} else {
|
||||||
if (option) {
|
formData.nodeParams[index].input = "";
|
||||||
quoteOptions.value = option;
|
const option = getInput(props.model.id);
|
||||||
}
|
if (option) {
|
||||||
}
|
quoteOptions.value = option;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
const dynamicForm = ref();
|
};
|
||||||
|
|
||||||
const setNodeProperties = async () => {
|
const dynamicForm = ref();
|
||||||
try {
|
|
||||||
const result = await dynamicForm.value.validate();
|
const setNodeProperties = async () => {
|
||||||
if (result) {
|
try {
|
||||||
const data = toRaw(formData);
|
const result = await dynamicForm.value.validate();
|
||||||
const properties = lf.getProperties(props.model.id);
|
if (result) {
|
||||||
lf.setProperties(props.model.id, {
|
const data = toRaw(formData);
|
||||||
...properties,
|
const properties = lf.getProperties(props.model.id);
|
||||||
...data,
|
lf.setProperties(props.model.id, {
|
||||||
});
|
...properties,
|
||||||
emits("contentChange");
|
...data,
|
||||||
}
|
zoom: nodeZoom.value
|
||||||
} catch {
|
});
|
||||||
dynamicForm.value.clearValidate();
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
};
|
} catch {
|
||||||
|
dynamicForm.value.clearValidate();
|
||||||
const nodeOperatingStatus = ref("NORMAL");
|
}
|
||||||
const inputJsonData = ref({});
|
};
|
||||||
const outputJsonData = ref({});
|
|
||||||
|
const nodeOperatingStatus = ref("NORMAL");
|
||||||
const visibleChange = (value) => {
|
const inputJsonData = ref({});
|
||||||
if (value) {
|
const outputJsonData = ref({});
|
||||||
const option = getInput(props.model.id);
|
|
||||||
if (option) {
|
const visibleChange = (value) => {
|
||||||
quoteOptions.value = option;
|
if (value) {
|
||||||
}
|
const option = getInput(props.model.id);
|
||||||
}
|
if (option) {
|
||||||
};
|
quoteOptions.value = option;
|
||||||
|
}
|
||||||
const validateForm = async () => {
|
}
|
||||||
try {
|
};
|
||||||
const result = await dynamicForm.value.validate();
|
|
||||||
if (result) {
|
const validateForm = async () => {
|
||||||
return { valid: true, message: "验证通过" };
|
try {
|
||||||
} else {
|
const result = await dynamicForm.value.validate();
|
||||||
return { valid: false, message: "验证失败" };
|
if (result) {
|
||||||
}
|
return { valid: true, message: "验证通过" };
|
||||||
} catch {
|
} else {
|
||||||
return { valid: false, message: "验证失败" };
|
return { valid: false, message: "验证失败" };
|
||||||
}
|
}
|
||||||
};
|
} catch {
|
||||||
|
return { valid: false, message: "验证失败" };
|
||||||
const addFormItem = () => {
|
}
|
||||||
formData.nodeParams.push({
|
};
|
||||||
name: "",
|
|
||||||
type: "",
|
const addFormItem = () => {
|
||||||
desc: "",
|
formData.nodeParams.push({
|
||||||
required: false,
|
name: "",
|
||||||
children: [],
|
type: "",
|
||||||
});
|
desc: "",
|
||||||
emits("contentChange");
|
required: false,
|
||||||
};
|
children: [],
|
||||||
|
});
|
||||||
watch(
|
emits("contentChange");
|
||||||
() => props.properties,
|
};
|
||||||
() => {
|
|
||||||
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
formData.nodeParams = props.properties.nodeParams;
|
const zoom = (flag) => {
|
||||||
const option = getInput(props.model.id);
|
nodeZoom.value = flag
|
||||||
if (option) {
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
quoteOptions.value = option;
|
}
|
||||||
}
|
|
||||||
}
|
watch(
|
||||||
},
|
() => props.properties,
|
||||||
{
|
() => {
|
||||||
immediate: true,
|
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
||||||
deep: true,
|
formData.nodeParams = props.properties.nodeParams;
|
||||||
}
|
const option = getInput(props.model.id);
|
||||||
);
|
if (option) {
|
||||||
|
quoteOptions.value = option;
|
||||||
onMounted(() => {
|
}
|
||||||
emitter.on("changeNodeState", (data) => {
|
nextTick(() => {
|
||||||
if (data.nodeId === props.model.id) {
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
nodeOperatingStatus.value = data.status;
|
})
|
||||||
let inputData = {};
|
}
|
||||||
let output = {};
|
},
|
||||||
try {
|
{
|
||||||
inputData = JSON.parse(data.paramsIn) || {};
|
immediate: true,
|
||||||
output = JSON.parse(data.paramsOut) || {};
|
deep: true,
|
||||||
} catch (error) {
|
}
|
||||||
inputData = data.paramsIn || {};
|
);
|
||||||
output = data.paramsOut || {};
|
|
||||||
}
|
onMounted(() => {
|
||||||
inputJsonData.value = inputData;
|
emitter.on("changeNodeState", (data) => {
|
||||||
outputJsonData.value = output;
|
if (data.nodeId === props.model.id) {
|
||||||
emits("contentChange");
|
nodeOperatingStatus.value = data.status;
|
||||||
}
|
let inputData = {};
|
||||||
});
|
let output = {};
|
||||||
|
try {
|
||||||
emitter.on("contentChange", (data) => {
|
inputData = JSON.parse(data.paramsIn) || {};
|
||||||
if (data.id === props.model.id) {
|
output = JSON.parse(data.paramsOut) || {};
|
||||||
nodeOperatingStatus.value = "NORMAL";
|
} catch (error) {
|
||||||
inputJsonData.value = {};
|
inputData = data.paramsIn || {};
|
||||||
outputJsonData.value = {};
|
output = data.paramsOut || {};
|
||||||
emits("contentChange");
|
}
|
||||||
}
|
inputJsonData.value = inputData;
|
||||||
});
|
outputJsonData.value = output;
|
||||||
});
|
emits("contentChange");
|
||||||
|
}
|
||||||
onUnmounted(() => {
|
});
|
||||||
emitter.off("changeNodeState");
|
|
||||||
emitter.off("contentChange");
|
emitter.on("contentChange", (data) => {
|
||||||
});
|
if (data.id === props.model.id) {
|
||||||
|
nodeOperatingStatus.value = "NORMAL";
|
||||||
defineExpose({
|
inputJsonData.value = {};
|
||||||
validateForm,
|
outputJsonData.value = {};
|
||||||
setNodeProperties,
|
emits("contentChange");
|
||||||
});
|
}
|
||||||
</script>
|
});
|
||||||
|
});
|
||||||
<style lang="scss" scoped>
|
|
||||||
.node__container {
|
onUnmounted(() => {
|
||||||
width: 100%;
|
emitter.off("changeNodeState");
|
||||||
height: auto;
|
emitter.off("contentChange");
|
||||||
|
});
|
||||||
.input__container {
|
|
||||||
width: 100%;
|
defineExpose({
|
||||||
background-color: #fafbfc;
|
validateForm,
|
||||||
padding: 0 16px;
|
setNodeProperties,
|
||||||
border-radius: 8px;
|
});
|
||||||
box-sizing: border-box;
|
</script>
|
||||||
|
|
||||||
.title {
|
<style lang="scss" scoped>
|
||||||
height: 32px;
|
.node__container {
|
||||||
display: flex;
|
width: 100%;
|
||||||
align-items: center;
|
height: auto;
|
||||||
justify-content: space-between;
|
|
||||||
|
.input__container {
|
||||||
.left {
|
width: 100%;
|
||||||
display: flex;
|
background-color: #fafbfc;
|
||||||
align-items: center;
|
padding: 0 16px;
|
||||||
|
border-radius: 8px;
|
||||||
.tag {
|
box-sizing: border-box;
|
||||||
width: 3px;
|
|
||||||
height: 16px;
|
.title {
|
||||||
background: #1664ff;
|
height: 32px;
|
||||||
border-radius: 0 4px 4px 0;
|
display: flex;
|
||||||
margin-right: 12px;
|
align-items: center;
|
||||||
}
|
justify-content: space-between;
|
||||||
|
|
||||||
.text {
|
.left {
|
||||||
font-size: 16px;
|
display: flex;
|
||||||
font-weight: 700;
|
align-items: center;
|
||||||
color: #0c0d0e;
|
|
||||||
}
|
.tag {
|
||||||
}
|
width: 3px;
|
||||||
|
height: 16px;
|
||||||
.right {
|
background: #1664ff;
|
||||||
.addFormItem {
|
border-radius: 0 4px 4px 0;
|
||||||
border: none;
|
margin-right: 12px;
|
||||||
background: transparent;
|
}
|
||||||
cursor: pointer;
|
|
||||||
}
|
.text {
|
||||||
}
|
font-size: 16px;
|
||||||
}
|
font-weight: 700;
|
||||||
|
color: #0c0d0e;
|
||||||
.form__container {
|
}
|
||||||
margin: 12px 0;
|
}
|
||||||
|
|
||||||
.sub-properties {
|
.right {
|
||||||
margin-left: 10px;
|
.addFormItem {
|
||||||
.zw {
|
border: none;
|
||||||
margin-left: 15px;
|
background: transparent;
|
||||||
&::before {
|
cursor: pointer;
|
||||||
content: "";
|
}
|
||||||
position: absolute;
|
}
|
||||||
left: 0;
|
}
|
||||||
top: -4px;
|
|
||||||
width: 10px;
|
.form__container {
|
||||||
border-left: 1px solid gray;
|
margin: 12px 0;
|
||||||
border-bottom: 1px solid gray;
|
|
||||||
border-bottom-left-radius: 4px;
|
.sub-properties {
|
||||||
background-color: transparent;
|
margin-left: 10px;
|
||||||
height: 24px;
|
.zw {
|
||||||
}
|
margin-left: 15px;
|
||||||
}
|
&::before {
|
||||||
}
|
content: "";
|
||||||
|
position: absolute;
|
||||||
.gSon-properties {
|
left: 0;
|
||||||
margin-left: 10px;
|
top: -4px;
|
||||||
.zw {
|
width: 10px;
|
||||||
margin-left: 15px;
|
border-left: 1px solid gray;
|
||||||
&::before {
|
border-bottom: 1px solid gray;
|
||||||
content: "";
|
border-bottom-left-radius: 4px;
|
||||||
position: absolute;
|
background-color: transparent;
|
||||||
left: 0;
|
height: 24px;
|
||||||
top: -4px;
|
}
|
||||||
width: 10px;
|
}
|
||||||
border-left: 1px solid gray;
|
}
|
||||||
border-bottom: 1px solid gray;
|
|
||||||
border-bottom-left-radius: 4px;
|
.gSon-properties {
|
||||||
background-color: transparent;
|
margin-left: 10px;
|
||||||
height: 24px;
|
.zw {
|
||||||
}
|
margin-left: 15px;
|
||||||
}
|
&::before {
|
||||||
}
|
content: "";
|
||||||
}
|
position: absolute;
|
||||||
}
|
left: 0;
|
||||||
|
top: -4px;
|
||||||
.output__container {
|
width: 10px;
|
||||||
width: 100%;
|
border-left: 1px solid gray;
|
||||||
background-color: #fafbfc;
|
border-bottom: 1px solid gray;
|
||||||
padding: 0 16px;
|
border-bottom-left-radius: 4px;
|
||||||
border-radius: 8px;
|
background-color: transparent;
|
||||||
box-sizing: border-box;
|
height: 24px;
|
||||||
|
}
|
||||||
.title {
|
}
|
||||||
height: 32px;
|
}
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
.tag {
|
.output__container {
|
||||||
width: 3px;
|
width: 100%;
|
||||||
height: 16px;
|
background-color: #fafbfc;
|
||||||
background: #1664ff;
|
padding: 0 16px;
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 8px;
|
||||||
margin-right: 12px;
|
box-sizing: border-box;
|
||||||
}
|
|
||||||
|
.title {
|
||||||
.text {
|
height: 32px;
|
||||||
font-size: 16px;
|
display: flex;
|
||||||
font-weight: 700;
|
align-items: center;
|
||||||
color: #0c0d0e;
|
|
||||||
}
|
.tag {
|
||||||
}
|
width: 3px;
|
||||||
|
height: 16px;
|
||||||
.form__container {
|
background: #1664ff;
|
||||||
margin: 12px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
}
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-row) {
|
.text {
|
||||||
align-items: end;
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
.el-input {
|
color: #0c0d0e;
|
||||||
--el-input-width: 170px;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select {
|
.form__container {
|
||||||
--el-select-width: 170px;
|
margin: 12px 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.el-cascader {
|
|
||||||
--el-form-inline-content-width: 170px;
|
:deep(.el-row) {
|
||||||
}
|
align-items: end;
|
||||||
}
|
|
||||||
}
|
.el-input {
|
||||||
</style>
|
--el-input-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
--el-select-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-cascader {
|
||||||
|
--el-form-inline-content-width: 170px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,440 +1,558 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="node__container" ref="switchRef" @mouseleave="setNodeProperties">
|
<div class="node__container" ref="switchRef" @mouseleave="setNodeProperties">
|
||||||
<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 :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
|
||||||
<div class="condition_title_container">
|
:icon="switchSvg"
|
||||||
<div class="left">
|
:nodeId="props.model.id"
|
||||||
<div class="space"></div>
|
:nodeProperties="props.properties"
|
||||||
<div class="title">所有条件</div>
|
:nodeName="props.properties?.name || '分支'"
|
||||||
</div>
|
nodeDesc="连接多个下游分支,根据设定的条件按照顺序查找的方式来匹配运行的分支,如果匹配到某条件则只运行该条件对应的分支,否则继续匹配下一条件直至结束"
|
||||||
<div class="right">
|
/>
|
||||||
<el-button :disabled="flowStore.disableForm" @click="addFormItem" class="addFormItem">
|
<div class="condition_title_container">
|
||||||
<el-icon :size="20" ><Plus /></el-icon>
|
<div class="left">
|
||||||
</el-button>
|
<div class="space"></div>
|
||||||
</div>
|
<div class="title">所有条件</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="right">
|
||||||
<el-form :inline="true" :model="formData" :rules="rules" ref="dynamicForm" label-position="top" label-width="auto" :disabled="flowStore.disableForm">
|
<el-button
|
||||||
<div class="condition" v-for="(params, index) in formData.nodeParams" :id="params.id">
|
:disabled="flowStore.disableForm"
|
||||||
<div class="title__container">
|
@click="addFormItem"
|
||||||
<div class="left">
|
class="addFormItem"
|
||||||
<div class="space"></div>
|
>
|
||||||
<div class="title">{{ index ===0 ? 'If' : 'Else If' }}</div>
|
<el-icon :size="20"><Plus /></el-icon>
|
||||||
</div>
|
</el-button>
|
||||||
<div class="right">
|
</div>
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="deleteFormItem(params.id, index)">
|
</div>
|
||||||
<el-icon :size="16" ><Minus /></el-icon>
|
<div>
|
||||||
</el-button>
|
<el-form
|
||||||
</div>
|
:inline="true"
|
||||||
</div>
|
:model="formData"
|
||||||
<div class="withOr">
|
:rules="rules"
|
||||||
<div class="title">条件</div>
|
ref="dynamicForm"
|
||||||
<div>
|
label-position="top"
|
||||||
<el-select v-model="params.withOr" placeholder="Select" style="width: 240px">
|
label-width="auto"
|
||||||
<el-option key="and" label="AND" value="and" />
|
:disabled="flowStore.disableForm"
|
||||||
<el-option key="or" label="OR" value="or" />
|
>
|
||||||
</el-select>
|
<div
|
||||||
</div>
|
class="condition"
|
||||||
</div>
|
v-for="(params, index) in formData.nodeParams"
|
||||||
<div class="form__container">
|
:id="params.id"
|
||||||
<el-row v-for="(property, pIndex) in params.list">
|
>
|
||||||
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
<div class="title__container">
|
||||||
<el-form-item :label="pIndex === 0 ? '引用变量' : ''" :prop="`nodeParams.${index}.list.${pIndex}.nameType`">
|
<div class="left">
|
||||||
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
<div class="space"></div>
|
||||||
<el-select v-model="property.nameType" @change="handleTypeChange(index, pIndex)">
|
<div class="title">{{ index === 0 ? "If" : "Else If" }}</div>
|
||||||
<el-option label="引用" value="quote" />
|
</div>
|
||||||
<el-option label="输入" value="input" />
|
<div class="right">
|
||||||
</el-select>
|
<el-button
|
||||||
<el-form-item v-if="property.nameType === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.name`">
|
:disabled="flowStore.disableForm"
|
||||||
<el-input v-model="property.name" placeholder="请输入" clearable />
|
circle
|
||||||
</el-form-item>
|
size="small"
|
||||||
<el-form-item v-if="property.nameType === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.nameQuote`">
|
@click="deleteFormItem(params.id, index)"
|
||||||
<el-cascader v-model="property.nameQuote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
>
|
||||||
</el-form-item>
|
<el-icon :size="16"><Minus /></el-icon>
|
||||||
</el-form-item>
|
</el-button>
|
||||||
<el-form-item :label="pIndex === 0 ? '选择条件' : ''" :prop="`nodeParams.${index}.list.${pIndex}.condition`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]">
|
</div>
|
||||||
<el-select v-model="property.condition">
|
</div>
|
||||||
<el-option label="等于" value="equal" />
|
<div class="withOr">
|
||||||
<el-option label="不等于" value="notEqualTo" />
|
<div class="title">条件</div>
|
||||||
<el-option label="为空" value="null" />
|
<div>
|
||||||
<el-option label="不为空" value="notNull" />
|
<el-select
|
||||||
<el-option label="包含" value="include" />
|
v-model="params.withOr"
|
||||||
<el-option label="不包含" value="notInclude" />
|
placeholder="Select"
|
||||||
<el-option label="大于" value="greaterThan" />
|
style="width: 240px"
|
||||||
<el-option label="大于等于" value="greaterThanOrEqual" />
|
>
|
||||||
<el-option label="小于" value="lessThan" />
|
<el-option key="and" label="AND" value="and" />
|
||||||
<el-option label="小于等于" value="lessThanOrEqual" />
|
<el-option key="or" label="OR" value="or" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</div>
|
||||||
<el-form-item :label="pIndex === 0 ? '比较值' : ''" :prop="`nodeParams.${index}.list.${pIndex}.type`" >
|
</div>
|
||||||
<el-select v-model="property.type" @change="handleTypeChange(index, pIndex)">
|
<div class="form__container">
|
||||||
<el-option label="引用" value="quote" />
|
<el-row v-for="(property, pIndex) in params.list">
|
||||||
<el-option label="输入" value="input" />
|
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
||||||
</el-select>
|
<el-form-item
|
||||||
<el-form-item v-if="property.type === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.input`">
|
:label="pIndex === 0 ? '引用变量' : ''"
|
||||||
<el-input v-model="property.input" placeholder="请输入" clearable />
|
:prop="`nodeParams.${index}.list.${pIndex}.nameType`"
|
||||||
</el-form-item>
|
>
|
||||||
<el-form-item v-if="property.type === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.quote`">
|
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
||||||
<el-cascader v-model="property.quote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
<el-select
|
||||||
</el-form-item>
|
v-model="property.nameType"
|
||||||
</el-form-item>
|
@change="handleTypeChange(index, pIndex)"
|
||||||
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
>
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="addListItem(index)">
|
<el-option label="引用" value="quote" />
|
||||||
<el-icon :size="12" ><Plus /></el-icon>
|
<el-option label="输入" value="input" />
|
||||||
</el-button>
|
</el-select>
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="removeListItem(index, pIndex)">
|
<el-form-item
|
||||||
<el-icon :size="12" ><Minus /></el-icon>
|
v-if="property.nameType === 'input'"
|
||||||
</el-button>
|
:rules="[
|
||||||
</el-form-item>
|
{
|
||||||
|
required: true,
|
||||||
</el-row>
|
message: '请输入参数值',
|
||||||
</div>
|
trigger: 'blur',
|
||||||
</div>
|
},
|
||||||
</el-form>
|
]"
|
||||||
</div>
|
:prop="`nodeParams.${index}.list.${pIndex}.name`"
|
||||||
<div class="else" :id="''.concat(props.model.id, '_else')">
|
>
|
||||||
<div class="space"></div>
|
<el-input
|
||||||
<div class="title">Else</div>
|
v-model="property.name"
|
||||||
</div>
|
placeholder="请输入"
|
||||||
</div>
|
clearable
|
||||||
</template>
|
/>
|
||||||
<script setup>
|
</el-form-item>
|
||||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
<el-form-item
|
||||||
import NodeTitle from '../../components/NodeTitle.vue'
|
v-if="property.nameType === 'quote'"
|
||||||
import NodeState from "../../components/NodeState.vue";
|
:rules="[
|
||||||
import switchSvg from '../../icon/switch.svg'
|
{
|
||||||
import { v4 as randomUUID } from 'uuid'
|
required: true,
|
||||||
import { useFlowStore } from '@/store/modules/flow'
|
message: '请选择参数值',
|
||||||
import { Plus, Minus } from '@element-plus/icons-vue'
|
trigger: 'blur',
|
||||||
import { getInput, addNewEdge, removeSwitchEdge } from '@/utils/flow'
|
},
|
||||||
import { emitter } from "@/utils/eventBus";
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.nameQuote`"
|
||||||
const props = defineProps({
|
>
|
||||||
model: Object,
|
<el-cascader
|
||||||
graphModel: Object,
|
v-model="property.nameQuote"
|
||||||
properties: Object,
|
:options="quoteOptions"
|
||||||
nowTime: Number,
|
placeholder="请选择"
|
||||||
});
|
@visible-change="visibleChange"
|
||||||
|
/>
|
||||||
const emits = defineEmits(['addAnchor', 'removeAnchor', 'bindRef', 'changeAnchor'])
|
</el-form-item>
|
||||||
|
</el-form-item>
|
||||||
const switchRef = ref()
|
<el-form-item
|
||||||
const dynamicForm = ref()
|
:label="pIndex === 0 ? '选择条件' : ''"
|
||||||
const flowStore = useFlowStore()
|
:prop="`nodeParams.${index}.list.${pIndex}.condition`"
|
||||||
|
:rules="[
|
||||||
const formData = reactive({
|
{ required: true, message: '请输入变量名', trigger: 'blur' },
|
||||||
nodeParams: props.properties?.conditions || []
|
]"
|
||||||
})
|
>
|
||||||
|
<el-select v-model="property.condition">
|
||||||
const addFormItem = () => {
|
<el-option label="等于" value="equal" />
|
||||||
const rect = switchRef.value.getBoundingClientRect();
|
<el-option label="不等于" value="notEqualTo" />
|
||||||
addCondition(rect.height - 60)
|
<el-option label="为空" value="null" />
|
||||||
}
|
<el-option label="不为空" value="notNull" />
|
||||||
|
<el-option label="包含" value="include" />
|
||||||
const deleteFormItem = (id, index) => {
|
<el-option label="不包含" value="notInclude" />
|
||||||
if (index === 0) {
|
<el-option label="大于" value="greaterThan" />
|
||||||
return
|
<el-option label="大于等于" value="greaterThanOrEqual" />
|
||||||
}
|
<el-option label="小于" value="lessThan" />
|
||||||
formData.nodeParams.splice(index, 1)
|
<el-option label="小于等于" value="lessThanOrEqual" />
|
||||||
emits('removeAnchor', id)
|
</el-select>
|
||||||
removeSwitchEdge(props.model.id, id)
|
</el-form-item>
|
||||||
nextTick(() => {
|
<el-form-item
|
||||||
changeFormItemHeight()
|
:label="pIndex === 0 ? '比较值' : ''"
|
||||||
})
|
:prop="`nodeParams.${index}.list.${pIndex}.type`"
|
||||||
}
|
>
|
||||||
|
<el-select
|
||||||
const quoteOptions = ref([])
|
v-model="property.type"
|
||||||
const handleTypeChange = (pIndex, index) => {
|
@change="handleTypeChange(index, pIndex)"
|
||||||
if (formData.nodeParams[pIndex].list[index].type === 'input') {
|
>
|
||||||
formData.nodeParams[pIndex].list[index].quote = ""
|
<el-option label="引用" value="quote" />
|
||||||
} else {
|
<el-option label="输入" value="input" />
|
||||||
formData.nodeParams[pIndex].list[index].input = ""
|
</el-select>
|
||||||
const option = getInput(props.model.id, false)
|
<el-form-item
|
||||||
if (option) {
|
v-if="property.type === 'input'"
|
||||||
quoteOptions.value = option
|
:rules="[
|
||||||
}
|
{
|
||||||
}
|
required: true,
|
||||||
}
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
const addCondition = (height) => {
|
},
|
||||||
const id = randomUUID().replace(/-/g, '')
|
]"
|
||||||
formData.nodeParams.push({
|
:prop="`nodeParams.${index}.list.${pIndex}.input`"
|
||||||
id,
|
>
|
||||||
withOr: 'and',
|
<el-input
|
||||||
list: [{
|
v-model="property.input"
|
||||||
name: '',
|
placeholder="请输入"
|
||||||
nameQuote: '',
|
clearable
|
||||||
nameType: 'input',
|
/>
|
||||||
type: 'input',
|
</el-form-item>
|
||||||
input: '',
|
<el-form-item
|
||||||
quote: ''
|
v-if="property.type === 'quote'"
|
||||||
}]
|
:rules="[
|
||||||
})
|
{
|
||||||
emits('addAnchor', height, id)
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
setTimeout(() => {
|
trigger: 'blur',
|
||||||
addNewEdge(props.model.id)
|
},
|
||||||
}, 50)
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.quote`"
|
||||||
nextTick(() => {
|
>
|
||||||
changeFormItemHeight()
|
<el-cascader
|
||||||
})
|
v-model="property.quote"
|
||||||
}
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
const addListItem = (pIndex, cIndex) => {
|
@visible-change="visibleChange"
|
||||||
formData.nodeParams[pIndex].list.push({
|
/>
|
||||||
name: '',
|
</el-form-item>
|
||||||
nameQuote: '',
|
</el-form-item>
|
||||||
nameType: 'input',
|
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
||||||
type: 'input',
|
<el-button
|
||||||
input: '',
|
:disabled="flowStore.disableForm"
|
||||||
quote: ''
|
circle
|
||||||
})
|
size="small"
|
||||||
nextTick(() => {
|
@click="addListItem(index)"
|
||||||
changeFormItemHeight()
|
>
|
||||||
})
|
<el-icon :size="12"><Plus /></el-icon>
|
||||||
}
|
</el-button>
|
||||||
|
<el-button
|
||||||
const removeListItem = (pIndex, cIndex) => {
|
:disabled="flowStore.disableForm"
|
||||||
if (cIndex === 0) {
|
circle
|
||||||
return
|
size="small"
|
||||||
}
|
@click="removeListItem(index, pIndex)"
|
||||||
formData.nodeParams[pIndex].list.splice(cIndex, 1)
|
>
|
||||||
nextTick(() => {
|
<el-icon :size="12"><Minus /></el-icon>
|
||||||
changeFormItemHeight()
|
</el-button>
|
||||||
})
|
</el-form-item>
|
||||||
}
|
</el-row>
|
||||||
|
</div>
|
||||||
const changeFormItemHeight = () => {
|
</div>
|
||||||
formData.nodeParams.forEach(item => {
|
</el-form>
|
||||||
const node = document.getElementById(item.id)
|
</div>
|
||||||
emits('changeAnchor', node.offsetTop, item.id)
|
<div class="else" :id="''.concat(props.model.id, '_else')">
|
||||||
});
|
<div class="space"></div>
|
||||||
|
<div class="title">Else</div>
|
||||||
const node = document.getElementById("".concat(props.model.id, "_else"))
|
</div>
|
||||||
emits('changeAnchor', node.offsetTop, "".concat(props.model.id, "_else"))
|
</div>
|
||||||
}
|
</template>
|
||||||
|
<script setup>
|
||||||
const setNodeProperties = async () => {
|
import { nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||||
try {
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
const valid = await dynamicForm.value.validate()
|
import NodeState from "../../components/NodeState.vue";
|
||||||
if (valid) {
|
import switchSvg from "../../icon/switch.svg";
|
||||||
const data = toRaw(formData)
|
import { v4 as randomUUID } from "uuid";
|
||||||
const properties = lf.getProperties(props.model.id)
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
lf.setProperties(props.model.id, {
|
import { Plus, Minus } from "@element-plus/icons-vue";
|
||||||
...properties,
|
import { getInput, addNewEdge, removeSwitchEdge } from "@/utils/flow";
|
||||||
...data
|
import { emitter } from "@/utils/eventBus";
|
||||||
})
|
|
||||||
emits('contentChange')
|
const props = defineProps({
|
||||||
}
|
model: Object,
|
||||||
} catch (error) {
|
graphModel: Object,
|
||||||
dynamicForm.value.clearValidate()
|
properties: Object,
|
||||||
}
|
nowTime: Number,
|
||||||
}
|
});
|
||||||
|
|
||||||
const visibleChange = (value) => {
|
const emits = defineEmits([
|
||||||
if (value) {
|
"addAnchor",
|
||||||
const option = getInput(props.model.id)
|
"removeAnchor",
|
||||||
if (option) {
|
"bindRef",
|
||||||
quoteOptions.value = option
|
"changeAnchor",
|
||||||
}
|
]);
|
||||||
}
|
|
||||||
}
|
const switchRef = ref();
|
||||||
|
const dynamicForm = ref();
|
||||||
const nodeOperatingStatus = ref("NORMAL");
|
const flowStore = useFlowStore();
|
||||||
const inputJsonData = ref({});
|
|
||||||
const outputJsonData = ref({});
|
const formData = reactive({
|
||||||
|
nodeParams: props.properties?.conditions || [],
|
||||||
watch(
|
});
|
||||||
() => props.properties,
|
|
||||||
() => {
|
const addFormItem = () => {
|
||||||
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
const rect = switchRef.value.getBoundingClientRect();
|
||||||
formData.nodeParams = props.properties.nodeParams
|
addCondition(rect.height - 60);
|
||||||
} else {
|
};
|
||||||
if (formData.nodeParams.length === 0) {
|
|
||||||
addCondition(100)
|
const deleteFormItem = (id, index) => {
|
||||||
}
|
if (index === 0) {
|
||||||
}
|
return;
|
||||||
}, {
|
}
|
||||||
immediate: true,
|
formData.nodeParams.splice(index, 1);
|
||||||
deep: true
|
emits("removeAnchor", id);
|
||||||
}
|
removeSwitchEdge(props.model.id, id);
|
||||||
);
|
nextTick(() => {
|
||||||
|
changeFormItemHeight();
|
||||||
onMounted(() => {
|
});
|
||||||
emits('addAnchor', 280, "".concat(props.model.id, "_else"))
|
};
|
||||||
|
|
||||||
emits('bindRef', dynamicForm.value)
|
const quoteOptions = ref([]);
|
||||||
|
const handleTypeChange = (pIndex, index) => {
|
||||||
emitter.on("changeNodeState", (data) => {
|
if (formData.nodeParams[pIndex].list[index].type === "input") {
|
||||||
if (data.nodeId === props.model.id) {
|
formData.nodeParams[pIndex].list[index].quote = "";
|
||||||
nodeOperatingStatus.value = data.status;
|
} else {
|
||||||
let inputData = {};
|
formData.nodeParams[pIndex].list[index].input = "";
|
||||||
let output = {};
|
const option = getInput(props.model.id, false);
|
||||||
try {
|
if (option) {
|
||||||
inputData = JSON.parse(data.paramsIn) || {};
|
quoteOptions.value = option;
|
||||||
output = JSON.parse(data.paramsOut) || {};
|
}
|
||||||
} catch (error) {
|
}
|
||||||
inputData = data.paramsIn || {};
|
};
|
||||||
output = data.paramsOut || {};
|
|
||||||
}
|
const addCondition = (height) => {
|
||||||
inputJsonData.value = inputData;
|
const id = randomUUID().replace(/-/g, "");
|
||||||
outputJsonData.value = output;
|
formData.nodeParams.push({
|
||||||
|
id,
|
||||||
emits("contentChange");
|
withOr: "and",
|
||||||
}
|
list: [
|
||||||
});
|
{
|
||||||
|
name: "",
|
||||||
emitter.on("contentChange", (data) => {
|
nameQuote: "",
|
||||||
if (data.id === props.model.id) {
|
nameType: "input",
|
||||||
nodeOperatingStatus.value = "NORMAL";
|
type: "input",
|
||||||
inputJsonData.value = {};
|
input: "",
|
||||||
outputJsonData.value = {};
|
quote: "",
|
||||||
|
},
|
||||||
emits("contentChange");
|
],
|
||||||
}
|
});
|
||||||
});
|
emits("addAnchor", height, id);
|
||||||
|
|
||||||
})
|
setTimeout(() => {
|
||||||
|
addNewEdge(props.model.id);
|
||||||
onUnmounted(() => {
|
}, 50);
|
||||||
emitter.off("changeNodeState");
|
|
||||||
emitter.off("contentChange");
|
nextTick(() => {
|
||||||
});
|
changeFormItemHeight();
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
const addListItem = (pIndex, cIndex) => {
|
||||||
.node__container {
|
formData.nodeParams[pIndex].list.push({
|
||||||
width: 720px;
|
name: "",
|
||||||
height: auto;
|
nameQuote: "",
|
||||||
background: #fff;
|
nameType: "input",
|
||||||
padding: 12px;
|
type: "input",
|
||||||
cursor: default;
|
input: "",
|
||||||
border-radius: 12px;
|
quote: "",
|
||||||
border: 2px solid white;
|
});
|
||||||
box-shadow: 0 5px 15px 0#00000008;
|
nextTick(() => {
|
||||||
position: relative;
|
changeFormItemHeight();
|
||||||
|
});
|
||||||
.condition_title_container {
|
};
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
const removeListItem = (pIndex, cIndex) => {
|
||||||
justify-content: space-between;
|
if (cIndex === 0) {
|
||||||
|
return;
|
||||||
.left {
|
}
|
||||||
display: flex;
|
formData.nodeParams[pIndex].list.splice(cIndex, 1);
|
||||||
align-items: center;
|
nextTick(() => {
|
||||||
|
changeFormItemHeight();
|
||||||
.space {
|
});
|
||||||
width: 4px;
|
};
|
||||||
height: 14px;
|
|
||||||
background: rgb(22, 100, 255);
|
const changeFormItemHeight = () => {
|
||||||
border-radius: 0px 4px 4px 0px;
|
formData.nodeParams.forEach((item) => {
|
||||||
}
|
const node = document.getElementById(item.id);
|
||||||
|
emits("changeAnchor", node.offsetTop, item.id);
|
||||||
.title {
|
});
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 14px;
|
const node = document.getElementById("".concat(props.model.id, "_else"));
|
||||||
font-weight: 500;
|
emits("changeAnchor", node.offsetTop, "".concat(props.model.id, "_else"));
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
const setNodeProperties = async () => {
|
||||||
|
try {
|
||||||
|
const valid = await dynamicForm.value.validate();
|
||||||
.el-button {
|
if (valid) {
|
||||||
border: none;
|
const data = toRaw(formData);
|
||||||
}
|
const properties = lf.getProperties(props.model.id);
|
||||||
}
|
lf.setProperties(props.model.id, {
|
||||||
|
...properties,
|
||||||
.condition {
|
...data,
|
||||||
width: 100%;
|
});
|
||||||
height: auto;
|
emits("contentChange");
|
||||||
margin-bottom: 10px;
|
}
|
||||||
background-color: #fafbfc;
|
} catch (error) {
|
||||||
padding: 8px 16px;
|
dynamicForm.value.clearValidate();
|
||||||
border-radius: 8px;
|
}
|
||||||
box-sizing: border-box;
|
};
|
||||||
|
|
||||||
.title__container {
|
const visibleChange = (value) => {
|
||||||
display: flex;
|
if (value) {
|
||||||
align-items: center;
|
const option = getInput(props.model.id);
|
||||||
justify-content: space-between;
|
if (option) {
|
||||||
|
quoteOptions.value = option;
|
||||||
.left {
|
}
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
};
|
||||||
|
|
||||||
.space {
|
const nodeOperatingStatus = ref("NORMAL");
|
||||||
width: 4px;
|
const inputJsonData = ref({});
|
||||||
height: 14px;
|
const outputJsonData = ref({});
|
||||||
background: rgb(22, 100, 255);
|
|
||||||
border-radius: 0px 4px 4px 0px;
|
watch(
|
||||||
}
|
() => props.properties,
|
||||||
|
() => {
|
||||||
.title {
|
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
||||||
margin-left: 8px;
|
formData.nodeParams = props.properties.nodeParams;
|
||||||
font-size: 14px;
|
} else {
|
||||||
font-weight: bold;
|
if (formData.nodeParams.length === 0) {
|
||||||
}
|
addCondition(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
.withOr {
|
{
|
||||||
margin-bottom: 12px;
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
.title {
|
}
|
||||||
font-size: 14px;
|
);
|
||||||
color: #737a87;
|
|
||||||
margin-bottom: 4px;
|
onMounted(() => {
|
||||||
}
|
emits("addAnchor", 280, "".concat(props.model.id, "_else"));
|
||||||
}
|
|
||||||
|
emits("bindRef", dynamicForm.value);
|
||||||
:deep(.form__container) {
|
|
||||||
|
emitter.on("changeNodeState", (data) => {
|
||||||
.el-form-item {
|
if (data.nodeId === props.model.id) {
|
||||||
margin-right: 20px;
|
nodeOperatingStatus.value = data.status;
|
||||||
}
|
let inputData = {};
|
||||||
|
let output = {};
|
||||||
.el-input {
|
try {
|
||||||
width: 92px;
|
inputData = JSON.parse(data.paramsIn) || {};
|
||||||
}
|
output = JSON.parse(data.paramsOut) || {};
|
||||||
|
} catch (error) {
|
||||||
.el-select {
|
inputData = data.paramsIn || {};
|
||||||
width: 92px;
|
output = data.paramsOut || {};
|
||||||
}
|
}
|
||||||
|
inputJsonData.value = inputData;
|
||||||
.el-cascader {
|
outputJsonData.value = output;
|
||||||
width: 92px;
|
|
||||||
}
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
.else {
|
emitter.on("contentChange", (data) => {
|
||||||
display: flex;
|
if (data.id === props.model.id) {
|
||||||
align-items: center;
|
nodeOperatingStatus.value = "NORMAL";
|
||||||
background-color: #fafbfc;
|
inputJsonData.value = {};
|
||||||
padding: 8px 16px;
|
outputJsonData.value = {};
|
||||||
|
|
||||||
.space {
|
emits("contentChange");
|
||||||
width: 4px;
|
}
|
||||||
height: 14px;
|
});
|
||||||
background: rgb(22, 100, 255);
|
});
|
||||||
border-radius: 0px 4px 4px 0px;
|
|
||||||
}
|
onUnmounted(() => {
|
||||||
|
emitter.off("changeNodeState");
|
||||||
.title {
|
emitter.off("contentChange");
|
||||||
margin-left: 8px;
|
});
|
||||||
font-size: 14px;
|
</script>
|
||||||
font-weight: 500;
|
<style lang="scss" scoped>
|
||||||
font-weight: bold;
|
.node__container {
|
||||||
}
|
width: 720px;
|
||||||
}
|
height: auto;
|
||||||
}
|
background: #fff;
|
||||||
</style>
|
padding: 12px;
|
||||||
|
cursor: default;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 2px solid white;
|
||||||
|
box-shadow: 0 5px 15px 0#00000008;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.condition_title_container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.space {
|
||||||
|
width: 4px;
|
||||||
|
height: 14px;
|
||||||
|
background: rgb(22, 100, 255);
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.condition {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background-color: #fafbfc;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.title__container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.space {
|
||||||
|
width: 4px;
|
||||||
|
height: 14px;
|
||||||
|
background: rgb(22, 100, 255);
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.withOr {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #737a87;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.form__container) {
|
||||||
|
.el-form-item {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input {
|
||||||
|
width: 92px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: 92px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-cascader {
|
||||||
|
width: 92px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.else {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fafbfc;
|
||||||
|
padding: 8px 16px;
|
||||||
|
|
||||||
|
.space {
|
||||||
|
width: 4px;
|
||||||
|
height: 14px;
|
||||||
|
background: rgb(22, 100, 255);
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,452 +1,461 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
<div ref="topContainerRef">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||||
<el-input
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
v-model="queryParams.menuName"
|
<el-input
|
||||||
placeholder="请输入菜单名称"
|
v-model="queryParams.menuName"
|
||||||
clearable
|
placeholder="请输入菜单名称"
|
||||||
style="width: 200px"
|
clearable
|
||||||
@keyup.enter="handleQuery"
|
style="width: 200px"
|
||||||
/>
|
@keyup.enter="handleQuery"
|
||||||
</el-form-item>
|
/>
|
||||||
<el-form-item label="状态" prop="status">
|
</el-form-item>
|
||||||
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-option
|
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
|
||||||
v-for="dict in sys_normal_disable"
|
<el-option
|
||||||
:key="dict.value"
|
v-for="dict in sys_normal_disable"
|
||||||
:label="dict.label"
|
:key="dict.value"
|
||||||
:value="dict.value"
|
:label="dict.label"
|
||||||
/>
|
:value="dict.value"
|
||||||
</el-select>
|
/>
|
||||||
</el-form-item>
|
</el-select>
|
||||||
<el-form-item>
|
</el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
</el-form-item>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form>
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
<el-row :gutter="10" class="mb8">
|
|
||||||
<el-col :span="1.5">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-button
|
<el-col :span="1.5">
|
||||||
type="primary"
|
<el-button
|
||||||
plain
|
type="primary"
|
||||||
icon="Plus"
|
plain
|
||||||
@click="handleAdd"
|
icon="Plus"
|
||||||
v-hasPermi="['system:menu:add']"
|
@click="handleAdd"
|
||||||
>新增</el-button>
|
v-hasPermi="['system:menu:add']"
|
||||||
</el-col>
|
>新增</el-button>
|
||||||
<el-col :span="1.5">
|
</el-col>
|
||||||
<el-button
|
<el-col :span="1.5">
|
||||||
type="info"
|
<el-button
|
||||||
plain
|
type="info"
|
||||||
icon="Sort"
|
plain
|
||||||
@click="toggleExpandAll"
|
icon="Sort"
|
||||||
>展开/折叠</el-button>
|
@click="toggleExpandAll"
|
||||||
</el-col>
|
>展开/折叠</el-button>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
</el-col>
|
||||||
</el-row>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
<el-table
|
</div>
|
||||||
v-if="refreshTable"
|
|
||||||
v-loading="loading"
|
<div :style="containerHeight">
|
||||||
:data="menuList"
|
<el-table
|
||||||
row-key="menuId"
|
v-if="refreshTable"
|
||||||
:default-expand-all="isExpandAll"
|
height="100%"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
v-loading="loading"
|
||||||
>
|
:data="menuList"
|
||||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
row-key="menuId"
|
||||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
:default-expand-all="isExpandAll"
|
||||||
<template #default="scope">
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
<svg-icon :icon-class="scope.row.icon" />
|
>
|
||||||
</template>
|
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||||
</el-table-column>
|
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||||
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
<template #default="scope">
|
||||||
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
<svg-icon :icon-class="scope.row.icon" />
|
||||||
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
</template>
|
||||||
<el-table-column prop="status" label="状态" width="80">
|
</el-table-column>
|
||||||
<template #default="scope">
|
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
||||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
||||||
</template>
|
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
||||||
</el-table-column>
|
<el-table-column prop="status" label="状态" width="80">
|
||||||
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
|
<template #default="scope">
|
||||||
<template #default="scope">
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
</template>
|
||||||
</template>
|
</el-table-column>
|
||||||
</el-table-column>
|
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
|
||||||
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
|
<template #default="scope">
|
||||||
<template #default="scope">
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']">修改</el-button>
|
</template>
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
|
</el-table-column>
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
|
<el-table-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:menu:edit']">修改</el-button>
|
||||||
</el-table>
|
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
|
||||||
<!-- 添加或修改菜单对话框 -->
|
</template>
|
||||||
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
</el-table-column>
|
||||||
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
|
</el-table>
|
||||||
<el-row>
|
</div>
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="上级菜单">
|
<!-- 添加或修改菜单对话框 -->
|
||||||
<el-tree-select
|
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
||||||
v-model="form.parentId"
|
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
|
||||||
:data="menuOptions"
|
<el-row>
|
||||||
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
<el-col :span="24">
|
||||||
value-key="menuId"
|
<el-form-item label="上级菜单">
|
||||||
placeholder="选择上级菜单"
|
<el-tree-select
|
||||||
check-strictly
|
v-model="form.parentId"
|
||||||
/>
|
:data="menuOptions"
|
||||||
</el-form-item>
|
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||||
</el-col>
|
value-key="menuId"
|
||||||
<el-col :span="24">
|
placeholder="选择上级菜单"
|
||||||
<el-form-item label="菜单类型" prop="menuType">
|
check-strictly
|
||||||
<el-radio-group v-model="form.menuType">
|
/>
|
||||||
<el-radio value="M">目录</el-radio>
|
</el-form-item>
|
||||||
<el-radio value="C">菜单</el-radio>
|
</el-col>
|
||||||
<el-radio value="F">按钮</el-radio>
|
<el-col :span="24">
|
||||||
</el-radio-group>
|
<el-form-item label="菜单类型" prop="menuType">
|
||||||
</el-form-item>
|
<el-radio-group v-model="form.menuType">
|
||||||
</el-col>
|
<el-radio value="M">目录</el-radio>
|
||||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
<el-radio value="C">菜单</el-radio>
|
||||||
<el-form-item label="菜单图标" prop="icon">
|
<el-radio value="F">按钮</el-radio>
|
||||||
<el-popover
|
</el-radio-group>
|
||||||
placement="bottom-start"
|
</el-form-item>
|
||||||
:width="540"
|
</el-col>
|
||||||
trigger="click"
|
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||||
>
|
<el-form-item label="菜单图标" prop="icon">
|
||||||
<template #reference>
|
<el-popover
|
||||||
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" readonly>
|
placement="bottom-start"
|
||||||
<template #prefix>
|
:width="540"
|
||||||
<svg-icon
|
trigger="click"
|
||||||
v-if="form.icon"
|
>
|
||||||
:icon-class="form.icon"
|
<template #reference>
|
||||||
class="el-input__icon"
|
<el-input v-model="form.icon" placeholder="点击选择图标" @blur="showSelectIcon" readonly>
|
||||||
style="height: 32px;width: 16px;"
|
<template #prefix>
|
||||||
/>
|
<svg-icon
|
||||||
<el-icon v-else style="height: 32px;width: 16px;"><search /></el-icon>
|
v-if="form.icon"
|
||||||
</template>
|
:icon-class="form.icon"
|
||||||
</el-input>
|
class="el-input__icon"
|
||||||
</template>
|
style="height: 32px;width: 16px;"
|
||||||
<icon-select ref="iconSelectRef" @selected="selected" :active-icon="form.icon" />
|
/>
|
||||||
</el-popover>
|
<el-icon v-else style="height: 32px;width: 16px;"><search /></el-icon>
|
||||||
</el-form-item>
|
</template>
|
||||||
</el-col>
|
</el-input>
|
||||||
<el-col :span="12">
|
</template>
|
||||||
<el-form-item label="显示排序" prop="orderNum">
|
<icon-select ref="iconSelectRef" @selected="selected" :active-icon="form.icon" />
|
||||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
</el-popover>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="菜单名称" prop="menuName">
|
<el-form-item label="显示排序" prop="orderNum">
|
||||||
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
|
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
<el-col :span="12">
|
||||||
<el-form-item prop="routeName">
|
<el-form-item label="菜单名称" prop="menuName">
|
||||||
<template #label>
|
<el-input v-model="form.menuName" placeholder="请输入菜单名称" />
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:因为router会删除名称相同路由,为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||||
</el-tooltip>
|
<el-form-item prop="routeName">
|
||||||
路由名称
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="默认不填则和路由地址相同:如地址为:`user`,则名称为`User`(注意:因为router会删除名称相同路由,为避免名字的冲突,特殊情况下请自定义,保证唯一性)" placement="top">
|
||||||
<el-input v-model="form.routeName" placeholder="请输入路由名称" />
|
<el-icon><question-filled /></el-icon>
|
||||||
</el-form-item>
|
</el-tooltip>
|
||||||
</el-col>
|
路由名称
|
||||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
</span>
|
||||||
<el-form-item>
|
</template>
|
||||||
<template #label>
|
<el-input v-model="form.routeName" placeholder="请输入路由名称" />
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||||
</el-tooltip>是否外链
|
<el-form-item>
|
||||||
</span>
|
<template #label>
|
||||||
</template>
|
<span>
|
||||||
<el-radio-group v-model="form.isFrame">
|
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
||||||
<el-radio value="0">是</el-radio>
|
<el-icon><question-filled /></el-icon>
|
||||||
<el-radio value="1">否</el-radio>
|
</el-tooltip>是否外链
|
||||||
</el-radio-group>
|
</span>
|
||||||
</el-form-item>
|
</template>
|
||||||
</el-col>
|
<el-radio-group v-model="form.isFrame">
|
||||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
<el-radio value="0">是</el-radio>
|
||||||
<el-form-item prop="path">
|
<el-radio value="1">否</el-radio>
|
||||||
<template #label>
|
</el-radio-group>
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||||
</el-tooltip>
|
<el-form-item prop="path">
|
||||||
路由地址
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
||||||
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
<el-icon><question-filled /></el-icon>
|
||||||
</el-form-item>
|
</el-tooltip>
|
||||||
</el-col>
|
路由地址
|
||||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
</span>
|
||||||
<el-form-item prop="component">
|
</template>
|
||||||
<template #label>
|
<el-input v-model="form.path" placeholder="请输入路由地址" />
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||||
</el-tooltip>
|
<el-form-item prop="component">
|
||||||
组件路径
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
||||||
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
<el-icon><question-filled /></el-icon>
|
||||||
</el-form-item>
|
</el-tooltip>
|
||||||
</el-col>
|
组件路径
|
||||||
<el-col :span="12" v-if="form.menuType != 'M'">
|
</span>
|
||||||
<el-form-item>
|
</template>
|
||||||
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
<el-input v-model="form.component" placeholder="请输入组件路径" />
|
||||||
<template #label>
|
</el-form-item>
|
||||||
<span>
|
</el-col>
|
||||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
|
<el-col :span="12" v-if="form.menuType != 'M'">
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-form-item>
|
||||||
</el-tooltip>
|
<el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
|
||||||
权限字符
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
|
||||||
</el-form-item>
|
<el-icon><question-filled /></el-icon>
|
||||||
</el-col>
|
</el-tooltip>
|
||||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
权限字符
|
||||||
<el-form-item>
|
</span>
|
||||||
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
|
</template>
|
||||||
<template #label>
|
</el-form-item>
|
||||||
<span>
|
</el-col>
|
||||||
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-form-item>
|
||||||
</el-tooltip>
|
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
|
||||||
路由参数
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||||
</el-form-item>
|
<el-icon><question-filled /></el-icon>
|
||||||
</el-col>
|
</el-tooltip>
|
||||||
<el-col :span="12" v-if="form.menuType == 'C'">
|
路由参数
|
||||||
<el-form-item>
|
</span>
|
||||||
<template #label>
|
</template>
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType == 'C'">
|
||||||
</el-tooltip>
|
<el-form-item>
|
||||||
是否缓存
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
||||||
<el-radio-group v-model="form.isCache">
|
<el-icon><question-filled /></el-icon>
|
||||||
<el-radio value="0">缓存</el-radio>
|
</el-tooltip>
|
||||||
<el-radio value="1">不缓存</el-radio>
|
是否缓存
|
||||||
</el-radio-group>
|
</span>
|
||||||
</el-form-item>
|
</template>
|
||||||
</el-col>
|
<el-radio-group v-model="form.isCache">
|
||||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
<el-radio value="0">缓存</el-radio>
|
||||||
<el-form-item>
|
<el-radio value="1">不缓存</el-radio>
|
||||||
<template #label>
|
</el-radio-group>
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||||
</el-tooltip>
|
<el-form-item>
|
||||||
显示状态
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
||||||
<el-radio-group v-model="form.visible">
|
<el-icon><question-filled /></el-icon>
|
||||||
<el-radio
|
</el-tooltip>
|
||||||
v-for="dict in sys_show_hide"
|
显示状态
|
||||||
:key="dict.value"
|
</span>
|
||||||
:value="dict.value"
|
</template>
|
||||||
>{{ dict.label }}</el-radio>
|
<el-radio-group v-model="form.visible">
|
||||||
</el-radio-group>
|
<el-radio
|
||||||
</el-form-item>
|
v-for="dict in sys_show_hide"
|
||||||
</el-col>
|
:key="dict.value"
|
||||||
<el-col :span="12">
|
:value="dict.value"
|
||||||
<el-form-item>
|
>{{ dict.label }}</el-radio>
|
||||||
<template #label>
|
</el-radio-group>
|
||||||
<span>
|
</el-form-item>
|
||||||
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
</el-col>
|
||||||
<el-icon><question-filled /></el-icon>
|
<el-col :span="12">
|
||||||
</el-tooltip>
|
<el-form-item>
|
||||||
菜单状态
|
<template #label>
|
||||||
</span>
|
<span>
|
||||||
</template>
|
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||||
<el-radio-group v-model="form.status">
|
<el-icon><question-filled /></el-icon>
|
||||||
<el-radio
|
</el-tooltip>
|
||||||
v-for="dict in sys_normal_disable"
|
菜单状态
|
||||||
:key="dict.value"
|
</span>
|
||||||
:value="dict.value"
|
</template>
|
||||||
>{{ dict.label }}</el-radio>
|
<el-radio-group v-model="form.status">
|
||||||
</el-radio-group>
|
<el-radio
|
||||||
</el-form-item>
|
v-for="dict in sys_normal_disable"
|
||||||
</el-col>
|
:key="dict.value"
|
||||||
</el-row>
|
:value="dict.value"
|
||||||
</el-form>
|
>{{ dict.label }}</el-radio>
|
||||||
<template #footer>
|
</el-radio-group>
|
||||||
<div class="dialog-footer">
|
</el-form-item>
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
</el-col>
|
||||||
<el-button @click="cancel">取 消</el-button>
|
</el-row>
|
||||||
</div>
|
</el-form>
|
||||||
</template>
|
<template #footer>
|
||||||
</el-dialog>
|
<div class="dialog-footer">
|
||||||
</div>
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
</template>
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
<script setup name="Menu">
|
</template>
|
||||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
</el-dialog>
|
||||||
import SvgIcon from "@/components/SvgIcon";
|
</div>
|
||||||
import IconSelect from "@/components/IconSelect";
|
</template>
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
<script setup name="Menu">
|
||||||
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
||||||
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
const menuList = ref([]);
|
import IconSelect from "@/components/IconSelect";
|
||||||
const open = ref(false);
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
const loading = ref(true);
|
|
||||||
const showSearch = ref(true);
|
const topContainerRef = ref();
|
||||||
const title = ref("");
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
const menuOptions = ref([]);
|
|
||||||
const isExpandAll = ref(false);
|
const { proxy } = getCurrentInstance();
|
||||||
const refreshTable = ref(true);
|
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
||||||
const iconSelectRef = ref(null);
|
|
||||||
|
const menuList = ref([]);
|
||||||
const data = reactive({
|
const open = ref(false);
|
||||||
form: {},
|
const loading = ref(true);
|
||||||
queryParams: {
|
const showSearch = ref(true);
|
||||||
menuName: undefined,
|
const title = ref("");
|
||||||
visible: undefined
|
const menuOptions = ref([]);
|
||||||
},
|
const isExpandAll = ref(false);
|
||||||
rules: {
|
const refreshTable = ref(true);
|
||||||
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
|
const iconSelectRef = ref(null);
|
||||||
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
|
|
||||||
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
|
const data = reactive({
|
||||||
},
|
form: {},
|
||||||
});
|
queryParams: {
|
||||||
|
menuName: undefined,
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
visible: undefined
|
||||||
|
},
|
||||||
/** 查询菜单列表 */
|
rules: {
|
||||||
function getList() {
|
menuName: [{ required: true, message: "菜单名称不能为空", trigger: "blur" }],
|
||||||
loading.value = true;
|
orderNum: [{ required: true, message: "菜单顺序不能为空", trigger: "blur" }],
|
||||||
listMenu(queryParams.value).then(response => {
|
path: [{ required: true, message: "路由地址不能为空", trigger: "blur" }]
|
||||||
menuList.value = proxy.handleTree(response.data, "menuId");
|
},
|
||||||
loading.value = false;
|
});
|
||||||
});
|
|
||||||
}
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
/** 查询菜单下拉树结构 */
|
/** 查询菜单列表 */
|
||||||
function getTreeselect() {
|
function getList() {
|
||||||
menuOptions.value = [];
|
loading.value = true;
|
||||||
listMenu().then(response => {
|
listMenu(queryParams.value).then(response => {
|
||||||
const menu = { menuId: 0, menuName: "主类目", children: [] };
|
menuList.value = proxy.handleTree(response.data, "menuId");
|
||||||
menu.children = proxy.handleTree(response.data, "menuId");
|
loading.value = false;
|
||||||
menuOptions.value.push(menu);
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
/** 查询菜单下拉树结构 */
|
||||||
/** 取消按钮 */
|
function getTreeselect() {
|
||||||
function cancel() {
|
menuOptions.value = [];
|
||||||
open.value = false;
|
listMenu().then(response => {
|
||||||
reset();
|
const menu = { menuId: 0, menuName: "主类目", children: [] };
|
||||||
}
|
menu.children = proxy.handleTree(response.data, "menuId");
|
||||||
|
menuOptions.value.push(menu);
|
||||||
/** 表单重置 */
|
});
|
||||||
function reset() {
|
}
|
||||||
form.value = {
|
|
||||||
menuId: undefined,
|
/** 取消按钮 */
|
||||||
parentId: 0,
|
function cancel() {
|
||||||
menuName: undefined,
|
open.value = false;
|
||||||
icon: undefined,
|
reset();
|
||||||
menuType: "M",
|
}
|
||||||
orderNum: undefined,
|
|
||||||
isFrame: "1",
|
/** 表单重置 */
|
||||||
isCache: "0",
|
function reset() {
|
||||||
visible: "0",
|
form.value = {
|
||||||
status: "0"
|
menuId: undefined,
|
||||||
};
|
parentId: 0,
|
||||||
proxy.resetForm("menuRef");
|
menuName: undefined,
|
||||||
}
|
icon: undefined,
|
||||||
|
menuType: "M",
|
||||||
/** 展示下拉图标 */
|
orderNum: undefined,
|
||||||
function showSelectIcon() {
|
isFrame: "1",
|
||||||
iconSelectRef.value.reset();
|
isCache: "0",
|
||||||
}
|
visible: "0",
|
||||||
|
status: "0"
|
||||||
/** 选择图标 */
|
};
|
||||||
function selected(name) {
|
proxy.resetForm("menuRef");
|
||||||
form.value.icon = name;
|
}
|
||||||
}
|
|
||||||
|
/** 展示下拉图标 */
|
||||||
/** 搜索按钮操作 */
|
function showSelectIcon() {
|
||||||
function handleQuery() {
|
iconSelectRef.value.reset();
|
||||||
getList();
|
}
|
||||||
}
|
|
||||||
|
/** 选择图标 */
|
||||||
/** 重置按钮操作 */
|
function selected(name) {
|
||||||
function resetQuery() {
|
form.value.icon = name;
|
||||||
proxy.resetForm("queryRef");
|
}
|
||||||
handleQuery();
|
|
||||||
}
|
/** 搜索按钮操作 */
|
||||||
|
function handleQuery() {
|
||||||
/** 新增按钮操作 */
|
getList();
|
||||||
function handleAdd(row) {
|
}
|
||||||
reset();
|
|
||||||
getTreeselect();
|
/** 重置按钮操作 */
|
||||||
if (row != null && row.menuId) {
|
function resetQuery() {
|
||||||
form.value.parentId = row.menuId;
|
proxy.resetForm("queryRef");
|
||||||
} else {
|
handleQuery();
|
||||||
form.value.parentId = 0;
|
}
|
||||||
}
|
|
||||||
open.value = true;
|
/** 新增按钮操作 */
|
||||||
title.value = "添加菜单";
|
function handleAdd(row) {
|
||||||
}
|
reset();
|
||||||
|
getTreeselect();
|
||||||
/** 展开/折叠操作 */
|
if (row != null && row.menuId) {
|
||||||
function toggleExpandAll() {
|
form.value.parentId = row.menuId;
|
||||||
refreshTable.value = false;
|
} else {
|
||||||
isExpandAll.value = !isExpandAll.value;
|
form.value.parentId = 0;
|
||||||
nextTick(() => {
|
}
|
||||||
refreshTable.value = true;
|
open.value = true;
|
||||||
});
|
title.value = "添加菜单";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 展开/折叠操作 */
|
||||||
async function handleUpdate(row) {
|
function toggleExpandAll() {
|
||||||
reset();
|
refreshTable.value = false;
|
||||||
await getTreeselect();
|
isExpandAll.value = !isExpandAll.value;
|
||||||
getMenu(row.menuId).then(response => {
|
nextTick(() => {
|
||||||
form.value = response.data;
|
refreshTable.value = true;
|
||||||
open.value = true;
|
});
|
||||||
title.value = "修改菜单";
|
}
|
||||||
});
|
|
||||||
}
|
/** 修改按钮操作 */
|
||||||
|
async function handleUpdate(row) {
|
||||||
/** 提交按钮 */
|
reset();
|
||||||
function submitForm() {
|
await getTreeselect();
|
||||||
proxy.$refs["menuRef"].validate(valid => {
|
getMenu(row.menuId).then(response => {
|
||||||
if (valid) {
|
form.value = response.data;
|
||||||
if (form.value.menuId != undefined) {
|
open.value = true;
|
||||||
updateMenu(form.value).then(response => {
|
title.value = "修改菜单";
|
||||||
proxy.$modal.msgSuccess("修改成功");
|
});
|
||||||
open.value = false;
|
}
|
||||||
getList();
|
|
||||||
});
|
/** 提交按钮 */
|
||||||
} else {
|
function submitForm() {
|
||||||
addMenu(form.value).then(response => {
|
proxy.$refs["menuRef"].validate(valid => {
|
||||||
proxy.$modal.msgSuccess("新增成功");
|
if (valid) {
|
||||||
open.value = false;
|
if (form.value.menuId != undefined) {
|
||||||
getList();
|
updateMenu(form.value).then(response => {
|
||||||
});
|
proxy.$modal.msgSuccess("修改成功");
|
||||||
}
|
open.value = false;
|
||||||
}
|
getList();
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
addMenu(form.value).then(response => {
|
||||||
/** 删除按钮操作 */
|
proxy.$modal.msgSuccess("新增成功");
|
||||||
function handleDelete(row) {
|
open.value = false;
|
||||||
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
|
getList();
|
||||||
return delMenu(row.menuId);
|
});
|
||||||
}).then(() => {
|
}
|
||||||
getList();
|
}
|
||||||
proxy.$modal.msgSuccess("删除成功");
|
});
|
||||||
}).catch(() => {});
|
}
|
||||||
}
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
getList();
|
function handleDelete(row) {
|
||||||
</script>
|
proxy.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
|
||||||
|
return delMenu(row.menuId);
|
||||||
|
}).then(() => {
|
||||||
|
getList();
|
||||||
|
proxy.$modal.msgSuccess("删除成功");
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
getList();
|
||||||
|
</script>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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" />
|
||||||
|
|||||||
@ -142,88 +142,91 @@
|
|||||||
|
|
||||||
<div :style="containerHeight">
|
<div :style="containerHeight">
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
height="100%"
|
height="100%"
|
||||||
:data="projectList"
|
:data="projectList"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
|
||||||
<el-table-column label="项目ID" align="center" prop="projectId" width="150" show-overflow-tooltip />
|
|
||||||
<el-table-column label="项目名称" align="center" prop="projectName" width="150" show-overflow-tooltip />
|
|
||||||
<el-table-column label="测试人员" align="center" prop="tester" />
|
|
||||||
<el-table-column
|
|
||||||
label="计划测试开始时间"
|
|
||||||
align="center"
|
|
||||||
prop="planStart"
|
|
||||||
width="180"
|
|
||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<span>{{ parseTime(row.planStart) }}</span>
|
<el-table-column label="项目ID" align="center" prop="projectId" width="150" show-overflow-tooltip />
|
||||||
</template>
|
<el-table-column label="项目名称" align="center" prop="projectName" width="150" show-overflow-tooltip />
|
||||||
</el-table-column>
|
<el-table-column label="测试人员" align="center" prop="tester" />
|
||||||
<el-table-column label="计划测试结束时间" align="center" prop="planEnd" width="180">
|
<el-table-column
|
||||||
<template #default="{ row }">
|
label="计划测试开始时间"
|
||||||
<span>{{ parseTime(row.planEnd) }}</span>
|
align="center"
|
||||||
</template>
|
prop="planStart"
|
||||||
</el-table-column>
|
width="180"
|
||||||
<el-table-column label="项目描述" width="200" show-overflow-tooltip align="center" prop="description" />
|
>
|
||||||
<el-table-column label="样品名称" align="center" prop="sampleName" width="150" show-overflow-tooltip />
|
<template #default="{ row }">
|
||||||
<el-table-column label="商标" align="center" prop="trademark" width="150" show-overflow-tooltip />
|
<span>{{ parseTime(row.planStart) }}</span>
|
||||||
<el-table-column label="型号规格" align="center" prop="modelSpec" width="150" show-overflow-tooltip />
|
</template>
|
||||||
<el-table-column label="数量" align="center" prop="quantity" />
|
</el-table-column>
|
||||||
<el-table-column label="项目状态" align="center" prop="status">
|
<el-table-column label="计划测试结束时间" align="center" prop="planEnd" width="180">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ row.status == 0 ? '已执行': '未执行' }}
|
<span>{{ parseTime(row.planEnd) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" width="300px" class-name="small-padding fixed-width" fixed="right">
|
<el-table-column label="项目描述" width="200" show-overflow-tooltip align="center" prop="description" />
|
||||||
<template #default="{ row }">
|
<el-table-column label="样品名称" align="center" prop="sampleName" width="150" show-overflow-tooltip />
|
||||||
<el-button
|
<el-table-column label="商标" align="center" prop="trademark" width="150" show-overflow-tooltip />
|
||||||
size="mini"
|
<el-table-column label="型号规格" align="center" prop="modelSpec" width="150" show-overflow-tooltip />
|
||||||
type="text"
|
<el-table-column label="数量" align="center" prop="quantity" />
|
||||||
@click="handleSetting(row)"
|
<el-table-column label="项目状态" align="center" prop="status">
|
||||||
>配置
|
<template #default="{ row }">
|
||||||
</el-button>
|
{{ row.status == 0 ? '已执行': '未执行' }}
|
||||||
<el-button
|
</template>
|
||||||
size="mini"
|
</el-table-column>
|
||||||
type="text"
|
<el-table-column label="操作" align="center" width="300px" class-name="small-padding fixed-width" fixed="right">
|
||||||
v-if="row.status == 1"
|
<template #default="{ row }">
|
||||||
@click="handleExecute(row)"
|
<el-button
|
||||||
>执行
|
size="mini"
|
||||||
</el-button>
|
type="text"
|
||||||
<el-button
|
@click="handleSetting(row)"
|
||||||
icon="DataLine"
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
v-if="row.status == 0"
|
>配置
|
||||||
link
|
</el-button>
|
||||||
type="primary"
|
<el-button
|
||||||
@click="handleOpenDashboard(row)"
|
size="mini"
|
||||||
>可视化
|
type="text"
|
||||||
</el-button>
|
v-if="row.status == 1"
|
||||||
<el-button
|
@click="handleExecute(row)"
|
||||||
size="mini"
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
type="text"
|
>执行
|
||||||
@click="handleUpdate(row)"
|
</el-button>
|
||||||
v-hasPermi="['system:project:edit']"
|
<el-button
|
||||||
>修改</el-button
|
icon="DataLine"
|
||||||
>
|
v-if="row.status == 0"
|
||||||
<el-button
|
link
|
||||||
size="mini"
|
type="primary"
|
||||||
type="text"
|
v-hasPermi="['system:project:add','system:project:edit']"
|
||||||
@click="handleDelete(row)"
|
@click="handleOpenDashboard(row)"
|
||||||
v-hasPermi="['system:project:remove']"
|
>可视化
|
||||||
>删除</el-button
|
</el-button>
|
||||||
>
|
<el-button
|
||||||
</template>
|
size="mini"
|
||||||
</el-table-column>
|
type="text"
|
||||||
</el-table>
|
@click="handleUpdate(row)"
|
||||||
|
v-hasPermi="['system:project:edit']"
|
||||||
|
>修改</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
@click="handleDelete(row)"
|
||||||
|
v-hasPermi="['system:project:remove']"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
<pagination
|
<pagination
|
||||||
v-show="total > 0"
|
v-show="total > 0"
|
||||||
:total="total"
|
:total="total"
|
||||||
:page.sync="queryParams.pageNum"
|
:page.sync="queryParams.pageNum"
|
||||||
:limit.sync="queryParams.pageSize"
|
:limit.sync="queryParams.pageSize"
|
||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 添加或修改语料库对话框 -->
|
<!-- 添加或修改语料库对话框 -->
|
||||||
|
|||||||
@ -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