373 lines
11 KiB
Vue
373 lines
11 KiB
Vue
<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>
|