<template>
|
<div class="site-tree">
|
<div class="site-tree__header">
|
<el-text>{{ t('组织站点树') }}</el-text>
|
<div class="site-tree__op">
|
<div class="item" @click="refresh()">
|
<el-tooltip :content="t('刷新')">
|
<cl-svg name="refresh" />
|
</el-tooltip>
|
</div>
|
</div>
|
</div>
|
|
<div class="site-tree__container">
|
<el-scrollbar>
|
<el-tree
|
v-loading="loading"
|
node-key="a_id"
|
default-expand-all
|
:data="list"
|
:props="{
|
label: 'a_name',
|
children: 'children'
|
}"
|
highlight-current
|
:expand-on-click-node="false"
|
@node-click="rowClick"
|
>
|
<template #default="{ node, data }">
|
<div class="site-tree__node">
|
<span
|
class="site-tree__node-label"
|
:class="{
|
'is-active': data.a_id == selectId
|
}"
|
>
|
{{ node.label }}
|
<span v-if="!/^\d+$/.test(data.a_id)" style="margin-left:6px;color:#67c23a;font-size:12px;">(站点)</span>
|
</span>
|
</div>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
defineOptions({
|
name: 'site-tree'
|
});
|
|
import { ref, nextTick, onMounted } from 'vue';
|
import { ElMessage } from 'element-plus';
|
import { useCool } from '/@/cool';
|
import { useI18n } from 'vue-i18n';
|
|
const emit = defineEmits(['select']);
|
|
const { service } = useCool();
|
const { t } = useI18n();
|
|
// 树形原始列表
|
const list = ref<any[]>([]);
|
const loading = ref(false);
|
const selectId = ref<number | string>();
|
|
function buildTree(source: any[]) {
|
const map = new Map<string, any>();
|
const roots: any[] = [];
|
source.forEach(item => {
|
map.set(item.a_id, { ...item, children: [] });
|
});
|
source.forEach(item => {
|
const node = map.get(item.a_id);
|
if (item.a_parentId && map.has(item.a_parentId)) {
|
map.get(item.a_parentId).children.push(node);
|
} else {
|
roots.push(node);
|
}
|
});
|
return roots;
|
}
|
|
async function refresh() {
|
loading.value = true;
|
try {
|
const res = await service.basicdata.iot.getSitelist();
|
const formatList = res.map(item => ({
|
...item,
|
a_id: String(item.a_id),
|
a_parentId: item.a_parentId === null ? null : String(item.a_parentId)
|
}));
|
list.value = buildTree(formatList);
|
} catch (err) {
|
ElMessage.error('加载树形失败');
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
// 节点点击
|
function rowClick(item: any) {
|
selectId.value = item.a_id;
|
const numReg = /^\d+$/;
|
const isSite = !numReg.test(item.a_id);
|
emit('select', item.a_id);
|
}
|
|
onMounted(() => {
|
refresh();
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.site-tree {
|
height: 100%;
|
width: 100%;
|
|
:deep(.el-tree-node__label) {
|
display: block;
|
height: 100%;
|
width: 100%;
|
}
|
|
&__header {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
height: 40px;
|
padding: 0 10px;
|
border-bottom: 1px solid var(--el-border-color-extra-light);
|
}
|
|
&__op {
|
display: flex;
|
align-items: center;
|
.item {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
margin-left: 5px;
|
cursor: pointer;
|
border-radius: 6px;
|
font-size: 16px;
|
height: 26px;
|
width: 26px;
|
color: var(--el-text-color-primary);
|
&:hover {
|
background-color: var(--el-fill-color-light);
|
}
|
}
|
}
|
|
&__container {
|
height: calc(100% - 40px);
|
padding: 10px;
|
:deep(.el-tree-node__content) {
|
height: 38px;
|
border-radius: 4px;
|
}
|
}
|
|
&__node {
|
display: flex;
|
align-items: center;
|
height: 100%;
|
width: 100%;
|
box-sizing: border-box;
|
&-label {
|
display: flex;
|
align-items: center;
|
flex: 1;
|
height: 100%;
|
font-size: 14px;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
&.is-active {
|
color: var(--el-color-primary);
|
}
|
}
|
}
|
}
|
</style>
|