Files
bigscreenWeb/src/components/tree/systemTree.vue
2025-10-11 09:54:24 +08:00

373 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div class="textInput">
<el-input v-model="filterText" placeholder="请输入内容" clearable maxlength="10" show-word-limit @input="change"
size="small">
<template #prefix>
<el-link :icon="Search"></el-link>
</template>
</el-input>
</div>
<!-- :check-strictly="true"
:check-on-click-node="true"
:expand-on-click-node="false" 点击三角标的时候展开点击文字不展开-->
<el-tree class="treeSet" ref="treeRef" show-checkbox :props="defaultProps" highlight-current
:filter-node-method="filterNode" node-key="id" :data="dataTree" v-bind="$attrs"
:default-expanded-keys="expandedKeys">
<template #default="{ node, data }">
<el-radio-group v-model="totalId" v-if="data.level == 6" @click.stop="changeRadio(data)">
<el-radio :value="data.id"></el-radio>
</el-radio-group>
<div class="custom-tree-node">
<div>
<el-link v-if="data.level == -1" style="color: #0a73ff" :icon="HomeFilled"></el-link>
<el-link v-if="data.level == 0" style="color: #0a73ff" :icon="CollectionTag"></el-link>
<el-link v-if="data.level == 2" style="color: #0a73ff" :icon="Flag"></el-link>
<el-link v-if="data.level == 3" style="color: #0a73ff" :icon="Guide"></el-link>
<el-link v-if="data.level == 7" style="color: #0a73ff" :icon="OfficeBuilding"></el-link>
<el-link v-if="data.level == 6"
:style="{ color: data.comFlag == 0 ? 'red' : data.comFlag == 1 ? '#0a73ff' : 'gray' }"
:icon="Location">
</el-link>
<span style="margin-left: 4px">{{ node.label }}</span>
</div>
</div>
</template>
</el-tree>
</div>
<div class="legend-group">
<!-- 第一个图例正方形 + 谐波 -->
<div class="legend-item ml30">
<div class="icon-square"></div>
<span>用采用户</span>
</div>
<!-- 第二个图例圆形 + 背景 -->
<div class="legend-item">
<div class="icon-circle"></div>
<span>背景谐波用户</span>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, computed, nextTick } from "vue";
import { ElTree } from "element-plus";
import {
Search,
HomeFilled,
CollectionTag,
Flag,
OfficeBuilding,
Location,
Guide,
} from "@element-plus/icons-vue";
import { getTerminalTreeForFive } from "@/api/manage_wx";
import { useStore } from "vuex";
const totalId = ref('');
const store = useStore();
const filterText = ref("");
const defaultProps = {
label: "name",
value: "id",
disabled: 'disabled',
};
const treeRef = ref();
const dataTree = ref([]);
const expandedKeys = ref([]);
const emit = defineEmits(["init"]);
const currentNodeKey = ref<string | number>("");
const specialCharsPattern =
/[`~!@$%^&*\-+=<>?:"{}|,.\/;'\\[\]·~@¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、~]/g;
const change = (val) => {
if (specialCharsPattern.test(val)) {
ElMessage.warning("禁止输入特殊字符!");
filterText.value = val.replace(
/[`~!@$%^&*\-+=<>?:"{}|,.\/;'\\[\]·~@¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、~]/g,
""
);
treeRef.value!.filter(filterText.value);
} else {
treeRef.value!.filter(filterText.value);
}
};
const filterNode = (value: string, data: any, node: any) => {
if (!value) return true;
// return data.name.includes(value)
if (data.name) {
return chooseNode(value, data, node);
}
};
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
return true;
}
const level = node.level;
// 如果传入的节点本身就是一级节点就不用校验了
if (level === 1) {
return false;
}
// 先取当前节点的父节点
let parentData = node.parent;
// 遍历当前节点的父节点
let index = 0;
while (index < level - 1) {
// 如果匹配到直接返回此处name值是中文字符enName是英文字符。判断匹配中英文过滤
if (parentData.data.name.indexOf(value) !== -1) {
return true;
}
// 否则的话再往上一层做匹配
parentData = parentData.parent;
index++;
}
// 没匹配到返回false
return false;
};
const classificationData = ref([]);
const formData = ref({
deptIndex: store.state.deptId,
});
const nodeTreeCopy: any = ref({})
// 点击单选
const changeRadio = (data) => {
// 恢复原来禁用状态
if (nodeTreeCopy.value.disabled) {
nodeTreeCopy.value.disabled = false
}
setTimeout(() => {
data.disabled = true;
nodeTreeCopy.value = data
}, 0)
// 取消选中
const currentChecked = treeRef.value.getCheckedKeys(true);
const newChecked = currentChecked.filter(id => id !== data.id);
console.log("🚀 ~ changeRadio ~ newChecked:", newChecked)
treeRef.value.setCheckedKeys(newChecked);
};
const loadData = () => {
let form = JSON.parse(JSON.stringify(formData.value));
getTerminalTreeForFive(form).then((res) => {
console.log(res);
res.data = [
{
name: "电网拓扑",
level: -1,
id: 0,
children: res.data,
},
];
// expandedKeys.value = [res.data[0].id];
// 查找第一层级的最后一个子节点
const firstLevelChildren = res.data[0].children;
if (firstLevelChildren && firstLevelChildren.length > 0) {
let flag = true;
// 设置节点别名
res.data.forEach((item: any) => {
item.children.forEach((item2: any) => {
item2.children.forEach((item3: any) => {
item3.children.forEach((item4: any) => {
item4.children.forEach((item5: any) => {
if (item5.level == 7) {
item5.children.forEach((item6: any) => {
item6.disabled = false
item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`;
});
} else {
if (flag) {
expandedKeys.value = [item5.id];
treeRef.value.setCurrentKey(item5.id);
emit("init", item5);
flag = false
}
item5.disabled = false
item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`;
}
});
});
});
});
});
}
dataTree.value = res.data;
});
};
loadData();
</script>
<style scoped lang="scss">
.cn-tree {
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
height: 100%;
width: 100%;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.menu-collapse {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;
}
.textInput {
display: flex;
align-items: center;
// height: 30px;
padding: 5px;
background-color: rgba(44, 46, 60);
}
.treeSet {
height: 690px;
overflow-y: auto;
background-color: rgba(44, 46, 60);
color: #fff;
}
/* 图例容器:横向排列、居中对齐 */
.legend-group {
background-color: rgba(44, 46, 60);
padding: 5px;
color: #fff;
display: flex;
/* 两个图例之间的间距 */
align-items: center;
/* 单个图例:固定宽度 150px、横向布局 */
.legend-item {
width: 120px;
display: flex;
align-items: center;
gap: 8px;
// margin-left: 40px;
/* 图标与文字间距 */
font-size: 14px;
}
/* 正方形图标样式 */
.icon-square {
width: 12px;
height: 12px;
background-color: #fff;
/* 蓝色示例色,可自行修改 */
}
/* 圆形图标样式 */
.icon-circle {
width: 12px;
height: 12px;
border-radius: 50%;
/* 圆形关键属性 */
background-color: #fff;
/* 绿色示例色,可自行修改 */
}
}
// 悬浮时的样式
:deep(.el-tree-node__content:hover) {
background-color: #0a73ff70 !important;
color: #fff !important;
.custom-tree-node {
color: #fff !important;
}
.el-link {
color: #fff !important;
}
// 添加更具体的选择器来覆盖默认样式
span {
color: #fff !important;
}
}
:deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: #0a73ff70 !important;
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: #0a73ff70 !important;
color: #fff !important;
.custom-tree-node {
color: #fff !important;
}
.el-link {
color: #fff !important;
}
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
:deep(.el-radio__input.is-checked .el-radio__inner) {
background: #DAA520;
border-color: #DAA520;
}
:deep(.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner) {
background-color: #63636380;
border-color: #63636380;
}
:deep(.el-checkbox__input.is-disabled .el-checkbox__inner) {
background-color: #63636380;
border-color: #63636380;
}
</style>