import { cjkEncodeDO, deepClone, each, extend, isEmpty, isNotNull, isNull, shortcut } from "@/core"; import { TreeView } from "./treeview"; import { TreeRenderPageService } from "./treerender.page.service"; import $ from "jquery"; @shortcut() export class Asynctree extends TreeView { static xtype = "bi.async_tree"; _defaultConfig() { return extend(super._defaultConfig(...arguments), { showIcon: false, showLine: true, }); } _init() { super._init(...arguments); const self = this; this.service = new TreeRenderPageService({ subNodeListGetter(tId) { // 获取待检测的子节点列表, ztree并没有获取节点列表dom的API, 此处使用$获取 return $(`#${self.id} #${tId}_ul`); }, }); } // 配置属性 _configSetting() { const o = this.options; const paras = this.options.paras; const self = this; function onClick(event, treeId, treeNode) { if (treeNode.disabled) { return false; } const zTree = $.fn.zTree.getZTreeObj(treeId); // 当前点击节点的状态是半选,且为true_part, 则将其改为false_part,使得点击半选后切换到的是全选 let checked = treeNode.checked; const status = treeNode.getCheckStatus(); if (status.half === true && status.checked === true) { checked = false; } zTree.checkNode(treeNode, !checked, true, true); } function beforeCheck(treeId, treeNode) { if (treeNode.disabled) { return false; } // 下面主动修改了node的halfCheck属性, 节点属性的判断依赖halfCheck,改之前就获取一下 const status = treeNode.getCheckStatus(); treeNode.halfCheck = false; if (treeNode.checked === true) { // 将展开的节点halfCheck设为false,解决展开节点存在halfCheck=true的情况 guy // 所有的半选状态都需要取消halfCheck=true的情况 function track(children) { each(children, (i, ch) => { ch.halfCheck = false; track(ch.children); }); } track(treeNode.children); const treeObj = $.fn.zTree.getZTreeObj(treeId); const nodes = treeObj.getSelectedNodes(); each(nodes, (index, node) => { node.halfCheck = false; }); } // 当前点击节点的状态是半选,且为true_part, 则将其改为false_part,使得点击半选后切换到的是全选 if (status.half === true && status.checked === true) { treeNode.checked = false; } } function beforeExpand(treeId, treeNode) { self._beforeExpandNode(treeId, treeNode); } function onCheck(event, treeId, treeNode) { if (treeNode.disabled) { return false; } self._selectTreeNode(treeId, treeNode); } function onExpand(event, treeId, treeNode) { treeNode.halfCheck = false; } function onCollapse(event, treeId, treeNode) { treeNode.halfCheck = false; } return { async: { enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: cjkEncodeDO(paras), }, check: { enable: true, }, data: { key: { title: "title", name: "text", }, simpleData: { enable: true, }, }, view: { showIcon: o.showIcon, expandSpeed: "", nameIsHTML: true, dblClickExpand: false, showLine: o.showLine, nodeClasses(treeId, treeNode) { return { add: [treeNode.iconCls || ""] }; }, }, callback: { beforeCheck, onCheck, beforeExpand, onExpand, onCollapse, onClick, }, }; } // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode(treeId, treeNode) { const self = this; let parentValues = deepClone(treeNode.parentValues || self._getParentValues(treeNode)); let name = this._getNodeValue(treeNode); // var values = parentValues.concat([name]); if (treeNode.checked === true) { this._addTreeNode(this.options.paras.selectedValues, parentValues, name, {}); } else { let tNode = treeNode; let pNode = this._getTree(this.options.paras.selectedValues, parentValues); if (isNotNull(pNode[name])) { delete pNode[name]; } while (tNode != null && isEmpty(pNode)) { parentValues = parentValues.slice(0, parentValues.length - 1); tNode = tNode.getParentNode(); if (tNode != null) { pNode = this._getTree(this.options.paras.selectedValues, parentValues); name = this._getNodeValue(tNode); delete pNode[name]; } } this.options.paras.selectedValues = this._getJoinValue(); } super._selectTreeNode(...arguments); } // 展开节点 _beforeExpandNode(treeId, treeNode) { const self = this, o = this.options; function complete(d) { const nodes = d.items || []; if (nodes.length > 0) { callback(self._dealWidthNodes(nodes), !!d.hasNext); } } function callback(nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); if (hasNext) { self.service.pushNodeList(treeNode.tId, getNodes); } else { self.service.removeNodeList(treeNode.tId); } } function getNodes(options) { // console.log(times); options = options || {}; const parentValues = treeNode.parentValues || self._getParentValues(treeNode); const op = extend( {}, o.paras, { id: treeNode.id, times: options.times, parentValues: parentValues.concat(self._getNodeValue(treeNode)), checkState: treeNode.getCheckStatus(), }, options ); o.itemsCreator(op, complete); } // 展开节点会将halfCheck置为false以开启自动计算半选, 所以第一次展开节点的时候需要在置为false之前获取配置 const checkState = treeNode.getCheckStatus(); if (!treeNode.children && !treeNode.requested) { treeNode.requested = true; setTimeout(() => { getNodes({ times: 1, checkState, }); }, 17); } } // a,b 两棵树 // a->b b->a 做两次校验, 构造一个校验后的map // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join(valueA, valueB) { const self = this; const map = {}; track([], valueA, valueB); track([], valueB, valueA); function track(parent, node, compare) { each(node, (n, item) => { if (isNull(compare[n])) { self._addTreeNode(map, parent, n, item); } else if (isEmpty(compare[n])) { self._addTreeNode(map, parent, n, item); } else { track(parent.concat([n]), node[n], compare[n]); } }); } return map; } hasChecked() { return !isEmpty(this.options.paras.selectedValues) || super.hasChecked(...arguments); } _getJoinValue() { if (!this.nodes) { return this.options.paras.selectedValues || {}; } const checkedValues = this._getSelectedValues(); if (isEmpty(checkedValues)) { return deepClone(this.options.paras.selectedValues); } if (isEmpty(this.options.paras.selectedValues)) { return checkedValues; } return this._join(checkedValues, this.options.paras.selectedValues); } getValue() { return this._getJoinValue(); } // 生成树方法 stroke(config) { delete this.options.keyword; this.service.clear(); extend(this.options.paras, config); const setting = this._configSetting(); this._initTree(setting); } }