|
<template>
<div class="dnd-nodes">
<div class="int-box">
<el-input
v-model="filterValue"
class="int"
placeholder="根据节点名称搜索"
@input="searchFilter"
>
<template #suffix>
<el-icon><Search @click.stop="searchFilter"></Search></el-icon>
</template>
</el-input>
</div>
<div class="node-container">
<el-collapse v-model="activeNames">
<template v-for="item in nodeList" :key="item?.name">
<el-collapse-item :name="item.name">
<template #title>
<div class="c-title">{{ item.label }}</div>
</template>
<el-row>
<template v-for="node in item.nodes" :key="node.id">
<el-col :span="8">
<div
:data-id="node.id"
:data-type="node.type"
:data-name="node.name"
:data-label="node.label"
:data-icon="node.icon"
class="ability-item"
@mousedown="startDrag"
>
<common-icon
v-if="item.name !== 'process'"
:name="node.icon"
:size="36"
></common-icon>
<img v-else class="img" :src="node.icon || icon" alt="" />
<span class="title">{{ node.label }}</span>
</div>
</el-col>
</template>
</el-row>
</el-collapse-item>
</template>
</el-collapse>
</div>
</div>
</template>
<script setup>
import { defineProps, ref, computed, watchEffect } from 'vue';
const props = defineProps({
nodes: {
type: Array,
default: () => []
},
dnd: {
type: Array,
default: () => []
},
processDefItemList: {
type: Array,
default: () => []
},
onDragStart: {
type: Function,
default: () => null
}
});
const filterValue = ref('');
const basicNodes = ref([]);
const nodeLists = ref([]);
const nodeList = computed(() => {
const nodes = JSON.parse(JSON.stringify(nodeLists.value));
const val = filterValue.value;
return nodes.reduce((acc, item) => {
if (item.nodes.some((node) => node.label.indexOf(val) > -1)) {
const nodes = item.nodes.filter((node) => node.label.indexOf(val) > -1);
acc.push({ ...item, nodes });
} else if (item.label.indexOf(val) > -1) {
acc.push({ ...item, nodes: [] });
}
return acc;
}, []);
});
const activeNames = computed(() => nodeLists.value.map((item) => item.name));
const formatDnd = (processDefItemList) => {
const nodes = processDefItemList.map((item) => ({
name: 'process',
id: item.assetSpecId,
label: item.assetSpecName,
type: 'process',
icon: item.iconUrl
}));
if (nodes.length) {
nodeLists.value = [
{ label: '资产模型节点', name: 'process', nodes },
...basicNodes.value
];
} else {
nodeLists.value = [...basicNodes.value];
}
};
watchEffect(() => {
basicNodes.value = props.nodes;
formatDnd(props.processDefItemList);
});
const startDrag = (event) => {
const { currentTarget } = event;
// const node = getShapeAttr(event.currentTarget);
const { id, type, name, label, icon } = currentTarget.dataset;
const offsetX = event.clientX - currentTarget.getBoundingClientRect().left;
const offsetY = event.clientY - currentTarget.getBoundingClientRect().top;
props.onDragStart({ id, type, name, label, icon, offsetX, offsetY }, event);
};
</script>
<style lang="scss" scoped>
.dnd-nodes {
width: 260px;
height: calc(100vh - 70px);
overflow: auto;
}
.int-box {
padding: 15px;
}
.c-title {
padding-left: 10px;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
}
:deep(.el-collapse-item__header) {
background: rgba(0, 0, 0, 0.02);
height: 40px;
line-height: 40px;
.el-collapse-item__arrow {
font-size: 18px;
color: #040000;
}
}
.ability-item {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 30px;
cursor: move;
.title {
margin-top: 6px;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
width: 90px;
word-wrap: break-word;
word-break: break-all;
text-align: center;
}
.img {
width: 32px;
height: 32px;
}
}
.node-container {
height: calc(100vh - 134px);
overflow: auto;
}
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar {
width: 5px;
height: 10px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
background-color: #f5f5f5;
}
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
background-color: #c8c8c8;
}
</style>
|