CMVR-IOT-UI/src/views/device/register/components/VueFlow/customFlow.vue

239 lines
5.4 KiB
Vue

<template>
<div class="custom_element" :class="props.properties.state">
<div class="custom_element__header">
<div class="custom_element__title">
{{ props.text || "--" }}
</div>
<el-button v-if="showDetailTypeList.includes(props.properties.type)" v-popover="popoverRef" class="custom_element__btn" link @click="openPop"
>详情</el-button
>
</div>
<div class="nodeType">节点类型: {{ props.properties.type }}</div>
<div class="nodeState">
<div>状态:{{ stateMap[props.properties.state] }}</div>
</div>
<el-popover
ref="popoverRef"
virtual-triggering
persistent
placement="right-start"
:visible="popoverVisible"
popper-class="popover__container"
>
<template #default>
<div class="popover__header">
<div>{{ props.text || "--" }}</div>
<div class="closeBtn" @click="popoverVisible = !popoverVisible">
<el-icon><CircleClose /></el-icon>
</div>
</div>
<div class="popover__context">
<div class="container">
<div class="title">输入参数</div>
<el-input
v-if="getTypeByParams(props.properties.input) === 0"
v-model="props.properties.input"
:readonly="true"
:autosize="{ minRows: 2, maxRows: 6 }"
type="textarea"
/>
<div v-if="getTypeByParams(props.properties.input) === 2">
<el-image
style="width: 200px; height: 100px"
:src="getUrlByParams(props.properties.input)"
:zoom-rate="2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="[getUrlByParams(props.properties.input)]"
show-progress
:initial-index="4"
fit="cover"
/>
</div>
</div>
<div class="container">
<div class="title">输出参数</div>
<el-input
v-if="getTypeByParams(props.properties.output) === 0"
v-model="props.properties.output"
:readonly="true"
:autosize="{ minRows: 2, maxRows: 6 }"
type="textarea"
/>
<div v-if="getTypeByParams(props.properties.output) === 2" class="imageContainer">
<el-image
v-for="item in getUrlByParams(props.properties.output)"
style="width: 60px; height: 60px"
:src="item"
:preview-src-list="getUrlByParams(props.properties.output)"
show-progress
fit="fill"
/>
</div>
<div v-if="getTypeByParams(props.properties.output) === 4" class="videoContainer">
<IPlayer v-for="item in getUrlByParams(props.properties.output)" :videoUrl="item" />
</div>
</div>
</div>
</template>
</el-popover>
</div>
</template>
<script setup>
import { watch } from "vue";
import { CircleClose } from '@element-plus/icons-vue'
import IPlayer from './IPlayer/index.vue'
const props = defineProps({
model: Object,
graphModel: Object,
properties: Object,
text: String,
});
const stateMap = {
success: "已执行",
unexecuted: "未执行",
running: "执行中",
failed: "异常",
paused: "暂停",
stopped: "停止"
};
const showDetailTypeList = ['inject', 'startCamera', 'getImage', 'stopCamera', 'process', 'end', 'stopVideo']
const popoverVisible = ref(false);
const popoverRef = ref();
const openPop = (e) => {
popoverVisible.value = true;
};
const getTypeByParams = (str) => {
let type = 0;
try {
const data = JSON.parse(str);
type = data?.type || 0;
} catch {
type = 0;
}
return type;
};
const propertiesTypeMap = {
'2': 'imageUrl',
'4': 'videoUrl',
'default': ''
}
const getUrlByParams = (str) => {
let url = [];
try {
const data = JSON.parse(str);
url = data?.[propertiesTypeMap[data?.type || 'default']] || 0;
} catch {
url = [];
}
return url;
};
watch(
() => props.properties.nowTime,
() => {
popoverVisible.value = false;
}
);
</script>
<style lang="scss" scoped>
.custom_element {
width: 100%;
height: 100%;
padding: 10px;
border-radius: 10px;
box-sizing: border-box;
color: #fff;
&__header {
display: flex;
justify-content: space-between;
}
&__title {
font-size: 20px;
}
&__btn {
color: skyblue;
}
}
.running, .paused, .stopped {
background-color: #8bbf86;
}
.unexecuted {
background-color: #ddd;
}
.success {
background-color: green;
}
.failed {
background-color: rgb(128, 41, 0);
}
.nodeType {
margin: 8px 0;
}
.nodeState {
margin: 8px 0;
}
</style>
<style lang="scss">
.popover__container {
width: 300px !important;
.popover__header {
display: flex;
justify-content: space-between;
.closeBtn {
cursor: pointer;
}
}
.popover__context {
.container {
display: flex;
max-height: 200px;
overflow-y: auto;
margin-bottom: 10px;
.title {
width: 80px;
}
.imageContainer {
width: 260px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: stretch;
max-height: 600px;
overflow-y: auto;
}
.videoContainer {
width: 260px;
max-height: 600px;
overflow-y: auto;
}
}
}
}
</style>