[zTree] Add different operation buttons to the node, and generate a pop-up window after clicking

zTree api documentation: https://www.treejs.cn/v3/api.php

1. Initialization tree configuration items

const initZtreeSetting = () => {<!-- -->
  const setting = {<!-- -->
    view: {<!-- -->
      addHoverDom: addHoverDom, // Display user-defined controls
      selectedMulti: false,//Whether multiple nodes are allowed to be selected at the same time, the default is true
      showIcon: true, //Whether to display the icon of the node, the default is true
    },
    data: {<!-- -->
      simpleData: {<!-- -->//Use simple data mode
        enable: true,
        idKey: 'id',
        pIdKey: 'parentId',
        rootPId: 0,
      },
    },
    callback: {<!-- -->
      onClick: handleNodeClick, // callback function when the node is clicked
      beforeClick: handleNodeBeforeClick, //Callback function before the node is clicked, set whether the node can be clicked
    },
  };
  return setting;
};

2. Customized action buttons

const addHoverDom = (treeId, treeNode) => {<!-- -->
  let addStr = null;
  const add = `<span class='button add' id='btn_add_${<!-- -->treeNode.tId}' title='Add file' οnfοcus='this.blur();'></span >`;
  const addSm = `<span class='button addSm' id='btn_addSm_${<!-- -->treeNode.tId}' title='Add Node' οnfοcus='this.blur();'></span >`;
  const edit = `<span class='button edit' id='btn_edit_${<!-- -->treeNode.tId}' title='Edit' οnfοcus='this.blur();'></span> `;
  const del = `<span class='button remove' id='btn_remove_${<!-- -->treeNode.tId}' title='Delete' οnfοcus='this.blur();'></span> `;
  
  if (treeNode.id === 'custom') {<!-- -->
    // customize
    addStr = addSm; //Add node
  } else if (treeNode.code === 'custom') {<!-- -->
    // Customized classification nodes (second level)
    if (treeNode.pid === 'custom') {<!-- -->
      addStr = add + edit;
      if (_.isEmpty(treeNode.children)) {<!-- -->
        addStr + = del; // When a child node is placed under a category, the category can be deleted
      }
    } else {<!-- -->
      //Three layers
      addStr = edit + del;
    }
    
  if (addStr) {<!-- -->
    const _id = `#${<!-- -->treeNode.tId}_span`;
    tippy(_id, {<!-- -->
      content: addStr, // Prompt content
      trigger: 'mouseenter click',// trigger method
      placement: 'right', // Appearance position
      interactive: true,//Whether it is possible to interact
      theme: 'material',// theme
      onMount: function () {<!-- -->// Execute after mounting
        $(`#btn_edit_${<!-- -->treeNode.tId}`)
          ?.off('click')
          ?.on('click', (e) => {<!-- -->
            editNode(treeId, treeNode);
            e.stopPropagation();
          });
        $(`#btn_add_${<!-- -->treeNode.tId}`)
          ?.off('click')
          ?.on('click', (e) => {<!-- -->
            addNode(treeId, treeNode);
            e.stopPropagation();
          });
        $(`#btn_addSm_${<!-- -->treeNode.tId}`)
          ?.off('click')
          ?.on('click', (e) => {<!-- -->
            saveSmNode('add', treeId, treeNode);
            e.stopPropagation();
          });
        $(`#btn_remove_${<!-- -->treeNode.tId}`)
          ?.off('click')
          ?.on('click', (e) => {<!-- -->
            removeNode(treeId, treeNode);
            e.stopPropagation();
          });
      },
    });
  }
};

tippy api documentation: https://atomiks.github.io/tippyjs/v6/all-props

3. Button binding event

//Add and edit nodes (category)
async function saveSmNode(type: 'add' | 'mod', treeId, treeNode) {<!-- -->
  const title = type === 'add' ? 'New node' : 'Edit node';
  let {<!-- --> value } = await ElMessageBox.prompt(title, '', {<!-- -->
    confirmButtonText: 'Confirm',
    cancelButtonText:'Cancel',
    inputPattern: /\S + /,// Input box verification rules
    inputPlaceholder: type === 'add' ? 'Please enter the node name' : null, // placeholder
    inputErrorMessage: 'Node name cannot be empty! ',//Verification failed information
    inputValue: type === 'add' ? null : treeNode.name,//default value of input box
  });
  try {<!-- -->
   //case1: Add a new node under this node
    if (type === 'add') {<!-- -->
      const res = await $.ajax({<!-- -->
        url: `${<!-- -->window.__ctx}/report/module/addNode`,
        type: 'POST',
        dataType: 'json',
        data: {<!-- -->
          parentId: treeNode.id,
          name: value,//Get the value of the input box
        },
      });
      if (!res.result) throw new Error(res?.message);
      ElMessage.success(res?.message || 'Submission successful');
      const zTreeObj = $.fn.zTree.getZTreeObj(treeId);
      zTreeObj.addNodes(treeNode, res?.object);//Update the display of tree nodes
     //case2: Edit the node
    } else {<!-- -->
      const res = await $.ajax({<!-- -->
        url: `${<!-- -->window.__ctx}/report/module/rename`,
        type: 'POST',
        dataType: 'json',
        data: {<!-- -->
          id: treeNode.id,
          reName: value,
        },
      });
      if (!res.result) throw new Error(res?.message);
      ElMessage.success(res?.message || 'Submission successful');
      const zTreeObj = $.fn.zTree.getZTreeObj(treeId);
      treeNode.name = value;
      zTreeObj.updateNode(treeNode);
    }
  } catch (error) {<!-- -->
    if (error === 'cancel') return;
    ElMessage.error(error?.message ||'Submission failed');
    console.log(`addSmNode - error`, error);
  }
}

// delete
async function removeNode(treeId, treeNode) {<!-- -->
  try {<!-- -->
    const modId = treeNode.id;
    await ElMessageBox.confirm('Do you want to delete this node?', 'Prompt', {<!-- -->
   confirmButtonText: 'Confirm',
 cancelButtonText:'Cancel',
      type: 'warning',
    });
    const res = await $.ajax({<!-- -->
      url: `${<!-- -->window.__ctx}/report/module/delete/${<!-- -->modId}`,
      type: 'GET',
      dataType: 'json',
    });
    if (!res.result) throw new Error(res?.message);
    ElMessage.success(res?.message || 'Submission successful');
    $.fn.zTree.getZTreeObj(treeId).removeNode(treeNode);//Remove the node
  } catch (error) {<!-- -->
    if (error === 'cancel') return;
    ElMessage.error(error?.message || 'Submission failed');
    console.log(`removeNode - error`, error);
  }
}
// add files
function addNode(treeId, treeNode) {<!-- -->
  ...
}
//Edit file
function editNode(treeId, treeNode) {<!-- -->
  ...
}

4. Interface request data, initialize zTree

async function initZtree() {<!-- -->
  const setting = initZtreeSetting ();
  try {<!-- -->
    isTreeLoading.value = true;
    const res = await $.ajax({<!-- -->
      url: `${<!-- -->window.__ctx}/report/tree`,
      type: 'POST',
      dataType: 'json',
    });
    if (!res?.result) return;
    const treeObj = $.fn.zTree.init($('#treeId'), setting, res?.object);
    if (treeObj.getNodes().length >= 1) {<!-- -->
      treeObj.expandNode(treeObj.getNodes()[0], true);//Expand the first node
    }
  } catch (err) {<!-- -->
    console.log(`[log] - initZtree- err`, err);
  } finally {<!-- -->
    isTreeLoading.value = false;
  }
}

5. All code

<template>
    <div v-loading="isTreeLoading">
      <ul class="ztree" id="treeId"></ul>
    </div>
</template>