|
|
|
|
|
<!--
|
|
|
|
|
|
图件的图层树
|
|
|
|
|
|
|
|
|
|
|
|
add by RYG
|
|
|
|
|
|
-->
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="tree-component">
|
|
|
|
|
|
<!-- 加载状态(由父组件控制) -->
|
|
|
|
|
|
<!-- <div v-if="loading" class="loading">
|
|
|
|
|
|
加载中……
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<div class="tree-container">
|
|
|
|
|
|
<div class="operation" v-if="!props.isPopup">
|
|
|
|
|
|
<el-button v-for="(btn, index) in iconButtons" :key="index" class="square-icon-button"
|
|
|
|
|
|
:icon="getNodeIcon(btn.id)" :type="btn.type" :title="btn.title" text @click="() => setLayerStatus(btn.id)" />
|
|
|
|
|
|
<el-divider direction="vertical" />
|
|
|
|
|
|
<el-button class="square-icon-button" :icon="Delete" type="danger" circle title="删除" text
|
|
|
|
|
|
@click="deleteLayer" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 树形结构(使用外部传入的数据) -->
|
|
|
|
|
|
<el-tree ref="treeRef" v-model="selectedKeys" :data="treeData" show-checkbox node-key="id" default-expand-all
|
|
|
|
|
|
:highlight-current="true" :props="defaultProps" placeholder="点击展开加载子节点..." clearable @check="handleCheck"
|
|
|
|
|
|
class="custom-tree">
|
|
|
|
|
|
<template #default="{ node, data }">
|
|
|
|
|
|
<div class="tree-node">
|
|
|
|
|
|
<span class="icon-container">
|
|
|
|
|
|
<!-- <el-icon :size="treeConfig.iconSize" :class="'icon-orange'">
|
|
|
|
|
|
<component :is="data.icon" />
|
|
|
|
|
|
</el-icon> -->
|
|
|
|
|
|
<el-icon v-if="data.status" :size="treeConfig.iconSize" :class="'icon-orange'">
|
|
|
|
|
|
<component :is="getNodeIcon(data.status)" />
|
|
|
|
|
|
</el-icon>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span>{{ node.label }}</span>
|
|
|
|
|
|
<!-- <span v-if="data.count" class="node-count">{{ data.count }}</span> -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-tree>
|
|
|
|
|
|
<div class="popup-operation" v-if="props.isPopup && props.showOper">
|
|
|
|
|
|
<el-button :icon="Finished" @click="handleConfirm" type="primary">确定</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
|
<!-- <div class="actions" v-if="treeData.length">
|
|
|
|
|
|
<el-button type="primary" @click="getSelectedNodes">获取选中项</el-button>
|
|
|
|
|
|
<el-button @click="clearSelection">清空选择</el-button>
|
|
|
|
|
|
</div> -->
|
|
|
|
|
|
<LoadingDialog v-model="loading" ref="loadingRef" :timeout="3000" message="正在加载图层……" @timeout="onTimeout" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, onMounted } from "vue";
|
|
|
|
|
|
import { emitter } from "@/utils/eventBus";
|
|
|
|
|
|
import { ElTree, ElButton } from "element-plus";
|
|
|
|
|
|
import { Hide, Lock, Edit, Delete, Finished } from "@element-plus/icons-vue";
|
|
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
|
|
import { COMMAND, EMIT_COMMAND } from '~/utils/commandTypes'
|
|
|
|
|
|
import { useWebSocket } from '@/composables/useWebSocket'
|
|
|
|
|
|
// 消息提示(自动隐藏)
|
|
|
|
|
|
const { $toastMessage } = useNuxtApp();
|
|
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
|
|
|
|
|
|
const { messages, onMessage, status, send } = useWebSocket();
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
isPopup: { type: Boolean, default: false },
|
|
|
|
|
|
showOper: { type: Boolean, defalut: true },
|
|
|
|
|
|
tokenKey: { type: String, default: 'drawerToken' }
|
|
|
|
|
|
// containerHeight: { type: Number, default: window.innerHeight - 75 }
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// const currentTabTokenKey = computed(() => props.tokenKey);
|
|
|
|
|
|
|
|
|
|
|
|
const currentToken = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
const isPopup = computed(() => {
|
|
|
|
|
|
return props.isPopup;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const iconButtons = [
|
|
|
|
|
|
{ icon: "edit", title: "可编辑", type: "warning", id: 1 },
|
|
|
|
|
|
{ icon: "lock", title: "只读", type: "warning", id: 2 },
|
|
|
|
|
|
{ icon: "hide", title: "隐藏", type: "warning", id: 3 },
|
|
|
|
|
|
// { icon: Delete, title: "删除", type: "danger" },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 树配置
|
|
|
|
|
|
const treeConfig = ref({
|
|
|
|
|
|
fontSize: 13,
|
|
|
|
|
|
iconSize: 13,
|
|
|
|
|
|
nodeHeight: 25,
|
|
|
|
|
|
currentHighlight: true,
|
|
|
|
|
|
showIcons: true,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 树的数据
|
|
|
|
|
|
const treeData = ref([]);
|
|
|
|
|
|
// 加载状态
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
const loadingRef = ref(null);
|
|
|
|
|
|
// 得到的原始图层数据
|
|
|
|
|
|
const sourceData = ref([]);
|
|
|
|
|
|
// 响应式数据
|
|
|
|
|
|
const treeRef = ref(null);
|
|
|
|
|
|
// 选中的节点 ID 数组
|
|
|
|
|
|
const selectedKeys = ref([]);
|
|
|
|
|
|
|
|
|
|
|
|
// 定义选择节点事件
|
|
|
|
|
|
const emit = defineEmits(['selectedChanged']);
|
|
|
|
|
|
|
|
|
|
|
|
// 树形配置(节点唯一标识、标签、子节点字段)
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
|
|
children: "children",
|
|
|
|
|
|
label: "label",
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const unsubscribe = onMessage((data) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!data) return; // 如果没有新消息,直接返回
|
|
|
|
|
|
const json = JSON.parse(data);
|
|
|
|
|
|
const evtType = json.type;
|
|
|
|
|
|
switch (evtType) {
|
|
|
|
|
|
case COMMAND.RELOAD_LAYER:
|
|
|
|
|
|
let layerData = json.data;
|
|
|
|
|
|
showLayers(layerData);
|
|
|
|
|
|
loadingRef.value.close();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const onTimeout = () => {
|
|
|
|
|
|
$toastMessage.error("加载图层超时,请稍后重试!");
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 组装树的数据
|
|
|
|
|
|
const showLayers = (layerData) => {
|
|
|
|
|
|
if (!layerData) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确保layerData是有效的JSON字符串
|
|
|
|
|
|
if (typeof layerData === "string") {
|
|
|
|
|
|
layerData = JSON.parse(layerData);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确保转换后是数组
|
|
|
|
|
|
if (!Array.isArray(layerData)) {
|
|
|
|
|
|
console.error("Invalid layer data format - expected array");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sourceData.value = layerData; // 假设data是树形结构数据
|
|
|
|
|
|
// 创建图层根节点
|
|
|
|
|
|
let layerNodes = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: "Layer:",
|
|
|
|
|
|
pId: "-1",
|
|
|
|
|
|
label: "图层",
|
|
|
|
|
|
open: true,
|
|
|
|
|
|
halfCheck: false,
|
|
|
|
|
|
status: 1,
|
|
|
|
|
|
icon: getNodeIcon(1), // 默认图标为可编辑
|
|
|
|
|
|
children: [],
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
layerNodes[0].children = layerData.map((node) => processNode(node));
|
|
|
|
|
|
|
|
|
|
|
|
treeData.value = layerNodes;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const setLayerStatus = (status) => {
|
|
|
|
|
|
let nodes = getSelectedNodes();
|
|
|
|
|
|
nodes = nodes.filter((node) => node.name !== "图层");
|
|
|
|
|
|
let nCount = nodes.length;
|
|
|
|
|
|
if (nCount === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let strStatus = "10";
|
|
|
|
|
|
if (status === 2) {
|
|
|
|
|
|
strStatus = "11";
|
|
|
|
|
|
} else if (status === 3) {
|
|
|
|
|
|
strStatus = "12";
|
|
|
|
|
|
}
|
|
|
|
|
|
let statusData = "";
|
|
|
|
|
|
for (let i = 0; i < nCount; i++) {
|
|
|
|
|
|
// var imgUrl = iconButtons.value[status].icon;
|
|
|
|
|
|
// nodes[i].status = status;
|
|
|
|
|
|
// treeObj.updateNode(nodes[i]);
|
|
|
|
|
|
editNodeById(treeData.value, nodes[i].id, status);
|
|
|
|
|
|
statusData += strStatus + "|Layer:\\" + nodes[i].fullPath + "\r\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
send(COMMAND.SET_LAYER_STATUS, { layerData: statusData }, getToken());
|
|
|
|
|
|
// 处理图层状态设置逻辑
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const deleteLayer = () => {
|
|
|
|
|
|
let nodes = getSelectedNodes();
|
|
|
|
|
|
nodes = nodes.filter((node) => node.name !== "图层");
|
|
|
|
|
|
let nCount = nodes.length;
|
|
|
|
|
|
if (nCount === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let statusData = "";
|
|
|
|
|
|
for (let i = 0; i < nCount; i++) {
|
|
|
|
|
|
// statusData += (nodes[i].id + ",");
|
|
|
|
|
|
statusData += "Layer:\\" + nodes[i].fullPath + ",";
|
|
|
|
|
|
// treeRef.value.removeNode(nodes[i]);
|
|
|
|
|
|
removeNodeById(treeData.value, nodes[i].id);
|
|
|
|
|
|
}
|
|
|
|
|
|
send(COMMAND.DELETE_LAYER, { layers: statusData, widthChild: 1 }, getToken());
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 删除指定ID的节点
|
|
|
|
|
|
const removeNodeById = (tree, id) => {
|
|
|
|
|
|
for (let i = 0; i < tree.length; i++) {
|
|
|
|
|
|
if (tree[i].id === id) {
|
|
|
|
|
|
const removedNode = tree.splice(i, 1)[0];
|
|
|
|
|
|
return { removed: true, removedNode };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tree[i].children && tree[i].children.length > 0) {
|
|
|
|
|
|
const result = removeNodeById(tree[i].children, id);
|
|
|
|
|
|
if (result.removed) {
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return { removed: false };
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 修改节点的状态
|
|
|
|
|
|
const editNodeById = (tree, id, status) => {
|
|
|
|
|
|
for (let i = 0; i < tree.length; i++) {
|
|
|
|
|
|
if (tree[i].id === id) {
|
|
|
|
|
|
// 在这里可以修改节点的属性
|
|
|
|
|
|
tree[i].status = status;
|
|
|
|
|
|
tree[i].icon = getNodeIcon(status); // 更新图标
|
|
|
|
|
|
return true; // 找到并修改节点,返回true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tree[i].children && tree[i].children.length > 0) {
|
|
|
|
|
|
const found = editNodeById(tree[i].children, id, status);
|
|
|
|
|
|
if (found) {
|
|
|
|
|
|
return true; // 如果在子节点中找到并修改,返回true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false; // 没有找到节点,返回false
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前图件的token
|
|
|
|
|
|
const getToken = () => {
|
|
|
|
|
|
currentToken.value = localStorage.getItem(props.tokenKey);
|
|
|
|
|
|
return currentToken.value || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
|
|
|
|
|
|
getToken();
|
|
|
|
|
|
clearTree();
|
|
|
|
|
|
// send("GetLayers", null, currentToken.value);
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
sourceChanged();
|
|
|
|
|
|
getLayer();
|
|
|
|
|
|
emitter.on(EMIT_COMMAND.SOURCE_CHANGED, sourceChanged);
|
|
|
|
|
|
emitter.on(EMIT_COMMAND.REFRESH_LAYER, getLayer);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const sourceChanged = () => {
|
|
|
|
|
|
clearTree();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getLayer = () => {
|
|
|
|
|
|
send(COMMAND.GET_LAYERS, null, getToken(), currentToken.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getNodeIcon = (status) => {
|
|
|
|
|
|
switch (status) {
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
return Edit;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
return Lock;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
return Hide;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return Edit; // 默认图标
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 递归处理节点和子节点
|
|
|
|
|
|
const processNode = (node) => {
|
|
|
|
|
|
let nodeIcon = getNodeIcon(node.status);
|
|
|
|
|
|
|
|
|
|
|
|
const treeNode = {
|
|
|
|
|
|
id: node.id,
|
|
|
|
|
|
pId: "Layer:", // node.ParentId.toString(),
|
|
|
|
|
|
label: node.name || "",
|
|
|
|
|
|
open: false,
|
|
|
|
|
|
icon: nodeIcon,
|
|
|
|
|
|
status: node.status || 0,
|
|
|
|
|
|
fullPath: node.fullPath || "",
|
|
|
|
|
|
children: [],
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有子节点,递归处理
|
|
|
|
|
|
if (node.children && node.children.length > 0) {
|
|
|
|
|
|
treeNode.children = node.children.map((child) => {
|
|
|
|
|
|
const childNode = processNode(child);
|
|
|
|
|
|
// 确保子节点的pId指向父节点id
|
|
|
|
|
|
childNode.pId = treeNode.id;
|
|
|
|
|
|
return childNode;
|
|
|
|
|
|
});
|
|
|
|
|
|
// 有子节点时默认展开
|
|
|
|
|
|
treeNode.open = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return treeNode;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
|
// emitter.off("ReloadLayer");
|
|
|
|
|
|
clearTree();
|
|
|
|
|
|
unsubscribe();
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.SOURCE_CHANGED);
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.REFRESH_LAYER)
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const clearTree = () => {
|
|
|
|
|
|
treeData.value = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 选中节点事件处理
|
|
|
|
|
|
const handleCheck = (currentNode, checkStatus) => {
|
|
|
|
|
|
selectedKeys.value = checkStatus.checkedKeys;
|
|
|
|
|
|
if (props.isPopup && !props.showOper) {
|
|
|
|
|
|
|
|
|
|
|
|
let statusData = getSelectedLayers();
|
|
|
|
|
|
emit(EMIT_COMMAND.SELECTED_CHANGED, statusData);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取选中的节点
|
|
|
|
|
|
const getSelectedNodes = () => {
|
|
|
|
|
|
// 通过 Tree 实例获取选中节点的完整数据
|
|
|
|
|
|
const selectedNodes = treeRef.value?.getCheckedNodes() || [];
|
|
|
|
|
|
return selectedNodes;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 清空选择
|
|
|
|
|
|
const clearSelection = () => {
|
|
|
|
|
|
treeRef.value?.setCheckedKeys([]);
|
|
|
|
|
|
selectedKeys.value = [];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 确定选择按钮事件
|
|
|
|
|
|
const handleConfirm = () => {
|
|
|
|
|
|
let statusData = getSelectedLayers();
|
|
|
|
|
|
if (statusData === '') {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
emitter.emit(EMIT_COMMAND.SELECTED_LAYER, statusData);
|
|
|
|
|
|
// 得到数据之后清空选择
|
|
|
|
|
|
clearSelection();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取选中的图层
|
|
|
|
|
|
const getSelectedLayers = () => {
|
|
|
|
|
|
let nodes = getSelectedNodes();
|
|
|
|
|
|
nodes = nodes.filter((node) => node.name !== "图层");
|
|
|
|
|
|
let nCount = nodes.length;
|
|
|
|
|
|
if (nCount === 0) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
let statusData = "";
|
|
|
|
|
|
for (let i = 0; i < nCount; i++) {
|
|
|
|
|
|
statusData += nodes[i].fullPath + ",";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return statusData;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
unsubscribe();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.tree-component {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
max-width: 240px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tree-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
/* height: calc(100vh - 75px); */
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
overflow: auto;
|
|
|
|
|
|
/* background: lightblue; */
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
/* background: #2c3e50; */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.operation {
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
padding-top: 5px;
|
|
|
|
|
|
padding-left: 10px;
|
|
|
|
|
|
border: 1px solid #eaeaea;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.popup-operation {
|
|
|
|
|
|
height: 50px;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
padding-top: 10px;
|
|
|
|
|
|
padding-right: 10px;
|
|
|
|
|
|
padding-bottom: 10px;
|
|
|
|
|
|
border-top: 1px solid #eaeaea;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.square-icon-button {
|
|
|
|
|
|
width: 25px;
|
|
|
|
|
|
height: 25px;
|
|
|
|
|
|
padding: 0 !important;
|
|
|
|
|
|
/* 去掉内边距 */
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
/* 设置圆角为4px,若要直角则设为0 */
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.square-icon-button:hover {
|
|
|
|
|
|
color: #ec0a0a;
|
|
|
|
|
|
/* 鼠标悬停时的背景色 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.loading {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
background: #333;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #3498db;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.actions {
|
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 5px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree {
|
|
|
|
|
|
/* 自定义文字大小 */
|
|
|
|
|
|
--tree-font-size: 13px;
|
|
|
|
|
|
--tree-icon-size: 13px;
|
|
|
|
|
|
/* overflow: auto; */
|
|
|
|
|
|
|
|
|
|
|
|
font-size: var(--tree-font-size);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node__content {
|
|
|
|
|
|
height: 25px !important;
|
|
|
|
|
|
transition: background-color 0.2s;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node__content:hover {
|
|
|
|
|
|
background-color: rgba(52, 152, 219, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node__label {
|
|
|
|
|
|
/* font-weight: 300; */
|
|
|
|
|
|
color: #2c3e50;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
margin-left: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node__expand-icon {
|
|
|
|
|
|
font-size: var(--tree-icon-size);
|
|
|
|
|
|
transition: transform 0.3s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node__expand-icon.expanded {
|
|
|
|
|
|
transform: rotate(90deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node.is-current>.el-tree-node__content {
|
|
|
|
|
|
background-color: rgba(52, 152, 219, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.custom-tree .el-tree-node.is-current>.el-tree-node__content .el-tree-node__label {
|
|
|
|
|
|
color: #2980b9;
|
|
|
|
|
|
/* font-weight: 400; */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.icon-container {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-right: 2px;
|
|
|
|
|
|
width: 16px;
|
|
|
|
|
|
height: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.icon-blue {
|
|
|
|
|
|
color: #3498db;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.icon-green {
|
|
|
|
|
|
color: #27ae60;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.icon-orange {
|
|
|
|
|
|
color: #e67e22;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.icon-purple {
|
|
|
|
|
|
color: #9b59b6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.el-tree {
|
|
|
|
|
|
--el-tree-node-hover-bg-color: rgba(52, 152, 219, 0.1);
|
|
|
|
|
|
--el-tree-text-color: #2c3e50;
|
|
|
|
|
|
--el-tree-expand-icon-color: #e4d61b;
|
|
|
|
|
|
/* background: #333; */
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|