<template> <vue3-tree-vue dir="ltr" :items="treeItems" :isCheckable="false" :hideGuideLines="false" @onCheck="onItemChecked" @dropValidator="onBeforeItemDropped" @onSelect="onClick" @onExpand="onItemExpanded" > <!-- Applying some simple styling to tree-items --> <template v-slot:item-prepend-icon="treeViewItem"> <!-- :src="prependIcon(treeViewItem)" --> <!-- <img src="assets/common/img/vue3-treevue/folder.svg" alt="folder" height="20" width="20" /> --> <svg class="icon icon-folder-2"> <use xlink:href="#icon-folder-2"></use> </svg> </template> </vue3-tree-vue> </template> <script> import "vue3-tree-vue/dist/style.css"; // remember to add this in your component or maint.[ts/js] import { mapState } from "pinia"; import entityApi from "~/apis/entityApi"; import { useCommonStore } from "~/stores/commonStore"; export default { props: { treeItems: { default() { return []; }, }, }, watch: { treeItems(newVal) { this.dicTreePath = {}; this.rootTreeItems.children = newVal; // this.rootTreeItems.children.forEach((element) => { // this.dicTreePath[element.keyId] = "" + element.index; // }); }, }, data() { return { dicTreePath: {}, rootTreeItems: [ { name: "Rejection Emails", type: "emails", expanded: true, children: [ { name: "List of Rejection Emails", type: "excel", }, { name: "Handling Rejection Through Open-sourcing User Guide", type: "doc", }, { name: "Leet Code Tracking Sheet", type: "folder", expanded: true, children: [ { name: "Solved Problems (30)", type: "excel", }, { name: "Unsolved Problems (5000)", type: "folder", id: 6, expanded: true, children: [ { name: "Inverting a linked list (lol)", id: 7, type: "playlist", }, { name: "Decoding hieroglyphs", id: 8, type: "playlist", children: [ { name: "List of Rejection Emails", id: 24334, type: "excel", }, { name: "Handling Rejection Through Open-sourcing User Guide", id: 354545, type: "doc", }, ], }, ], }, ], }, ], }, { name: "System Design Playlist", id: 993029302938, type: "playlist", children: [ { name: "Space Station Design", id: 10, type: "playlist", }, { name: "Gabbage Collector Design", id: 11, type: "playlist", }, { name: "Design Extra-Terrestrial Life Support", type: "playlist", id: 12, }, ], }, { name: "Lazyloaded", id: 389813, type: "playlist", disabled: true, }, ], dicTreePath: {}, }; }, computed: { ...mapState(useCommonStore, ["paginationGetter"]), }, methods: { // new tree methods. onItemChecked(checkedItems) { console.log(checkedItems); }, onItemSelected(item) { console.log(item); }, onBeforeItemDropped(droppedItem, dropHost) { // dropHost == undefined means dropping at the root of the tree. // Here you can specify any kind of drop validation you will like. // this function should return true if the drop operation is valid. if (dropHost.type !== playlist) return false; return true; }, onItemExpanded(expandedItem) { console.log(expandedItem); //to use this feature properly you need to set lazyLoad property as true //fetch data // const lazyLoadedItems = fetchFromApi(...); // expandedItem.children.push(...lazyLoadedItems) }, // old tree methods. /** * حذف یک نود. * این متد یک نود را حذف میکند. * * @param {HTMLElement} node - نودی که قرار است حذف شود */ onDel(node) { node.remove(); }, /** * تغییر نام. * این متد نام یک مورد را تغییر میدهد. * * @param {object} params - پارامترهای مورد نیاز */ onChangeName(params) {}, /** * افزودن یک نود جدید. * * @param {object} params - پارامترهای مورد نیاز */ onAddNode(params) {}, /** * رویداد کلیک. * این متد وظیفه اعمال تغییرات پس از کلیک را دارد. * * @param {object} params - پارامترهای مورد نیاز */ onClick(params) { if (this.classId !== "") { let id = document.getElementById(this.classId); if (id) id.classList.remove("selected"); const element = document.getElementById(params.id); if (element) element.classList.add("selected"); } else { const element = document.getElementById(params.id); if (element) element.classList.add("selected"); } this.classId = structuredClone(params.id); this.$emit("on-click", params); }, /** * اضافه کردن یک نود جدید. * * @param {object} item - مورد جدید برای افزودن */ addNode(item) { var node = new TreeNode({ item: item, isLeaf: false }); if (!this.rootTreeItems.children) this.rootTreeItems.children = []; this.rootTreeItems.addChildren(node); }, /** * بهروزرسانی فرزندان. * این متد فرزندان یک المان را بهروزرسانی میکند. * * @param {object} element - المانی که فرزندانش باید بهروز شود * @param {array} childs - فرزندان جدید */ updateChildren(element, childs) { var parent = this.rootTreeItems; if (element.parent != null) parent = element.parent; const index = parent.children.findIndex((item) => item.id === element.id); if (index !== -1) { parent.children[index].children = childs; } }, /** * دریافت درخت جدید. * این متد یک درخت جدید از دادههای فعلی دریافت میکند. */ getNewTree() { var vm = this; function _dfs(oldNode) { var newNode = {}; for (var k in oldNode) { if (k !== "children" && k !== "parent") { newNode[k] = oldNode[k]; } } if (oldNode.children && oldNode.children.length > 0) { newNode.children = []; for (var i = 0, len = oldNode.children.length; i < len; i++) { newNode.children.push(_dfs(oldNode.children[i])); } } return newNode; } vm.newTree = _dfs(vm.rootTreeItems); }, }, // components: { // VJstree, // VJstree: () => import("vue-jstree"), // }, }; </script> <style lang="scss"> .icon-tree { color: #dbc056; font-size: 0.6rem; } .vtl-node-main { padding: 5px 1rem 5px 0 !important; .vtl-node-content { // margin-right: 7px; } &.vtl-drag-disabled { // background-color: #d0cfcf; background-color: inherit !important; } &:hover { cursor: pointer; background-color: #f0f0f0 !important; } .vtl-caret { // margin-left: 0; // margin-right: -1rem; // margin-top: 8px; // transform: rotateY(180deg); } } .vtl-tree-margin { // margin-right: 2em; // margin-left: auto; } .vtl { .vtl-drag-disabled { background-color: #d0cfcf; &:hover { background-color: #d0cfcf; } } .vtl-disabled { background-color: #d0cfcf; } } .vtl { } .tree-icon { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAABgCAMAAABblVsaAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAdRQTFRFAAAAHR0bubm5MzMz////28BW28BW28BW28BW28BW28BW28BW28BWeHh428BW28BW28BW28BWeHh4eHh428BWeHh4eHh4eHh428BW28BW28BW28BW28BW28BW28BWubm5ubm5ubm5dHZ7qKepgIKJXGNwVVdbALq6ALq6ALq6ALq6ALq6ALq6ALq670RE7kRE7kRE70RE70RE70RE70RE7e3tmJmY09PUALq6ALq670RE70RE70RE/Pv77Oztr6/jArW1EL6+3/b2ALq670REhISEAjawAbi47/v7ALq670REgICAALq6fn5+fHx8e3t7IMPD7EREJiYm39/gf3+4ALq670REscS0BAAABAoCfn5+ODg4+CgoAAAA9vX25+fnM6wABAQEpbml/v//8fLx1NPURm1D/Pr709TU/////v7/+/v68PLxOTk5OTk6//3+//7/PT49/v3+//7+Pj4+/f39//3//fz8/fv7/Pv8Nzc3PT09+vn5+vr6/Pr69fP19vb2/Pv7PDw88PHw8vPy8vTy8fLy8fPxOTk5+vr5+Pj59/f39vX19/b3+Pf4+/n6/Pv6dHZ7dXd8dXd8dnh9dnd8dHZ8dXZ7CQ4GCA4GCA4HCA0G1tXEywAAAJx0Uk5TAP////8krf+xKsrRSOT++64W7f9+8/b543tF2u2lE/z9/v//////QI/P79+fIECQ0O/fnyD///8Q/xCP/////0L//zAw//+y/6+v/+D/////Mf///7+//wkWgFr/Jv///0H//////////v///1ta/P9b+/9b+v////8BW/n///r//lr8/////1r9//////////39/Pz8/v4WFxcXHg+V+QAABbNJREFUeJztnM1vG0UYh99xHMVJFTsfFEpRaHFJqFoUoUagBpBaUSQkxAUh0ZRWyiIEJ0BC6glunJA4gcSJA0ECBP8AXPgqStsISCulgNrSuIQDVUlbN6b5ol4vO7t2vOuZ2fU4r+Pd8D5VJ+N9be/o6W9nZ+1NGeDCrObWW40wPtaSYWwisAVSAgk9KIF6UAKxoQTqQQnEhhKoR4wTmPA/LGHXG8QjsM273RSfGlZ330+ZoPW+fcJnoCQKWl+9nXEVjC2Le/YSlMA2U96vtx5Cm2dXluztQ+pNFtjl7jK5KO45EGyBAQlsvsC1bQl9gR3ln+23xF17CE+gt/WDkkDLbVsrsHNZLRA6VgFSjOXFEUjBFhiWwCgITLOFAIEu3dfEEXAogQC9JQgXCKviCKT4BZbPhKZKYGDdfT/L/8fzcgZWZZ+WqV9HEJixzUGfydtGBf6/E5gBWOgvcn/NSiBsboHcIDj+KIENzoGZsr8mJlDs11sPIRrrwMyC4vVoCRT79dZDiPiVCEYCvdsbvRZWE/Fr4W3+lXPfFXEEHPo0RlXfzioqCpAGxv6sc1jxERgNYpzAiEIC9aAEYkMC9aAEYkMC9aAEYoMucJN/MUwJxIYSqAclEBtKoB6UQGwogXpQArGhBOoR4wTuYGxurW9Zc7V1rPsDs4zZlhIX6xwW+ncigQl6gDmcU9WH3frPstrOrd5H83/U1hMj3kfTosCQeoVH8lZ/Hqzf5dUWfisHsP9mwvlmG/LnpfVH2dIWp2OdlFTvu8P76Nrl2vr6BQ46LYNSf97WpDBYC7rAgATu7q30/vlFVn9sbTDL02K1DkFrrxppTKDzjzLK/rrnSi6riGAL70yAg/yr1pR7D23XN2J9OF3tp74WyogCe24qBD7Bf3y7M0CgALpAdQKfKthNqsO5NaDnK7H+dKHaT38plPEE3jmVbVhgKxP4zHXe/vQwbxd+E+v7uqr9xbNCGU3gtlPQuEABhPsD1bcE+uujtj13i+3wtFh/HGDK3bIfYFLYPYLAnG0O7j7J2zgmcK8zx2VWV+y28KtY9yZw6YxQRhEI2e2T3F+E50A1D3bz1hUomwNHOqv9Js2BOd7Jyl9fOQsD3DsQzQQeWuJtZ/qq3d64INafna/2CzNCGWUOzJX9yRfS7kIQzIH+c2DmJE+QsJELaTeCHPlKuhpB2Uoa5ySSy6peb/Mcb2bMAdg605P6QTbE1l6JrK2k8z1T0nplJW1Zp8Ri869EXIaG4cw+W+Os6gl+Nu7+QM6hq6XMwt4ZyfHr8mS+tGVx8Lx4/MLGXQsfts9fZtLq/VFapU9jlPUGiY/AaBDjBEYUEqgHJRAbEqgHJRAbEqgHJRAbEqgHJRAbEqgHJRAbEqgHJRAbEqgHJRAbEqhHcxM4Zv/9XF0+4u6MfYq5z1ajI/AYfFLT8TPGklC01AaPfsHbF9jtzzR2GjHqTKABE5Ktx8AVV/lZy1j7HOwq3lYadASOstXp52NssBapQAOkAsvmVP7gSGr2/ksBBh2B44xZFwZia7CuBBoKf647pT8ucHcxwKB7CL9kJs/Cno/qGW0ckAg0lP4cg0p/jkCwDa4o5sGj6Q/t9hXGZoaW43oiCUpgeeIzAvwFHL9QFmgb3KGI4GtFLhDGPx7dcyuuAgV8Ark5I8xfSAIDBL7OPij3Xp2Pq8DAOdCw3Rmh+QueA4MO4TfY++MA3W3vARyOq0AB3xxo8GZC/eTws3DgSeQ4/x0QsBKTp18uxFVgyFnYqGv+UxkMWca8ydiJ4T74+67vYGglrgIFas7CxkTAc0OvREIW0m8lL2fdm0R3XYyrwKZeC4ddyr1d/t/W2ey/ZlwFCmzkhwnvuL8Jxy4NHo/tSaSlnwe++BDXZybZu3BgM1+JNI0xduDEQcZK3wMEHOjRhj6RxoYE6kEJxIYE6kEJxIYE6kEJxOY/TrEkjkDL/tIAAAAASUVORK5CYII=") !important; } </style> <style lang="scss" scoped> .label { position: relative; background-color: #fafafa; // background-color: #fff; padding: 0.3em; border-radius: 0.5em; margin-left: 1.4em; margin-top: 0.5rem; border: 1px solid #9e00b1; span { position: absolute; top: -0.5em; left: -1.2em; display: -webkit-box; display: -ms-flexbox; display: flex; } } .icon { &:hover { cursor: pointer; } } .muted { color: gray; font-size: 80%; } .tree { text-align: right; } .tree-list-container { .tree-list-content { width: 100%; height: calc(100vh - 20em); overflow-y: auto; } // } } </style>