Merge branch 'dev' of 192.168.0.100:smart_bench/cmvr-iot-ui into dev
This commit is contained in:
commit
6558135b8e
@ -17,6 +17,14 @@ export function flowExecute(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function flowAction(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/action',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function flowExecuteTrial(data) {
|
export function flowExecuteTrial(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/flow/executeTrial',
|
url: '/flow/executeTrial',
|
||||||
|
|||||||
46
src/api/device/microphone.js
Normal file
46
src/api/device/microphone.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 开始录音
|
||||||
|
export function startMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/start',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停录音
|
||||||
|
export function pauseMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/pause',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复录音
|
||||||
|
export function resumeMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/resume',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止录音
|
||||||
|
export function stopMicrophoneApi(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Microphone/stop',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放音频
|
||||||
|
export function playSpeaker(data) {
|
||||||
|
return request({
|
||||||
|
url: '/api/Speaker/play',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { createWebHistory, createRouter } from "vue-router";
|
import { createWebHistory, createRouter } from "vue-router";
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from "@/layout";
|
import Layout from "@/layout";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: 路由配置项
|
* Note: 路由配置项
|
||||||
@ -92,7 +93,14 @@ export const constantRoutes = [
|
|||||||
name: "灵巧手示教",
|
name: "灵巧手示教",
|
||||||
meta: { title: "灵巧手详情" },
|
meta: { title: "灵巧手详情" },
|
||||||
hidden: true,
|
hidden: true,
|
||||||
},
|
},{
|
||||||
|
path: "microphone/:id",
|
||||||
|
component: () =>
|
||||||
|
import("@/views/device/register/components/Microphone/index.vue"),
|
||||||
|
name: "麦克风示教",
|
||||||
|
meta: { title: "麦克风详情" },
|
||||||
|
hidden: true,
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -127,6 +127,34 @@ export const formatTableData = (arr, data = {}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const addNewEdge = (nodeId) => {
|
export const addNewEdge = (nodeId) => {
|
||||||
|
const { edges } = lf.getGraphData();
|
||||||
|
const ttt = edges.slice(); // 浅拷贝(比 JSON 深拷贝高效 10x+)
|
||||||
|
|
||||||
|
const edgesToDelete = ttt.filter(_edge =>
|
||||||
|
_edge.sourceNodeId === nodeId || _edge.targetNodeId === nodeId
|
||||||
|
);
|
||||||
|
|
||||||
|
edgesToDelete.forEach(edge => lf.deleteEdge(edge.id));
|
||||||
|
|
||||||
|
if (window.addNewEdgeTimer) {
|
||||||
|
clearTimeout(window.addNewEdgeTimer); // 清理上一次未执行的定时器
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addNewEdgeTimer = setTimeout(() => {
|
||||||
|
edgesToDelete.forEach(item => {
|
||||||
|
lf.addEdge({
|
||||||
|
type: "bezier",
|
||||||
|
sourceNodeId: item.sourceNodeId,
|
||||||
|
targetNodeId: item.targetNodeId,
|
||||||
|
sourceAnchorId: item.sourceAnchorId,
|
||||||
|
targetAnchorId: item.targetAnchorId
|
||||||
|
});
|
||||||
|
})
|
||||||
|
delete window.addNewEdgeTimer;
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const newEdge = (nodeId) => {
|
||||||
const { edges } = lf.getGraphData();
|
const { edges } = lf.getGraphData();
|
||||||
const arr = JSON.parse(JSON.stringify(edges))
|
const arr = JSON.parse(JSON.stringify(edges))
|
||||||
arr.forEach(_edge => {
|
arr.forEach(_edge => {
|
||||||
@ -144,6 +172,22 @@ export const addNewEdge = (nodeId) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const initNodeZoom = (modelId, nodeZoom, className, init=false) => {
|
||||||
|
const nodes = document.getElementsByClassName(modelId)
|
||||||
|
if (nodes.length > 0) {
|
||||||
|
const node = nodes[0]
|
||||||
|
const parent = node.closest(className);
|
||||||
|
if (nodeZoom) {
|
||||||
|
parent.style.width = '680px'
|
||||||
|
} else {
|
||||||
|
parent.style.width = '380px'
|
||||||
|
}
|
||||||
|
if (!init) {
|
||||||
|
addNewEdge(modelId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const getInputNumber = (nodeId) => {
|
export const getInputNumber = (nodeId) => {
|
||||||
const data = lf.getGraphData();
|
const data = lf.getGraphData();
|
||||||
let flag = false
|
let flag = false
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
|
||||||
|
|
||||||
<TableSearch
|
<TableSearch
|
||||||
:queryParams="queryParams"
|
:queryParams="queryParams"
|
||||||
:showSearch="showSearch"
|
:showSearch="showSearch"
|
||||||
|
|||||||
225
src/views/device/register/components/Microphone/index.vue
Normal file
225
src/views/device/register/components/Microphone/index.vue
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
<template>
|
||||||
|
<div class="microphone-container">
|
||||||
|
<div class="title">远程麦克风</div>
|
||||||
|
<div class="audiosList" v-if="audiosList.length > 0">
|
||||||
|
<div class="speaker-container">
|
||||||
|
<div class="speaker-title">选择扬声器</div>
|
||||||
|
<el-select v-model="speaker" size="small">
|
||||||
|
<el-option
|
||||||
|
v-for="item in speakerOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item"
|
||||||
|
:value="item"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div class="audioItem" v-for="item in audiosList">
|
||||||
|
<div>{{ item }}</div>
|
||||||
|
<div>
|
||||||
|
<el-button
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="VideoPlay"
|
||||||
|
@click="handlePlay(item)"
|
||||||
|
></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-container">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击开始录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'end'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="startRecording"><Microphone /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击暂停录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'recording'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="pauseRecording"><VideoPause /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击恢复录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus === 'pause'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="recoverRecording"><Mic /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="点击结束录音"
|
||||||
|
placement="top-start"
|
||||||
|
v-if="recordStatus !== 'end'"
|
||||||
|
>
|
||||||
|
<el-icon class="btn" :size="40" @click="stopRecording"><Mute /></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { Microphone, VideoPause, Mute, Mic, VideoPlay } from "@element-plus/icons-vue";
|
||||||
|
import {
|
||||||
|
startMicrophoneApi,
|
||||||
|
pauseMicrophoneApi,
|
||||||
|
resumeMicrophoneApi,
|
||||||
|
stopMicrophoneApi,
|
||||||
|
playSpeaker
|
||||||
|
} from '@/api/device/microphone'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
|
||||||
|
const terminalId = route.query.terminalId
|
||||||
|
const deviceId = route.query.deviceId
|
||||||
|
|
||||||
|
const recordStatus = ref('end');
|
||||||
|
const isRecording = ref(false)
|
||||||
|
const list = []
|
||||||
|
const audiosList = ref([])
|
||||||
|
const speaker = ref('spk1')
|
||||||
|
const speakerOptions = ref(['spk1'])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始录音
|
||||||
|
*/
|
||||||
|
const startRecording = async () => {
|
||||||
|
const fileName = new Date().getTime() + '.wav'
|
||||||
|
isRecording.value = true
|
||||||
|
const res = await startMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId,
|
||||||
|
filePath: `/home/share/record/audios/${terminalId}_${deviceId}_${fileName}`
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'recording'
|
||||||
|
list.push(`${terminalId}_${deviceId}_${fileName}`)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停录音
|
||||||
|
*/
|
||||||
|
const pauseRecording = async () => {
|
||||||
|
const res = await pauseMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'pause'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复录音
|
||||||
|
*/
|
||||||
|
const recoverRecording = async () => {
|
||||||
|
const res = await resumeMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'recording'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束录音
|
||||||
|
*/
|
||||||
|
const stopRecording = async () => {
|
||||||
|
const res = await stopMicrophoneApi({
|
||||||
|
terminalId,
|
||||||
|
deviceId
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
recordStatus.value = 'end'
|
||||||
|
audiosList.value.unshift(list[list.length - 1])
|
||||||
|
}
|
||||||
|
isRecording.value = false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放录音
|
||||||
|
*/
|
||||||
|
const handlePlay = async (audioPath) => {
|
||||||
|
const res = await playSpeaker({
|
||||||
|
terminalId,
|
||||||
|
deviceId: speaker.value,
|
||||||
|
audioPath: `/home/share/record/audios/${audioPath}`
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success('播放成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.microphone-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: 800px;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - 125px);
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
.audiosList {
|
||||||
|
margin: 20px;
|
||||||
|
max-height: 280px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.speaker-container {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.speaker-title {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.audioItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-top: 20px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -378,6 +378,10 @@ function handleControl(row) {
|
|||||||
const fullPath = `${row.deviceModel}/${row.id}`; // 构造路由路径
|
const fullPath = `${row.deviceModel}/${row.id}`; // 构造路由路径
|
||||||
router.push({
|
router.push({
|
||||||
path: fullPath,
|
path: fullPath,
|
||||||
|
query: {
|
||||||
|
terminalId: row.idDeDeviceTerminalConfig,
|
||||||
|
deviceId: row.deviceCode
|
||||||
|
}
|
||||||
}); // 使用路由跳转
|
}); // 使用路由跳转
|
||||||
// intoControlPage(`/${row.deviceModel}`, `${row.id}`)
|
// intoControlPage(`/${row.deviceModel}`, `${row.id}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,80 @@
|
|||||||
<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 circle size="small" @click="deleteNode">
|
|
||||||
<el-icon><Delete /></el-icon>
|
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="input_name_closeBold"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="cancelNodeName"
|
||||||
|
>
|
||||||
|
<el-icon><CloseBold /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subTitle">{{ props.nodeDesc }}</div>
|
<div class="right">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="执行"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button v-if="nodeType && nodeType !=='NONE'" circle @click="execute">
|
||||||
|
<el-icon>
|
||||||
|
<VideoPlay />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="zoomState ? '缩小' : '放大'"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button v-if="showZoom" circle @click="zoom">
|
||||||
|
<el-icon>
|
||||||
|
<ZoomOut v-if="zoomState" />
|
||||||
|
<ZoomIn v-else />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="删除"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button circle @click="deleteNode">
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="subTitle">{{ props.nodeDesc }}</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="js">
|
<script setup lang="js">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { EditPen, Select, CloseBold, Delete } from '@element-plus/icons-vue'
|
import { EditPen, Select, CloseBold, Delete, ZoomOut, ZoomIn, VideoPlay } from '@element-plus/icons-vue'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -57,9 +101,19 @@ const props = defineProps({
|
|||||||
nodeType: {
|
nodeType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
showZoom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
zoomState: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['zoom'])
|
||||||
|
|
||||||
const showTextTitle = ref(true)
|
const showTextTitle = ref(true)
|
||||||
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
const nodeName = ref(props.nodeProperties.name || props.nodeName)
|
||||||
|
|
||||||
@ -98,74 +152,88 @@ const deleteNode = () => {
|
|||||||
lf.deleteNode(props.nodeId);
|
lf.deleteNode(props.nodeId);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const zoom = () => {
|
||||||
|
emits('zoom', !props.zoomState)
|
||||||
|
}
|
||||||
|
|
||||||
|
const execute = () => {
|
||||||
|
const myEvent = new CustomEvent('singleNodeExecution', {
|
||||||
|
bubbles: false, // 是否冒泡(默认 false)
|
||||||
|
cancelable: false, // 是否可被 preventDefault() 取消(默认 false)
|
||||||
|
detail: { ...props.nodeProperties } // 自定义数据(任意类型,通过 event.detail 读取)
|
||||||
|
});
|
||||||
|
document.dispatchEvent(myEvent);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.title__container {
|
.title__container {
|
||||||
.title {
|
.title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.left {
|
img {
|
||||||
display: flex;
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
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 {
|
.text__container {
|
||||||
cursor: pointer;
|
.text__title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.el-button {
|
.text {
|
||||||
border: none;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subTitle {
|
.right {
|
||||||
color: #737a87;
|
cursor: pointer;
|
||||||
font-size: 12px;
|
|
||||||
margin: 8px 0;
|
.el-button {
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subTitle {
|
||||||
|
color: #737a87;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</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,31 +251,31 @@ const handleTypeChange = (index) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cascaderRefs = ref([])
|
const cascaderRefs = ref([]);
|
||||||
const outputRules = reactive({});
|
const outputRules = reactive({});
|
||||||
const cascaderChange = (value, index) => {
|
const cascaderChange = (value, index) => {
|
||||||
const selectedOptions = cascaderRefs.value[index].getCheckedNodes(true);
|
const selectedOptions = cascaderRefs.value[index].getCheckedNodes(true);
|
||||||
formData.nodeParams[index].quote = value
|
formData.nodeParams[index].quote = value;
|
||||||
formData.nodeParams[index].quoteType = selectedOptions[0].data.type
|
formData.nodeParams[index].quoteType = selectedOptions[0].data.type;
|
||||||
}
|
};
|
||||||
|
|
||||||
const addOutputFormItem = () => {
|
const addOutputFormItem = () => {
|
||||||
formData.outputParams.push({
|
formData.outputParams.push({
|
||||||
name: '',
|
name: "",
|
||||||
type: '',
|
type: "",
|
||||||
desc: '',
|
desc: "",
|
||||||
children: []
|
children: [],
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const dynamicForm = ref();
|
const dynamicForm = ref();
|
||||||
const outputFormRef = ref()
|
const outputFormRef = ref();
|
||||||
const setNodeProperties = async () => {
|
const setNodeProperties = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await dynamicForm.value.validate();
|
const result = await dynamicForm.value.validate();
|
||||||
let flag = true
|
let flag = true;
|
||||||
if (outputFormRef.value) {
|
if (outputFormRef.value) {
|
||||||
flag = await outputFormRef.value.validate()
|
flag = await outputFormRef.value.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && flag) {
|
if (result && flag) {
|
||||||
@ -222,6 +284,7 @@ const setNodeProperties = async () => {
|
|||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data,
|
...data,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -286,7 +349,7 @@ const addFormItem = () => {
|
|||||||
|
|
||||||
// 删除顶层表单项
|
// 删除顶层表单项
|
||||||
const deleteTopLevelItem = (fullPath) => {
|
const deleteTopLevelItem = (fullPath) => {
|
||||||
// 从顶层数据开始查找
|
// 从顶层数据开始查找
|
||||||
let currentLevel = formData.outputParams;
|
let currentLevel = formData.outputParams;
|
||||||
|
|
||||||
// 遍历路径(除最后一个索引,因为最后一个是要删除的项)
|
// 遍历路径(除最后一个索引,因为最后一个是要删除的项)
|
||||||
@ -300,6 +363,12 @@ const deleteTopLevelItem = (fullPath) => {
|
|||||||
const lastIndex = fullPath[fullPath.length - 1];
|
const lastIndex = fullPath[fullPath.length - 1];
|
||||||
currentLevel.splice(lastIndex, 1);
|
currentLevel.splice(lastIndex, 1);
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
|
const zoom = (flag) => {
|
||||||
|
nodeZoom.value = flag
|
||||||
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@ -311,8 +380,15 @@ watch(
|
|||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option;
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (props.properties.outputParams && props.properties.outputParams.length > 0) {
|
if (
|
||||||
|
props.properties.outputParams &&
|
||||||
|
props.properties.outputParams.length > 0
|
||||||
|
) {
|
||||||
formData.outputParams = props.properties.outputParams;
|
formData.outputParams = props.properties.outputParams;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -322,6 +398,15 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleInputKeydown = (e) => {
|
||||||
|
// 阻止事件冒泡到 Logic Flow 节点,避免被其事件拦截
|
||||||
|
e.stopPropagation();
|
||||||
|
// 可选:明确放行 Ctrl+V(增强兼容性)
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === "v") {
|
||||||
|
e.returnValue = true; // 允许默认粘贴行为
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
emitter.on("changeNodeState", (data) => {
|
emitter.on("changeNodeState", (data) => {
|
||||||
if (data.nodeId === props.model.id) {
|
if (data.nodeId === props.model.id) {
|
||||||
@ -501,11 +586,11 @@ defineExpose({
|
|||||||
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,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="node__container">
|
<div class="node__container" :class="props.model.id">
|
||||||
<NodeState :state="nodeOperatingStatus">
|
<NodeState :state="nodeOperatingStatus">
|
||||||
<template #input>
|
<template #input>
|
||||||
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
<JsonViewer :value="inputJsonData" copyable boxed sort theme="light" />
|
||||||
@ -25,8 +25,10 @@
|
|||||||
:nodeProperties="props.properties"
|
:nodeProperties="props.properties"
|
||||||
:nodeName="props.properties.name"
|
:nodeName="props.properties.name"
|
||||||
:nodeDesc="props.properties.desc"
|
:nodeDesc="props.properties.desc"
|
||||||
|
:zoom-state="nodeZoom"
|
||||||
|
@zoom="zoom"
|
||||||
/>
|
/>
|
||||||
<div class="input__container">
|
<div class="input__container" v-show="nodeZoom">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="tag"></div>
|
<div class="tag"></div>
|
||||||
@ -42,7 +44,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form__container">
|
<div class="form__container" v-show="nodeZoom">
|
||||||
<el-form
|
<el-form
|
||||||
:inline="true"
|
:inline="true"
|
||||||
:model="formData"
|
:model="formData"
|
||||||
@ -134,8 +136,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted, onUnmounted } from "vue";
|
import { ref, reactive, onMounted, onUnmounted, nextTick } from "vue";
|
||||||
import { getInput } from "@/utils/flow";
|
import { getInput, initNodeZoom } from "@/utils/flow";
|
||||||
import { useFlowStore } from "@/store/modules/flow";
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import { Plus } from "@element-plus/icons-vue";
|
import { Plus } from "@element-plus/icons-vue";
|
||||||
import NodeTitle from "../../components/NodeTitle.vue";
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
@ -183,6 +185,7 @@ const setNodeProperties = async () => {
|
|||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data,
|
...data,
|
||||||
|
zoom: nodeZoom.value
|
||||||
});
|
});
|
||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
@ -228,6 +231,12 @@ const addFormItem = () => {
|
|||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nodeZoom = ref(props?.properties?.zoom ?? true)
|
||||||
|
const zoom = (flag) => {
|
||||||
|
nodeZoom.value = flag
|
||||||
|
initNodeZoom(props.model.id, nodeZoom.value, '.node__box')
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.properties,
|
() => props.properties,
|
||||||
() => {
|
() => {
|
||||||
@ -237,6 +246,9 @@ watch(
|
|||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option;
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
initNodeZoom(props.model.id, props?.properties?.zoom ?? true, '.node__box', true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,119 +1,235 @@
|
|||||||
<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)">
|
|
||||||
<el-icon :size="16" ><Minus /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="withOr">
|
|
||||||
<div class="title">条件</div>
|
|
||||||
<div>
|
|
||||||
<el-select v-model="params.withOr" placeholder="Select" style="width: 240px">
|
|
||||||
<el-option key="and" label="AND" value="and" />
|
|
||||||
<el-option key="or" label="OR" value="or" />
|
|
||||||
</el-select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form__container">
|
|
||||||
<el-row v-for="(property, pIndex) in params.list">
|
|
||||||
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
|
||||||
<el-form-item :label="pIndex === 0 ? '引用变量' : ''" :prop="`nodeParams.${index}.list.${pIndex}.nameType`">
|
|
||||||
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
|
||||||
<el-select v-model="property.nameType" @change="handleTypeChange(index, pIndex)">
|
|
||||||
<el-option label="引用" value="quote" />
|
|
||||||
<el-option label="输入" value="input" />
|
|
||||||
</el-select>
|
|
||||||
<el-form-item v-if="property.nameType === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.name`">
|
|
||||||
<el-input v-model="property.name" placeholder="请输入" clearable />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="property.nameType === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.nameQuote`">
|
|
||||||
<el-cascader v-model="property.nameQuote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="pIndex === 0 ? '选择条件' : ''" :prop="`nodeParams.${index}.list.${pIndex}.condition`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]">
|
|
||||||
<el-select v-model="property.condition">
|
|
||||||
<el-option label="等于" value="equal" />
|
|
||||||
<el-option label="不等于" value="notEqualTo" />
|
|
||||||
<el-option label="为空" value="null" />
|
|
||||||
<el-option label="不为空" value="notNull" />
|
|
||||||
<el-option label="包含" value="include" />
|
|
||||||
<el-option label="不包含" value="notInclude" />
|
|
||||||
<el-option label="大于" value="greaterThan" />
|
|
||||||
<el-option label="大于等于" value="greaterThanOrEqual" />
|
|
||||||
<el-option label="小于" value="lessThan" />
|
|
||||||
<el-option label="小于等于" value="lessThanOrEqual" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="pIndex === 0 ? '比较值' : ''" :prop="`nodeParams.${index}.list.${pIndex}.type`" >
|
|
||||||
<el-select v-model="property.type" @change="handleTypeChange(index, pIndex)">
|
|
||||||
<el-option label="引用" value="quote" />
|
|
||||||
<el-option label="输入" value="input" />
|
|
||||||
</el-select>
|
|
||||||
<el-form-item v-if="property.type === 'input'" :rules="[{ required: true, message: '请输入参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.input`">
|
|
||||||
<el-input v-model="property.input" placeholder="请输入" clearable />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="property.type === 'quote'" :rules="[{ required: true, message: '请选择参数值', trigger: 'blur' }]" :prop="`nodeParams.${index}.list.${pIndex}.quote`">
|
|
||||||
<el-cascader v-model="property.quote" :options="quoteOptions" placeholder="请选择" @visible-change="visibleChange" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="addListItem(index)">
|
|
||||||
<el-icon :size="12" ><Plus /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
<el-button :disabled="flowStore.disableForm" circle size="small" @click="removeListItem(index, pIndex)">
|
|
||||||
<el-icon :size="12" ><Minus /></el-icon>
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
<div class="else" :id="''.concat(props.model.id, '_else')">
|
|
||||||
<div class="space"></div>
|
|
||||||
<div class="title">Else</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-form
|
||||||
|
:inline="true"
|
||||||
|
:model="formData"
|
||||||
|
:rules="rules"
|
||||||
|
ref="dynamicForm"
|
||||||
|
label-position="top"
|
||||||
|
label-width="auto"
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="condition"
|
||||||
|
v-for="(params, index) in formData.nodeParams"
|
||||||
|
:id="params.id"
|
||||||
|
>
|
||||||
|
<div class="title__container">
|
||||||
|
<div class="left">
|
||||||
|
<div class="space"></div>
|
||||||
|
<div class="title">{{ index === 0 ? "If" : "Else If" }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="deleteFormItem(params.id, index)"
|
||||||
|
>
|
||||||
|
<el-icon :size="16"><Minus /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="withOr">
|
||||||
|
<div class="title">条件</div>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="params.withOr"
|
||||||
|
placeholder="Select"
|
||||||
|
style="width: 240px"
|
||||||
|
>
|
||||||
|
<el-option key="and" label="AND" value="and" />
|
||||||
|
<el-option key="or" label="OR" value="or" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form__container">
|
||||||
|
<el-row v-for="(property, pIndex) in params.list">
|
||||||
|
<!-- :prop="`nodeParams.${index}.list.${pIndex}.name`" :rules="[{ required: true, message: '请输入变量名', trigger: 'blur' }]" -->
|
||||||
|
<el-form-item
|
||||||
|
:label="pIndex === 0 ? '引用变量' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.nameType`"
|
||||||
|
>
|
||||||
|
<!-- <el-input v-model="property.name" placeholder="请输入" clearable /> -->
|
||||||
|
<el-select
|
||||||
|
v-model="property.nameType"
|
||||||
|
@change="handleTypeChange(index, pIndex)"
|
||||||
|
>
|
||||||
|
<el-option label="引用" value="quote" />
|
||||||
|
<el-option label="输入" value="input" />
|
||||||
|
</el-select>
|
||||||
|
<el-form-item
|
||||||
|
v-if="property.nameType === 'input'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.name`"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="property.name"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="property.nameType === 'quote'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.nameQuote`"
|
||||||
|
>
|
||||||
|
<el-cascader
|
||||||
|
v-model="property.nameQuote"
|
||||||
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
|
@visible-change="visibleChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="pIndex === 0 ? '选择条件' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.condition`"
|
||||||
|
:rules="[
|
||||||
|
{ required: true, message: '请输入变量名', trigger: 'blur' },
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<el-select v-model="property.condition">
|
||||||
|
<el-option label="等于" value="equal" />
|
||||||
|
<el-option label="不等于" value="notEqualTo" />
|
||||||
|
<el-option label="为空" value="null" />
|
||||||
|
<el-option label="不为空" value="notNull" />
|
||||||
|
<el-option label="包含" value="include" />
|
||||||
|
<el-option label="不包含" value="notInclude" />
|
||||||
|
<el-option label="大于" value="greaterThan" />
|
||||||
|
<el-option label="大于等于" value="greaterThanOrEqual" />
|
||||||
|
<el-option label="小于" value="lessThan" />
|
||||||
|
<el-option label="小于等于" value="lessThanOrEqual" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="pIndex === 0 ? '比较值' : ''"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.type`"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="property.type"
|
||||||
|
@change="handleTypeChange(index, pIndex)"
|
||||||
|
>
|
||||||
|
<el-option label="引用" value="quote" />
|
||||||
|
<el-option label="输入" value="input" />
|
||||||
|
</el-select>
|
||||||
|
<el-form-item
|
||||||
|
v-if="property.type === 'input'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.input`"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="property.input"
|
||||||
|
placeholder="请输入"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="property.type === 'quote'"
|
||||||
|
:rules="[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请选择参数值',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
:prop="`nodeParams.${index}.list.${pIndex}.quote`"
|
||||||
|
>
|
||||||
|
<el-cascader
|
||||||
|
v-model="property.quote"
|
||||||
|
:options="quoteOptions"
|
||||||
|
placeholder="请选择"
|
||||||
|
@visible-change="visibleChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="pIndex === 0 ? '操作' : ''">
|
||||||
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="addListItem(index)"
|
||||||
|
>
|
||||||
|
<el-icon :size="12"><Plus /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
:disabled="flowStore.disableForm"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
@click="removeListItem(index, pIndex)"
|
||||||
|
>
|
||||||
|
<el-icon :size="12"><Minus /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="else" :id="''.concat(props.model.id, '_else')">
|
||||||
|
<div class="space"></div>
|
||||||
|
<div class="title">Else</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
import { nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||||
import NodeTitle from '../../components/NodeTitle.vue'
|
import NodeTitle from "../../components/NodeTitle.vue";
|
||||||
import NodeState from "../../components/NodeState.vue";
|
import NodeState from "../../components/NodeState.vue";
|
||||||
import switchSvg from '../../icon/switch.svg'
|
import switchSvg from "../../icon/switch.svg";
|
||||||
import { v4 as randomUUID } from 'uuid'
|
import { v4 as randomUUID } from "uuid";
|
||||||
import { useFlowStore } from '@/store/modules/flow'
|
import { useFlowStore } from "@/store/modules/flow";
|
||||||
import { Plus, Minus } from '@element-plus/icons-vue'
|
import { Plus, Minus } from "@element-plus/icons-vue";
|
||||||
import { getInput, addNewEdge, removeSwitchEdge } from '@/utils/flow'
|
import { getInput, addNewEdge, removeSwitchEdge } from "@/utils/flow";
|
||||||
import { emitter } from "@/utils/eventBus";
|
import { emitter } from "@/utils/eventBus";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -123,130 +239,137 @@ const props = defineProps({
|
|||||||
nowTime: Number,
|
nowTime: Number,
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['addAnchor', 'removeAnchor', 'bindRef', 'changeAnchor'])
|
const emits = defineEmits([
|
||||||
|
"addAnchor",
|
||||||
|
"removeAnchor",
|
||||||
|
"bindRef",
|
||||||
|
"changeAnchor",
|
||||||
|
]);
|
||||||
|
|
||||||
const switchRef = ref()
|
const switchRef = ref();
|
||||||
const dynamicForm = ref()
|
const dynamicForm = ref();
|
||||||
const flowStore = useFlowStore()
|
const flowStore = useFlowStore();
|
||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
nodeParams: props.properties?.conditions || []
|
nodeParams: props.properties?.conditions || [],
|
||||||
})
|
});
|
||||||
|
|
||||||
const addFormItem = () => {
|
const addFormItem = () => {
|
||||||
const rect = switchRef.value.getBoundingClientRect();
|
const rect = switchRef.value.getBoundingClientRect();
|
||||||
addCondition(rect.height - 60)
|
addCondition(rect.height - 60);
|
||||||
}
|
};
|
||||||
|
|
||||||
const deleteFormItem = (id, index) => {
|
const deleteFormItem = (id, index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
formData.nodeParams.splice(index, 1)
|
formData.nodeParams.splice(index, 1);
|
||||||
emits('removeAnchor', id)
|
emits("removeAnchor", id);
|
||||||
removeSwitchEdge(props.model.id, id)
|
removeSwitchEdge(props.model.id, id);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const quoteOptions = ref([])
|
const quoteOptions = ref([]);
|
||||||
const handleTypeChange = (pIndex, index) => {
|
const handleTypeChange = (pIndex, index) => {
|
||||||
if (formData.nodeParams[pIndex].list[index].type === 'input') {
|
if (formData.nodeParams[pIndex].list[index].type === "input") {
|
||||||
formData.nodeParams[pIndex].list[index].quote = ""
|
formData.nodeParams[pIndex].list[index].quote = "";
|
||||||
} else {
|
} else {
|
||||||
formData.nodeParams[pIndex].list[index].input = ""
|
formData.nodeParams[pIndex].list[index].input = "";
|
||||||
const option = getInput(props.model.id, false)
|
const option = getInput(props.model.id, false);
|
||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addCondition = (height) => {
|
const addCondition = (height) => {
|
||||||
const id = randomUUID().replace(/-/g, '')
|
const id = randomUUID().replace(/-/g, "");
|
||||||
formData.nodeParams.push({
|
formData.nodeParams.push({
|
||||||
id,
|
id,
|
||||||
withOr: 'and',
|
withOr: "and",
|
||||||
list: [{
|
list: [
|
||||||
name: '',
|
{
|
||||||
nameQuote: '',
|
name: "",
|
||||||
nameType: 'input',
|
nameQuote: "",
|
||||||
type: 'input',
|
nameType: "input",
|
||||||
input: '',
|
type: "input",
|
||||||
quote: ''
|
input: "",
|
||||||
}]
|
quote: "",
|
||||||
})
|
},
|
||||||
emits('addAnchor', height, id)
|
],
|
||||||
|
});
|
||||||
|
emits("addAnchor", height, id);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
addNewEdge(props.model.id)
|
addNewEdge(props.model.id);
|
||||||
}, 50)
|
}, 50);
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const addListItem = (pIndex, cIndex) => {
|
const addListItem = (pIndex, cIndex) => {
|
||||||
formData.nodeParams[pIndex].list.push({
|
formData.nodeParams[pIndex].list.push({
|
||||||
name: '',
|
name: "",
|
||||||
nameQuote: '',
|
nameQuote: "",
|
||||||
nameType: 'input',
|
nameType: "input",
|
||||||
type: 'input',
|
type: "input",
|
||||||
input: '',
|
input: "",
|
||||||
quote: ''
|
quote: "",
|
||||||
})
|
});
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const removeListItem = (pIndex, cIndex) => {
|
const removeListItem = (pIndex, cIndex) => {
|
||||||
if (cIndex === 0) {
|
if (cIndex === 0) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
formData.nodeParams[pIndex].list.splice(cIndex, 1)
|
formData.nodeParams[pIndex].list.splice(cIndex, 1);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeFormItemHeight()
|
changeFormItemHeight();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const changeFormItemHeight = () => {
|
const changeFormItemHeight = () => {
|
||||||
formData.nodeParams.forEach(item => {
|
formData.nodeParams.forEach((item) => {
|
||||||
const node = document.getElementById(item.id)
|
const node = document.getElementById(item.id);
|
||||||
emits('changeAnchor', node.offsetTop, item.id)
|
emits("changeAnchor", node.offsetTop, item.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
const node = document.getElementById("".concat(props.model.id, "_else"))
|
const node = document.getElementById("".concat(props.model.id, "_else"));
|
||||||
emits('changeAnchor', node.offsetTop, "".concat(props.model.id, "_else"))
|
emits("changeAnchor", node.offsetTop, "".concat(props.model.id, "_else"));
|
||||||
}
|
};
|
||||||
|
|
||||||
const setNodeProperties = async () => {
|
const setNodeProperties = async () => {
|
||||||
try {
|
try {
|
||||||
const valid = await dynamicForm.value.validate()
|
const valid = await dynamicForm.value.validate();
|
||||||
if (valid) {
|
if (valid) {
|
||||||
const data = toRaw(formData)
|
const data = toRaw(formData);
|
||||||
const properties = lf.getProperties(props.model.id)
|
const properties = lf.getProperties(props.model.id);
|
||||||
lf.setProperties(props.model.id, {
|
lf.setProperties(props.model.id, {
|
||||||
...properties,
|
...properties,
|
||||||
...data
|
...data,
|
||||||
})
|
});
|
||||||
emits('contentChange')
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dynamicForm.value.clearValidate()
|
dynamicForm.value.clearValidate();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const visibleChange = (value) => {
|
const visibleChange = (value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
const option = getInput(props.model.id)
|
const option = getInput(props.model.id);
|
||||||
if (option) {
|
if (option) {
|
||||||
quoteOptions.value = option
|
quoteOptions.value = option;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const nodeOperatingStatus = ref("NORMAL");
|
const nodeOperatingStatus = ref("NORMAL");
|
||||||
const inputJsonData = ref({});
|
const inputJsonData = ref({});
|
||||||
@ -256,22 +379,23 @@ watch(
|
|||||||
() => props.properties,
|
() => props.properties,
|
||||||
() => {
|
() => {
|
||||||
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
if (props.properties.nodeParams && props.properties.nodeParams.length > 0) {
|
||||||
formData.nodeParams = props.properties.nodeParams
|
formData.nodeParams = props.properties.nodeParams;
|
||||||
} else {
|
} else {
|
||||||
if (formData.nodeParams.length === 0) {
|
if (formData.nodeParams.length === 0) {
|
||||||
addCondition(100)
|
addCondition(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
emits('addAnchor', 280, "".concat(props.model.id, "_else"))
|
emits("addAnchor", 280, "".concat(props.model.id, "_else"));
|
||||||
|
|
||||||
emits('bindRef', dynamicForm.value)
|
emits("bindRef", dynamicForm.value);
|
||||||
|
|
||||||
emitter.on("changeNodeState", (data) => {
|
emitter.on("changeNodeState", (data) => {
|
||||||
if (data.nodeId === props.model.id) {
|
if (data.nodeId === props.model.id) {
|
||||||
@ -301,15 +425,12 @@ onMounted(() => {
|
|||||||
emits("contentChange");
|
emits("contentChange");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
emitter.off("changeNodeState");
|
emitter.off("changeNodeState");
|
||||||
emitter.off("contentChange");
|
emitter.off("contentChange");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.node__container {
|
.node__container {
|
||||||
@ -346,8 +467,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@ -397,7 +516,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.form__container) {
|
:deep(.form__container) {
|
||||||
|
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
@ -423,18 +541,18 @@ onUnmounted(() => {
|
|||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
|
|
||||||
.space {
|
.space {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background: rgb(22, 100, 255);
|
background: rgb(22, 100, 255);
|
||||||
border-radius: 0px 4px 4px 0px;
|
border-radius: 0px 4px 4px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,87 +1,92 @@
|
|||||||
<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-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
|
|
||||||
<el-option
|
|
||||||
v-for="dict in sys_normal_disable"
|
|
||||||
:key="dict.value"
|
|
||||||
:label="dict.label"
|
|
||||||
:value="dict.value"
|
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-form-item>
|
||||||
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
||||||
<el-form-item>
|
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 200px">
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-option
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
v-for="dict in sys_normal_disable"
|
||||||
</el-form-item>
|
:key="dict.value"
|
||||||
</el-form>
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
icon="Plus"
|
icon="Plus"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
v-hasPermi="['system:menu:add']"
|
v-hasPermi="['system:menu:add']"
|
||||||
>新增</el-button>
|
>新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="info"
|
type="info"
|
||||||
plain
|
plain
|
||||||
icon="Sort"
|
icon="Sort"
|
||||||
@click="toggleExpandAll"
|
@click="toggleExpandAll"
|
||||||
>展开/折叠</el-button>
|
>展开/折叠</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-table
|
<div :style="containerHeight">
|
||||||
v-if="refreshTable"
|
<el-table
|
||||||
v-loading="loading"
|
v-if="refreshTable"
|
||||||
:data="menuList"
|
height="100%"
|
||||||
row-key="menuId"
|
v-loading="loading"
|
||||||
:default-expand-all="isExpandAll"
|
:data="menuList"
|
||||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
row-key="menuId"
|
||||||
>
|
:default-expand-all="isExpandAll"
|
||||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
>
|
||||||
<template #default="scope">
|
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||||
<svg-icon :icon-class="scope.row.icon" />
|
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<svg-icon :icon-class="scope.row.icon" />
|
||||||
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
</template>
|
||||||
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
<el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
|
||||||
<el-table-column prop="status" label="状态" width="80">
|
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
||||||
<template #default="scope">
|
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
||||||
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
<el-table-column prop="status" label="状态" width="80">
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
|
||||||
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
|
</template>
|
||||||
<template #default="scope">
|
</el-table-column>
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<el-table-column label="创建时间" align="center" width="160" prop="createTime">
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
<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-column label="操作" align="center" width="210" class-name="small-padding fixed-width">
|
||||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['system:menu:add']">新增</el-button>
|
<template #default="scope">
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:menu:remove']">删除</el-button>
|
<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>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 添加或修改菜单对话框 -->
|
<!-- 添加或修改菜单对话框 -->
|
||||||
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
||||||
@ -292,6 +297,10 @@
|
|||||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
||||||
import SvgIcon from "@/components/SvgIcon";
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
import IconSelect from "@/components/IconSelect";
|
import IconSelect from "@/components/IconSelect";
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
||||||
|
|||||||
@ -1,98 +1,101 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<div ref="topContainerRef">
|
||||||
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
|
<el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.roleName"
|
v-model="queryParams.roleName"
|
||||||
placeholder="请输入角色名称"
|
placeholder="请输入角色名称"
|
||||||
clearable
|
clearable
|
||||||
style="width: 240px"
|
style="width: 240px"
|
||||||
@keyup.enter="handleQuery"
|
@keyup.enter="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="权限字符" prop="roleKey">
|
<el-form-item label="权限字符" prop="roleKey">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.roleKey"
|
v-model="queryParams.roleKey"
|
||||||
placeholder="请输入权限字符"
|
placeholder="请输入权限字符"
|
||||||
clearable
|
clearable
|
||||||
style="width: 240px"
|
style="width: 240px"
|
||||||
@keyup.enter="handleQuery"
|
@keyup.enter="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="queryParams.status"
|
v-model="queryParams.status"
|
||||||
placeholder="角色状态"
|
placeholder="角色状态"
|
||||||
clearable
|
clearable
|
||||||
style="width: 240px"
|
style="width: 240px"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in sys_normal_disable"
|
v-for="dict in sys_normal_disable"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
:label="dict.label"
|
:label="dict.label"
|
||||||
:value="dict.value"
|
:value="dict.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px">
|
<el-form-item label="创建时间" style="width: 308px">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="dateRange"
|
v-model="dateRange"
|
||||||
value-format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD"
|
||||||
type="daterange"
|
type="daterange"
|
||||||
range-separator="-"
|
range-separator="-"
|
||||||
start-placeholder="开始日期"
|
start-placeholder="开始日期"
|
||||||
end-placeholder="结束日期"
|
end-placeholder="结束日期"
|
||||||
></el-date-picker>
|
></el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
icon="Plus"
|
icon="Plus"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
v-hasPermi="['system:role:add']"
|
v-hasPermi="['system:role:add']"
|
||||||
>新增</el-button>
|
>新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
plain
|
plain
|
||||||
icon="Edit"
|
icon="Edit"
|
||||||
:disabled="single"
|
:disabled="single"
|
||||||
@click="handleUpdate"
|
@click="handleUpdate"
|
||||||
v-hasPermi="['system:role:edit']"
|
v-hasPermi="['system:role:edit']"
|
||||||
>修改</el-button>
|
>修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
plain
|
plain
|
||||||
icon="Delete"
|
icon="Delete"
|
||||||
:disabled="multiple"
|
:disabled="multiple"
|
||||||
@click="handleDelete"
|
@click="handleDelete"
|
||||||
v-hasPermi="['system:role:remove']"
|
v-hasPermi="['system:role:remove']"
|
||||||
>删除</el-button>
|
>删除</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="warning"
|
type="warning"
|
||||||
plain
|
plain
|
||||||
icon="Download"
|
icon="Download"
|
||||||
@click="handleExport"
|
@click="handleExport"
|
||||||
v-hasPermi="['system:role:export']"
|
v-hasPermi="['system:role:export']"
|
||||||
>导出</el-button>
|
>导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div :style="containerHeight">
|
||||||
<!-- 表格数据 -->
|
<!-- 表格数据 -->
|
||||||
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-table height="100%" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="角色编号" prop="roleId" width="120" />
|
<el-table-column label="角色编号" prop="roleId" width="120" />
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
@ -139,6 +142,8 @@
|
|||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 添加或修改角色配置对话框 -->
|
<!-- 添加或修改角色配置对话框 -->
|
||||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||||
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
|
||||||
@ -244,6 +249,10 @@
|
|||||||
<script setup name="Role">
|
<script setup name="Role">
|
||||||
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
|
import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role";
|
||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu";
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu";
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|||||||
@ -16,86 +16,90 @@
|
|||||||
<!--用户数据-->
|
<!--用户数据-->
|
||||||
<pane size="84">
|
<pane size="84">
|
||||||
<el-col>
|
<el-col>
|
||||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="90px">
|
<div ref="topContainerRef">
|
||||||
<el-form-item label="用户名称啊" prop="userName">
|
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="90px">
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-form-item label="用户名称啊" prop="userName">
|
||||||
</el-form-item>
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
</el-form-item>
|
||||||
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
</el-form-item>
|
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||||
<el-form-item label="状态" prop="status">
|
</el-form-item>
|
||||||
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
|
||||||
</el-select>
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-form-item>
|
</el-select>
|
||||||
<el-form-item label="创建时间" style="width: 308px">
|
</el-form-item>
|
||||||
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
|
<el-form-item label="创建时间" style="width: 308px">
|
||||||
</el-form-item>
|
<el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
|
||||||
<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-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
|
<el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
<div :style="containerHeight">
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
<el-table height="100%" v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
|
||||||
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
|
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
|
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
|
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
|
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
|
||||||
<template #default="scope">
|
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
|
||||||
<el-switch
|
<template #default="scope">
|
||||||
v-model="scope.row.status"
|
<el-switch
|
||||||
active-value="0"
|
v-model="scope.row.status"
|
||||||
inactive-value="0"
|
active-value="0"
|
||||||
@change="handleStatusChange(scope.row)"
|
inactive-value="0"
|
||||||
></el-switch>
|
@change="handleStatusChange(scope.row)"
|
||||||
</template>
|
></el-switch>
|
||||||
</el-table-column>
|
</template>
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
|
</el-table-column>
|
||||||
<template #default="scope">
|
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<template #default="scope">
|
||||||
</template>
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
</el-table-column>
|
</template>
|
||||||
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
</el-table-column>
|
||||||
<template #default="scope">
|
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
||||||
<el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
|
<template #default="scope">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
<el-tooltip content="修改" placement="top" v-if="scope.row.userId !== 1">
|
||||||
</el-tooltip>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
||||||
<el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
|
</el-tooltip>
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
|
<el-tooltip content="删除" placement="top" v-if="scope.row.userId !== 1">
|
||||||
</el-tooltip>
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']"></el-button>
|
||||||
<el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
|
</el-tooltip>
|
||||||
<el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
|
<el-tooltip content="重置密码" placement="top" v-if="scope.row.userId !== 1">
|
||||||
</el-tooltip>
|
<el-button link type="primary" icon="Key" @click="handleResetPwd(scope.row)" v-hasPermi="['system:user:resetPwd']"></el-button>
|
||||||
<el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
|
</el-tooltip>
|
||||||
<el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
<el-tooltip content="分配角色" placement="top" v-if="scope.row.userId !== 1">
|
||||||
</el-tooltip>
|
<el-button link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)" v-hasPermi="['system:user:edit']"></el-button>
|
||||||
</template>
|
</el-tooltip>
|
||||||
</el-table-column>
|
</template>
|
||||||
</el-table>
|
</el-table-column>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
</el-table>
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</pane>
|
</pane>
|
||||||
</splitpanes>
|
</splitpanes>
|
||||||
@ -220,6 +224,11 @@ import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser,
|
|||||||
import { Splitpanes, Pane } from "splitpanes"
|
import { Splitpanes, Pane } from "splitpanes"
|
||||||
import "splitpanes/dist/splitpanes.css"
|
import "splitpanes/dist/splitpanes.css"
|
||||||
|
|
||||||
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
|
|
||||||
|
const topContainerRef = ref();
|
||||||
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<el-table-column prop="value" label="入参值">
|
<el-table-column prop="value" label="入参值">
|
||||||
<template #default="{ row, column, $index }">
|
<template #default="{ row, column, $index }">
|
||||||
<el-form-item v-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`formData.tableData.${pIndex}.config.${row.propPath}.value`" :rules="row.required ? [{ required: true, message: '请输入', trigger: 'blur' }] : []">
|
<el-form-item v-if="row.type !== 'object' && !row.type.includes('array')" label="" :prop="`formData.tableData.${pIndex}.config${row.propPath}value`" :rules="row.required ? [{ required: true, message: '请输入', trigger: 'blur' }] : []">
|
||||||
<el-input v-if="row.type === 'string'" v-model="row.value" />
|
<el-input v-if="row.type === 'string'" v-model="row.value" />
|
||||||
<el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" />
|
<el-input-number v-if="row.type === 'number'" :controls="false" v-model="row.value" />
|
||||||
<el-switch v-if="row.type === 'boolean'" v-model="row.value" />
|
<el-switch v-if="row.type === 'boolean'" v-model="row.value" />
|
||||||
|
|||||||
@ -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