239 lines
5.4 KiB
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>
|