重新构建一遍okr-tree
This commit is contained in:
		@@ -8,7 +8,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import AiOkrTree from "./AiOkrTree";
 | 
					import AiOkrTree from "./AiOkrTree/AiOkrTree";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name: 'AiDvPartyOrg',
 | 
					  name: 'AiDvPartyOrg',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
  <section class="AiOkrTree">
 | 
					 | 
				
			||||||
    <component v-if="okrTreeLoaded" v-bind="$attrs" :is="ot" :data="data"/>
 | 
					 | 
				
			||||||
  </section>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
import Vue from "vue"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  name: "AiOkrTree",
 | 
					 | 
				
			||||||
  props: {
 | 
					 | 
				
			||||||
    data: {default: () => []}
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    okrTreeLoaded: v => !!v.ot
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  data() {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      ot: null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  created() {
 | 
					 | 
				
			||||||
    this.$injectCss("https://cdn.cunwuyun.cn/vot/vue-okr-tree.css")
 | 
					 | 
				
			||||||
    this.$injectLib("https://cdn.cunwuyun.cn/vot/vue-okr-tree.umd.min.js", () => {
 | 
					 | 
				
			||||||
      const {VueOkrTree} = (window?.["vue-okr-tree"] || {})
 | 
					 | 
				
			||||||
      this.ot = Vue.extend({
 | 
					 | 
				
			||||||
        ...VueOkrTree, data() {
 | 
					 | 
				
			||||||
          return {...this.$attrs}
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style lang="scss" scoped>
 | 
					 | 
				
			||||||
.AiOkrTree {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
							
								
								
									
										732
									
								
								components/AiOkrTree/AiOkrTree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										732
									
								
								components/AiOkrTree/AiOkrTree.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,732 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="org-chart-container">
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					        ref="orgChartRoot"
 | 
				
			||||||
 | 
					        class="org-chart-node-children"
 | 
				
			||||||
 | 
					        :class="{
 | 
				
			||||||
 | 
					        vertical: direction === 'vertical',
 | 
				
			||||||
 | 
					        horizontal: direction === 'horizontal',
 | 
				
			||||||
 | 
					        'show-collapsable': showCollapsable,
 | 
				
			||||||
 | 
					        'one-branch': data.length === 1
 | 
				
			||||||
 | 
					      }"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <OkrTreeNode
 | 
				
			||||||
 | 
					          v-for="child in root.childNodes"
 | 
				
			||||||
 | 
					          :node="child"
 | 
				
			||||||
 | 
					          :root="root"
 | 
				
			||||||
 | 
					          orkstyle
 | 
				
			||||||
 | 
					          :show-collapsable="showCollapsable"
 | 
				
			||||||
 | 
					          :label-width="labelWidth"
 | 
				
			||||||
 | 
					          :label-height="labelHeight"
 | 
				
			||||||
 | 
					          :renderContent="renderContent"
 | 
				
			||||||
 | 
					          :nodeBtnContent="nodeBtnContent"
 | 
				
			||||||
 | 
					          :selected-key="selectedKey"
 | 
				
			||||||
 | 
					          :default-expand-all="defaultExpandAll"
 | 
				
			||||||
 | 
					          :node-key="nodeKey"
 | 
				
			||||||
 | 
					          :show-node-num="showNodeNum"
 | 
				
			||||||
 | 
					          :key="getNodeKey(child)"
 | 
				
			||||||
 | 
					          :props="props"
 | 
				
			||||||
 | 
					      ></OkrTreeNode>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import Vue from "vue";
 | 
				
			||||||
 | 
					import OkrTreeNode from "./OkrTreeNode.vue";
 | 
				
			||||||
 | 
					import TreeStore from "./model/tree-store.js";
 | 
				
			||||||
 | 
					import {getNodeKey} from "./model/util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: "AiOkrTree",
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    OkrTreeNode
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  provide() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      okrEventBus: this.okrEventBus
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    data: {
 | 
				
			||||||
 | 
					      // 源数据
 | 
				
			||||||
 | 
					      required: true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    leftData: {
 | 
				
			||||||
 | 
					      // 源数据
 | 
				
			||||||
 | 
					      type: Array
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 方向
 | 
				
			||||||
 | 
					    direction: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: "vertical"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 子节点是否可折叠
 | 
				
			||||||
 | 
					    showCollapsable: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 飞书 OKR 模式
 | 
				
			||||||
 | 
					    onlyBothTree: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    orkstyle: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 树节点的内容区的渲染 Function
 | 
				
			||||||
 | 
					    renderContent: Function,
 | 
				
			||||||
 | 
					    // 展开节点的内容渲染 Function
 | 
				
			||||||
 | 
					    nodeBtnContent: Function,
 | 
				
			||||||
 | 
					    // 显示节点数
 | 
				
			||||||
 | 
					    showNodeNum: Boolean,
 | 
				
			||||||
 | 
					    // 树节点区域的宽度
 | 
				
			||||||
 | 
					    labelWidth: [String, Number],
 | 
				
			||||||
 | 
					    // 树节点区域的高度
 | 
				
			||||||
 | 
					    labelHeight: [String, Number],
 | 
				
			||||||
 | 
					    // 树节点的样式
 | 
				
			||||||
 | 
					    labelClassName: [Function, String],
 | 
				
			||||||
 | 
					    // 当前选中节点样式
 | 
				
			||||||
 | 
					    currentLableClassName: [Function, String],
 | 
				
			||||||
 | 
					    // 用来控制选择节点的字段名
 | 
				
			||||||
 | 
					    selectedKey: String,
 | 
				
			||||||
 | 
					    // 是否默认展开所有节点
 | 
				
			||||||
 | 
					    defaultExpandAll: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 当前选中的节点
 | 
				
			||||||
 | 
					    currentNodeKey: [String, Number],
 | 
				
			||||||
 | 
					    // 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
 | 
				
			||||||
 | 
					    nodeKey: String,
 | 
				
			||||||
 | 
					    defaultExpandedKeys: {
 | 
				
			||||||
 | 
					      type: Array
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    filterNodeMethod: Function,
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      default() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          leftChildren: "leftChildren",
 | 
				
			||||||
 | 
					          children: "children",
 | 
				
			||||||
 | 
					          label: "label",
 | 
				
			||||||
 | 
					          disabled: "disabled"
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 动画
 | 
				
			||||||
 | 
					    animate: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    animateName: {
 | 
				
			||||||
 | 
					      type: String,
 | 
				
			||||||
 | 
					      default: "okr-zoom-in-center"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    animateDuration: {
 | 
				
			||||||
 | 
					      type: Number,
 | 
				
			||||||
 | 
					      default: 200
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    ondeClass() {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        findNode: null
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      okrEventBus: new Vue(),
 | 
				
			||||||
 | 
					      store: null,
 | 
				
			||||||
 | 
					      root: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  created() {
 | 
				
			||||||
 | 
					    this.isTree = true;
 | 
				
			||||||
 | 
					    this.store = new TreeStore({
 | 
				
			||||||
 | 
					      key: this.nodeKey,
 | 
				
			||||||
 | 
					      data: Object.freeze(this.data),
 | 
				
			||||||
 | 
					      leftData: this.leftData,
 | 
				
			||||||
 | 
					      props: this.props,
 | 
				
			||||||
 | 
					      defaultExpandedKeys: this.defaultExpandedKeys,
 | 
				
			||||||
 | 
					      showCollapsable: this.showCollapsable,
 | 
				
			||||||
 | 
					      currentNodeKey: this.currentNodeKey,
 | 
				
			||||||
 | 
					      defaultExpandAll: this.defaultExpandAll,
 | 
				
			||||||
 | 
					      filterNodeMethod: this.filterNodeMethod,
 | 
				
			||||||
 | 
					      labelClassName: this.labelClassName,
 | 
				
			||||||
 | 
					      currentLableClassName: this.currentLableClassName,
 | 
				
			||||||
 | 
					      onlyBothTree: this.onlyBothTree,
 | 
				
			||||||
 | 
					      direction: this.direction,
 | 
				
			||||||
 | 
					      animate: this.animate,
 | 
				
			||||||
 | 
					      animateName: this.animateName
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.root = this.store.root;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  watch: {
 | 
				
			||||||
 | 
					    data(newVal) {
 | 
				
			||||||
 | 
					      this.store.setData(newVal);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    defaultExpandedKeys(newVal) {
 | 
				
			||||||
 | 
					      this.store.defaultExpandedKeys = newVal;
 | 
				
			||||||
 | 
					      this.store.setDefaultExpandedKeys(newVal);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    filter(value) {
 | 
				
			||||||
 | 
					      if (!this.filterNodeMethod)
 | 
				
			||||||
 | 
					        throw new Error("[Tree] filterNodeMethod is required when filter");
 | 
				
			||||||
 | 
					      this.store.filter(value);
 | 
				
			||||||
 | 
					      if (this.onlyBothTree) {
 | 
				
			||||||
 | 
					        this.store.filter(value, "leftChildNodes");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    getNodeKey(node) {
 | 
				
			||||||
 | 
					      return getNodeKey(this.nodeKey, node.data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 通过 node 设置某个节点的当前选中状态
 | 
				
			||||||
 | 
					    setCurrentNode(node) {
 | 
				
			||||||
 | 
					      if (!this.nodeKey)
 | 
				
			||||||
 | 
					        throw new Error("[Tree] nodeKey is required in setCurrentNode");
 | 
				
			||||||
 | 
					      this.store.setUserCurrentNode(node);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 根据 data 或者 key 拿到 Tree 组件中的 node
 | 
				
			||||||
 | 
					    getNode(data) {
 | 
				
			||||||
 | 
					      return this.store.getNode(data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 通过 key 设置某个节点的当前选中状态
 | 
				
			||||||
 | 
					    setCurrentKey(key) {
 | 
				
			||||||
 | 
					      if (!this.nodeKey)
 | 
				
			||||||
 | 
					        throw new Error("[Tree] nodeKey is required in setCurrentKey");
 | 
				
			||||||
 | 
					      this.store.setCurrentNodeKey(key);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    remove(data) {
 | 
				
			||||||
 | 
					      this.store.remove(data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 获取当前被选中节点的 data
 | 
				
			||||||
 | 
					    getCurrentNode() {
 | 
				
			||||||
 | 
					      const currentNode = this.store.getCurrentNode();
 | 
				
			||||||
 | 
					      return currentNode ? currentNode.data : null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    getCurrentKey() {
 | 
				
			||||||
 | 
					      if (!this.nodeKey)
 | 
				
			||||||
 | 
					        throw new Error("[Tree] nodeKey is required in getCurrentKey");
 | 
				
			||||||
 | 
					      const currentNode = this.getCurrentNode();
 | 
				
			||||||
 | 
					      return currentNode ? currentNode[this.nodeKey] : null;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    append(data, parentNode) {
 | 
				
			||||||
 | 
					      this.store.append(data, parentNode);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    insertBefore(data, refNode) {
 | 
				
			||||||
 | 
					      this.store.insertBefore(data, refNode);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    insertAfter(data, refNode) {
 | 
				
			||||||
 | 
					      this.store.insertAfter(data, refNode);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    updateKeyChildren(key, data) {
 | 
				
			||||||
 | 
					      if (!this.nodeKey) throw new Error('[Tree] nodeKey is required in updateKeyChild');
 | 
				
			||||||
 | 
					      this.store.updateChildren(key, data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					@import "./model/transition.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.org-chart-container {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-children {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					  transition: all 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node {
 | 
				
			||||||
 | 
					  float: left;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  list-style-type: none;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding: 20px 5px 0 5px;
 | 
				
			||||||
 | 
					  transition: all 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*使用 ::before 和 ::after 绘制连接器*/
 | 
				
			||||||
 | 
					.vertical .org-chart-node::before,
 | 
				
			||||||
 | 
					.vertical .org-chart-node::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 50%;
 | 
				
			||||||
 | 
					  width: 50%;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node::after {
 | 
				
			||||||
 | 
					  right: auto;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  border-left: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*我们需要从没有任何兄弟元素的元素中删除左右连接器*/
 | 
				
			||||||
 | 
					.vertical.one-branch > .org-chart-node::after,
 | 
				
			||||||
 | 
					.vertical.one-branch > .org-chart-node::before {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从单个子节点的顶部移除空格*/
 | 
				
			||||||
 | 
					.vertical.one-branch > .org-chart-node {
 | 
				
			||||||
 | 
					  padding-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从第一个子节点移除左连接器,从最后一个子节点移除右连接器*/
 | 
				
			||||||
 | 
					.vertical .org-chart-node:first-child::before,
 | 
				
			||||||
 | 
					.vertical .org-chart-node:last-child::after {
 | 
				
			||||||
 | 
					  border: 0 none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*将垂直连接器添加回最后的节点*/
 | 
				
			||||||
 | 
					.vertical .org-chart-node:last-child::before {
 | 
				
			||||||
 | 
					  border-right: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 0 5px 0 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node:only-child:before {
 | 
				
			||||||
 | 
					  border-radius: 0 0px 0 0;
 | 
				
			||||||
 | 
					  margin-right: -1px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node:first-child::after {
 | 
				
			||||||
 | 
					  border-radius: 5px 0 0 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node.is-leaf {
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					  padding-bottom: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node.is-leaf::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node.is-leaf .org-chart-node-label::after {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从父节点添加向下的连接器了*/
 | 
				
			||||||
 | 
					.vertical .org-chart-node-children::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  border-left: 1px solid #ccc;
 | 
				
			||||||
 | 
					  width: 0;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-label-inner {
 | 
				
			||||||
 | 
					  box-shadow: 0 1px 10px rgba(31, 35, 41, 0.08);
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  padding: 10px;
 | 
				
			||||||
 | 
					  margin: 0px;
 | 
				
			||||||
 | 
					  font-size: 16px;
 | 
				
			||||||
 | 
					  word-break: break-all;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-label-inner:hover {
 | 
				
			||||||
 | 
					  box-shadow: 0 1px 14px rgba(31, 35, 41, 0.12);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 100%;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					  z-index: 10;
 | 
				
			||||||
 | 
					  margin-left: -11px;
 | 
				
			||||||
 | 
					  margin-top: 9px;
 | 
				
			||||||
 | 
					  background-color: #fff;
 | 
				
			||||||
 | 
					  border: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  box-shadow: 0 0 2px rgba(0, 0, 0, 0.15);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: all 0.35s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn:hover {
 | 
				
			||||||
 | 
					  transform: scale(1.15);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn::before,
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn::before {
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  left: 4px;
 | 
				
			||||||
 | 
					  right: 4px;
 | 
				
			||||||
 | 
					  height: 0;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .org-chart-node-btn::after {
 | 
				
			||||||
 | 
					  top: 4px;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  bottom: 4px;
 | 
				
			||||||
 | 
					  width: 0;
 | 
				
			||||||
 | 
					  border-left: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node-label .expanded.org-chart-node-btn::after {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node.collapsed .org-chart-node-label {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.vertical .org-chart-node.collapsed .org-chart-node-label::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 100%;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  width: 50%;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					  border-right: 1px solid #ddd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-children,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-left-children {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding-left: 20px;
 | 
				
			||||||
 | 
					  transition: all 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-left-children {
 | 
				
			||||||
 | 
					  padding-right: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node) {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding: 0px 5px 0 20px;
 | 
				
			||||||
 | 
					  transition: all 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  justify-content: flex-end;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node {
 | 
				
			||||||
 | 
					  padding: 0px 20px 0 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*使用 ::before 和 ::after 绘制连接器*/
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node):before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node)::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  border-left: 1px solid #ccc;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					  height: 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:before,
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  border-right: 1px solid #ccc;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					  height: 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node):after {
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:after {
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*我们需要从没有任何兄弟元素的元素中删除左右连接器*/
 | 
				
			||||||
 | 
					.horizontal.one-branch > .org-chart-node::after,
 | 
				
			||||||
 | 
					.horizontal.one-branch > .org-chart-node::before {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从单个子节点的顶部移除空格*/
 | 
				
			||||||
 | 
					.horizontal.one-branch > .org-chart-node {
 | 
				
			||||||
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从第一个子节点移除左连接器,从最后一个子节点移除右连接器*/
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:first-child::before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:last-child::after {
 | 
				
			||||||
 | 
					  border: 0 none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*将垂直连接器添加回最后的节点*/
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node):not(.is-not-child):last-child::before {
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 0 0px 0 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:last-child::before {
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 0 0px 5px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:only-child::before {
 | 
				
			||||||
 | 
					  border-radius: 0 0px 0 0px !important;
 | 
				
			||||||
 | 
					  border-color: #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node:not(.is-left-child-node):first-child::after {
 | 
				
			||||||
 | 
					  border-radius: 5px 0px 0 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:first-child::after {
 | 
				
			||||||
 | 
					  border-radius: 0 5px 0px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.is-leaf {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding-left: 20px;
 | 
				
			||||||
 | 
					  padding-right: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.is-leaf::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.is-leaf .org-chart-node-label::after,
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.is-leaf .org-chart-node-label::before {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:last-child::after {
 | 
				
			||||||
 | 
					  /* border-bottom: 1px solid green; */
 | 
				
			||||||
 | 
					  border-radius: 0 0px 5px 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node:only-child::after {
 | 
				
			||||||
 | 
					  border-radius: 0 0px 0 0px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.is-leaf {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  padding-left: 20px;
 | 
				
			||||||
 | 
					  padding-right: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.is-leaf::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node .org-chart-node-label::after {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*从父节点添加向下的连接器了*/
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-children::before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-left-children::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					  width: 12px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-children::before {
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-left-children::before {
 | 
				
			||||||
 | 
					  left: calc(100% - 11px);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal > .only-both-tree-node > .org-chart-node-left-children::before {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-label-inner {
 | 
				
			||||||
 | 
					  box-shadow: 0 1px 10px rgba(31, 35, 41, 0.08);
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  padding: 10px;
 | 
				
			||||||
 | 
					  margin: 10px 0;
 | 
				
			||||||
 | 
					  font-size: 16px;
 | 
				
			||||||
 | 
					  word-break: break-all;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-label-inner:hover {
 | 
				
			||||||
 | 
					  box-shadow: 0 1px 14px rgba(31, 35, 41, 0.12);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  left: 100%;
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					  z-index: 10;
 | 
				
			||||||
 | 
					  margin-top: -11px;
 | 
				
			||||||
 | 
					  margin-left: 9px;
 | 
				
			||||||
 | 
					  background-color: #fff;
 | 
				
			||||||
 | 
					  border: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  box-shadow: 0 0 2px rgba(0, 0, 0, 0.15);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: all 0.35s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn:hover,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn:hover {
 | 
				
			||||||
 | 
					  transform: scale(1.15);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn::before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn::after,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn::before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn::after {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn::before,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn::before {
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  left: 4px;
 | 
				
			||||||
 | 
					  right: 3px;
 | 
				
			||||||
 | 
					  border-top: 1px solid #ccc;
 | 
				
			||||||
 | 
					  height: 0;
 | 
				
			||||||
 | 
					  transform: translateY(-50%);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-btn::after,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn::after {
 | 
				
			||||||
 | 
					  top: 4px;
 | 
				
			||||||
 | 
					  left: 50%;
 | 
				
			||||||
 | 
					  bottom: 4px;
 | 
				
			||||||
 | 
					  width: 0;
 | 
				
			||||||
 | 
					  border-left: 1px solid #ccc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .expanded.org-chart-node-btn::after,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .expanded.org-chart-node-left-btn::after {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node-label .org-chart-node-left-btn {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  right: 100%;
 | 
				
			||||||
 | 
					  top: 50%;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					  height: 20px;
 | 
				
			||||||
 | 
					  z-index: 10;
 | 
				
			||||||
 | 
					  margin-top: -11px;
 | 
				
			||||||
 | 
					  margin-right: 9px;
 | 
				
			||||||
 | 
					  background-color: #fff;
 | 
				
			||||||
 | 
					  border: 1px solid #ccc;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  box-shadow: 0 0 2px rgba(0, 0, 0, 0.15);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: all 0.35s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.collapsed .org-chart-node-label,
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.collapsed .org-chart-node-label {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.collapsed .org-chart-node-label::after,
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.collapsed .org-chart-node-label::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #ccc;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 100%;
 | 
				
			||||||
 | 
					  height: 50%;
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .org-chart-node .is-root-label.is-not-right-child::after,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node .is-root-label.is-not-left-child::before {
 | 
				
			||||||
 | 
					  display: none !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* .horizontal .org-chart-node.collapsed .is-root-label.is-right-child::after,
 | 
				
			||||||
 | 
					.horizontal .org-chart-node.collapsed .is-root-label.is-left-child::before {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					} */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .is-left-child-node.collapsed .org-chart-node-label::before {
 | 
				
			||||||
 | 
					  left: -10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.horizontal .only-both-tree-node > .org-chart-node-label::before {
 | 
				
			||||||
 | 
					  content: "";
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #ccc;
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 100%;
 | 
				
			||||||
 | 
					  height: 50%;
 | 
				
			||||||
 | 
					  width: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.org-chart-node-children .org-chart-node-btn-text {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  bottom: 0;
 | 
				
			||||||
 | 
					  background: #fff;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  color: #909090;
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										386
									
								
								components/AiOkrTree/OkrTreeNode.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								components/AiOkrTree/OkrTreeNode.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,386 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div
 | 
				
			||||||
 | 
					    class="org-chart-node"
 | 
				
			||||||
 | 
					    @contextmenu="$event => this.handleContextMenu($event)"
 | 
				
			||||||
 | 
					    v-if="node.visible"
 | 
				
			||||||
 | 
					    :class="{
 | 
				
			||||||
 | 
					      collapsed: !node.leftExpanded || !node.expanded,
 | 
				
			||||||
 | 
					      'is-leaf': isLeaf,
 | 
				
			||||||
 | 
					      'is-current': node.isCurrent,
 | 
				
			||||||
 | 
					      'is-left-child-node': isLeftChildNode,
 | 
				
			||||||
 | 
					      'is-not-child': node.level === 1 && node.childNodes.length <= 0 && leftChildNodes.length <= 0,
 | 
				
			||||||
 | 
					      'only-both-tree-node': node.level === 1 && tree.store.onlyBothTree
 | 
				
			||||||
 | 
					    }"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <transition :duration="animateDuration" :name="animateName">
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        class="org-chart-node-left-children"
 | 
				
			||||||
 | 
					        v-if="showLeftChildNode"
 | 
				
			||||||
 | 
					        v-show="node.leftExpanded"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <OkrTreeNode
 | 
				
			||||||
 | 
					          v-for="child in leftChildNodes"
 | 
				
			||||||
 | 
					          :show-collapsable="showCollapsable"
 | 
				
			||||||
 | 
					          :node="child"
 | 
				
			||||||
 | 
					          :label-width="labelWidth"
 | 
				
			||||||
 | 
					          :label-height="labelHeight"
 | 
				
			||||||
 | 
					          :renderContent="renderContent"
 | 
				
			||||||
 | 
					          :nodeBtnContent="nodeBtnContent"
 | 
				
			||||||
 | 
					          :selected-key="selectedKey"
 | 
				
			||||||
 | 
					          :node-key="nodeKey"
 | 
				
			||||||
 | 
					          :key="getNodeKey(child)"
 | 
				
			||||||
 | 
					          :props="props"
 | 
				
			||||||
 | 
					          :show-node-num="showNodeNum"
 | 
				
			||||||
 | 
					          is-left-child-node
 | 
				
			||||||
 | 
					        ></OkrTreeNode>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </transition>
 | 
				
			||||||
 | 
					    <div class="org-chart-node-label"
 | 
				
			||||||
 | 
					      :class="{
 | 
				
			||||||
 | 
					        'is-root-label': node.level === 1,
 | 
				
			||||||
 | 
					        'is-not-right-child': node.level === 1 && node.childNodes.length <= 0,
 | 
				
			||||||
 | 
					        'is-not-left-child': node.level === 1 && leftChildNodes.length <= 0
 | 
				
			||||||
 | 
					      }"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        v-if="showNodeLeftBtn && leftChildNodes.length > 0"
 | 
				
			||||||
 | 
					        class="org-chart-node-left-btn"
 | 
				
			||||||
 | 
					        :class="{ expanded: node.leftExpanded }"
 | 
				
			||||||
 | 
					        @click="handleBtnClick('left')">
 | 
				
			||||||
 | 
					        <template v-if="showNodeNum" >
 | 
				
			||||||
 | 
					          <span v-if="!node.leftExpanded" class="org-chart-node-btn-text">
 | 
				
			||||||
 | 
					            {{ (node.level === 1 && leftChildNodes.length > 0) ? leftChildNodes.length : node.childNodes.length }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <node-btn-content v-else :node="node">
 | 
				
			||||||
 | 
					          <slot>
 | 
				
			||||||
 | 
					          </slot>
 | 
				
			||||||
 | 
					        </node-btn-content>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        class="org-chart-node-label-inner"
 | 
				
			||||||
 | 
					        @click="handleNodeClick"
 | 
				
			||||||
 | 
					        :class="computeLabelClass"
 | 
				
			||||||
 | 
					        :style="computeLabelStyle"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <node-content :node="node">
 | 
				
			||||||
 | 
					          <slot>
 | 
				
			||||||
 | 
					            {{ node.label }}
 | 
				
			||||||
 | 
					          </slot>
 | 
				
			||||||
 | 
					        </node-content>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        v-if="showNodeBtn && !isLeftChildNode"
 | 
				
			||||||
 | 
					        class="org-chart-node-btn"
 | 
				
			||||||
 | 
					        :class="{ expanded: node.expanded }"
 | 
				
			||||||
 | 
					        @click="handleBtnClick('right')">
 | 
				
			||||||
 | 
					        <template v-if="showNodeNum">
 | 
				
			||||||
 | 
					          <span v-if="!node.expanded " class="org-chart-node-btn-text">
 | 
				
			||||||
 | 
					            {{ node.childNodes.length }}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <node-btn-content v-else :node="node">
 | 
				
			||||||
 | 
					          <slot>
 | 
				
			||||||
 | 
					            <!-- <div class="org-chart-node-btn-text">10</div> -->
 | 
				
			||||||
 | 
					          </slot>
 | 
				
			||||||
 | 
					        </node-btn-content>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <transition :duration="animateDuration" :name="animateName">
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        class="org-chart-node-children"
 | 
				
			||||||
 | 
					        v-if="!isLeftChildNode && node.childNodes && node.childNodes.length > 0"
 | 
				
			||||||
 | 
					        v-show="node.expanded"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <OkrTreeNode
 | 
				
			||||||
 | 
					          v-for="child in node.childNodes"
 | 
				
			||||||
 | 
					          :show-collapsable="showCollapsable"
 | 
				
			||||||
 | 
					          :node="child"
 | 
				
			||||||
 | 
					          :label-width="labelWidth"
 | 
				
			||||||
 | 
					          :label-height="labelHeight"
 | 
				
			||||||
 | 
					          :renderContent="renderContent"
 | 
				
			||||||
 | 
					          :nodeBtnContent="nodeBtnContent"
 | 
				
			||||||
 | 
					          :selected-key="selectedKey"
 | 
				
			||||||
 | 
					          :node-key="nodeKey"
 | 
				
			||||||
 | 
					          :key="getNodeKey(child)"
 | 
				
			||||||
 | 
					          :show-node-num='showNodeNum'
 | 
				
			||||||
 | 
					          :props="props"
 | 
				
			||||||
 | 
					        ></OkrTreeNode>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </transition>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import { getNodeKey } from "./model/util";
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: "OkrTreeNode",
 | 
				
			||||||
 | 
					  inject: ["okrEventBus"],
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    props: {},
 | 
				
			||||||
 | 
					    node: {
 | 
				
			||||||
 | 
					      default() {
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    root: {
 | 
				
			||||||
 | 
					      default() {
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 子节点是否可折叠
 | 
				
			||||||
 | 
					    showCollapsable: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 判断是否是左子树的节点,样式需要改
 | 
				
			||||||
 | 
					    isLeftChildNode: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 树节点的内容区的渲染 Function
 | 
				
			||||||
 | 
					    renderContent: Function,
 | 
				
			||||||
 | 
					    // 展开节点的内容渲染 Function
 | 
				
			||||||
 | 
					    nodeBtnContent: Function,
 | 
				
			||||||
 | 
					    // 显示节点数
 | 
				
			||||||
 | 
					    showNodeNum: Boolean,
 | 
				
			||||||
 | 
					    // 树节点区域的宽度
 | 
				
			||||||
 | 
					    labelWidth: [String, Number],
 | 
				
			||||||
 | 
					    // 树节点区域的高度
 | 
				
			||||||
 | 
					    labelHeight: [String, Number],
 | 
				
			||||||
 | 
					    // 用来控制选择节点的字段名
 | 
				
			||||||
 | 
					    selectedKey: String,
 | 
				
			||||||
 | 
					    // 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
 | 
				
			||||||
 | 
					    nodeKey: String
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    NodeContent: {
 | 
				
			||||||
 | 
					      props: {
 | 
				
			||||||
 | 
					        node: {
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      render(h) {
 | 
				
			||||||
 | 
					        const parent = this.$parent;
 | 
				
			||||||
 | 
					        if (parent._props.renderContent) {
 | 
				
			||||||
 | 
					          return parent._props.renderContent(h, this.node);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return this.$scopedSlots.default(this.node);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 渲染展开节点的样式
 | 
				
			||||||
 | 
					    NodeBtnContent: {
 | 
				
			||||||
 | 
					      props: {
 | 
				
			||||||
 | 
					        node: {
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      render(h) {
 | 
				
			||||||
 | 
					        const parent = this.$parent;
 | 
				
			||||||
 | 
					        if (parent._props.nodeBtnContent) {
 | 
				
			||||||
 | 
					          return parent._props.nodeBtnContent(h, this.node);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          if (this.$scopedSlots.default) {
 | 
				
			||||||
 | 
					            return this.$scopedSlots.default(this.node);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    isLeaf () {
 | 
				
			||||||
 | 
					      if (this.node.level === 1) {
 | 
				
			||||||
 | 
					        if (this.leftChildNodes.length == 0 && this.node.childNodes.length == 0) {
 | 
				
			||||||
 | 
					          return true
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return this.node.isLeaf
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    leftChildNodes() {
 | 
				
			||||||
 | 
					      if (this.tree.store.onlyBothTree) {
 | 
				
			||||||
 | 
					        if (this.isLeftChildNode) {
 | 
				
			||||||
 | 
					          return this.node.childNodes;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return this.node.leftChildNodes;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return [];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    animateName() {
 | 
				
			||||||
 | 
					      if (this.tree.store.animate) {
 | 
				
			||||||
 | 
					        return this.tree.store.animateName;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return "";
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    animateDuration() {
 | 
				
			||||||
 | 
					      if (this.tree.store.animate) {
 | 
				
			||||||
 | 
					        return this.tree.store.animateDuration;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 是否显示展开按钮
 | 
				
			||||||
 | 
					    showNodeBtn() {
 | 
				
			||||||
 | 
					      if (this.isLeftChildNode) {
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					          (this.tree.store.direction === "horizontal" &&
 | 
				
			||||||
 | 
					          this.showCollapsable &&
 | 
				
			||||||
 | 
					          this.leftChildNodes.length > 0) || this.level === 1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        this.showCollapsable &&
 | 
				
			||||||
 | 
					        this.node.childNodes &&
 | 
				
			||||||
 | 
					        this.node.childNodes.length > 0
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    showNodeLeftBtn() {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        (this.tree.store.direction === "horizontal" &&
 | 
				
			||||||
 | 
					        this.showCollapsable &&
 | 
				
			||||||
 | 
					        this.leftChildNodes.length > 0)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 节点的宽度
 | 
				
			||||||
 | 
					    computeLabelStyle() {
 | 
				
			||||||
 | 
					      let { labelWidth = "auto", labelHeight = "auto" } = this;
 | 
				
			||||||
 | 
					      if (typeof labelWidth === "number") {
 | 
				
			||||||
 | 
					        labelWidth = `${labelWidth}px`;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (typeof labelHeight === "number") {
 | 
				
			||||||
 | 
					        labelHeight = `${labelHeight}px`;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        width: labelWidth,
 | 
				
			||||||
 | 
					        height: labelHeight
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computeLabelClass() {
 | 
				
			||||||
 | 
					      let clsArr = [];
 | 
				
			||||||
 | 
					      const store = this.tree.store;
 | 
				
			||||||
 | 
					      if (store.labelClassName) {
 | 
				
			||||||
 | 
					        if (typeof store.labelClassName === "function") {
 | 
				
			||||||
 | 
					          clsArr.push(store.labelClassName(this.node));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          clsArr.push(store.labelClassName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (store.currentLableClassName && this.node.isCurrent) {
 | 
				
			||||||
 | 
					        if (typeof store.currentLableClassName === "function") {
 | 
				
			||||||
 | 
					          clsArr.push(store.currentLableClassName(this.node));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          clsArr.push(store.currentLableClassName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.node.isCurrent) {
 | 
				
			||||||
 | 
					        clsArr.push("is-current");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return clsArr;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computNodeStyle() {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        display: this.node.expanded ? "" : "none"
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computLeftNodeStyle() {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        display: this.node.leftExpanded ? "" : "none"
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // 是否显示左子数
 | 
				
			||||||
 | 
					    showLeftChildNode() {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        this.tree.onlyBothTree &&
 | 
				
			||||||
 | 
					        this.tree.store.direction === "horizontal" &&
 | 
				
			||||||
 | 
					        this.leftChildNodes &&
 | 
				
			||||||
 | 
					        this.leftChildNodes.length > 0
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  watch: {
 | 
				
			||||||
 | 
					    "node.expanded"(val) {
 | 
				
			||||||
 | 
					      // this.$nextTick(() => this.expanded = val);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node.leftExpanded"(val) {
 | 
				
			||||||
 | 
					      // this.$nextTick(() => this.expanded = val);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      // node 的展开状态
 | 
				
			||||||
 | 
					      expanded: false,
 | 
				
			||||||
 | 
					      tree: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  created() {
 | 
				
			||||||
 | 
					    const parent = this.$parent;
 | 
				
			||||||
 | 
					    if (parent.isTree) {
 | 
				
			||||||
 | 
					      this.tree = parent;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.tree = parent.tree;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const tree = this.tree;
 | 
				
			||||||
 | 
					    if (!tree) {
 | 
				
			||||||
 | 
					      console.warn("Can not find node's tree.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    getNodeKey(node) {
 | 
				
			||||||
 | 
					      return getNodeKey(this.nodeKey, node.data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    handleNodeClick() {
 | 
				
			||||||
 | 
					      const store = this.tree.store;
 | 
				
			||||||
 | 
					      store.setCurrentNode(this.node);
 | 
				
			||||||
 | 
					      this.tree.$emit("node-click", this.node.data, this.node, this);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    handleBtnClick(isLeft) {
 | 
				
			||||||
 | 
					      isLeft = isLeft === "left";
 | 
				
			||||||
 | 
					      const store = this.tree.store;
 | 
				
			||||||
 | 
					      // 表示是OKR飞书模式
 | 
				
			||||||
 | 
					      if (store.onlyBothTree) {
 | 
				
			||||||
 | 
					        if (isLeft) {
 | 
				
			||||||
 | 
					          if (this.node.leftExpanded) {
 | 
				
			||||||
 | 
					            this.node.leftExpanded = false;
 | 
				
			||||||
 | 
					            this.tree.$emit("node-collapse", this.node.data, this.node, this);
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            this.node.leftExpanded = true;
 | 
				
			||||||
 | 
					            this.tree.$emit("node-expand", this.node.data, this.node, this);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.node.expanded) {
 | 
				
			||||||
 | 
					        this.node.collapse();
 | 
				
			||||||
 | 
					        this.tree.$emit("node-collapse", this.node.data, this.node, this);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        if (this.node.parent.childNodes && this.node.parent.childNodes.length) {
 | 
				
			||||||
 | 
					          this.node.parent.childNodes.forEach(e => {
 | 
				
			||||||
 | 
					            e.collapse()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.node.expand();
 | 
				
			||||||
 | 
					        this.tree.$emit("node-expand", this.node.data, this.node, this);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    handleContextMenu(event) {
 | 
				
			||||||
 | 
					      if (
 | 
				
			||||||
 | 
					        this.tree._events["node-contextmenu"] &&
 | 
				
			||||||
 | 
					        this.tree._events["node-contextmenu"].length > 0
 | 
				
			||||||
 | 
					      ) {
 | 
				
			||||||
 | 
					        event.stopPropagation();
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.tree.$emit(
 | 
				
			||||||
 | 
					        "node-contextmenu",
 | 
				
			||||||
 | 
					        event,
 | 
				
			||||||
 | 
					        this.node.data,
 | 
				
			||||||
 | 
					        this.node,
 | 
				
			||||||
 | 
					        this
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
							
								
								
									
										14
									
								
								components/AiOkrTree/model/merge.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								components/AiOkrTree/model/merge.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					export default function(target) {
 | 
				
			||||||
 | 
					  for (let i = 1, j = arguments.length; i < j; i++) {
 | 
				
			||||||
 | 
					    let source = arguments[i] || {};
 | 
				
			||||||
 | 
					    for (let prop in source) {
 | 
				
			||||||
 | 
					      if (source.hasOwnProperty(prop)) {
 | 
				
			||||||
 | 
					        let value = source[prop];
 | 
				
			||||||
 | 
					        if (value !== undefined) {
 | 
				
			||||||
 | 
					          target[prop] = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return target;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										254
									
								
								components/AiOkrTree/model/node.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								components/AiOkrTree/model/node.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,254 @@
 | 
				
			|||||||
 | 
					import { markNodeData, NODE_KEY } from './util';
 | 
				
			||||||
 | 
					import objectAssign from './merge';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getPropertyFromData = function (node, prop) {
 | 
				
			||||||
 | 
					  const props = node.store.props;
 | 
				
			||||||
 | 
					  const data = node.data || {};
 | 
				
			||||||
 | 
					  const config = props[prop];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (typeof config === 'function') {
 | 
				
			||||||
 | 
					    return config(data, node);
 | 
				
			||||||
 | 
					  } else if (typeof config === 'string') {
 | 
				
			||||||
 | 
					    return data[config];
 | 
				
			||||||
 | 
					  } else if (typeof config === 'undefined') {
 | 
				
			||||||
 | 
					    const dataProp = data[prop];
 | 
				
			||||||
 | 
					    return dataProp === undefined ? '' : dataProp;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let nodeIdSeed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default class Node {
 | 
				
			||||||
 | 
					  constructor(options, isLeftChild = false) {
 | 
				
			||||||
 | 
					    this.isLeftChild = isLeftChild;
 | 
				
			||||||
 | 
					    this.id = nodeIdSeed++;
 | 
				
			||||||
 | 
					    this.data = null;
 | 
				
			||||||
 | 
					    this.expanded = false;
 | 
				
			||||||
 | 
					    this.leftExpanded = false;
 | 
				
			||||||
 | 
					    this.isCurrent = false;
 | 
				
			||||||
 | 
					    this.visible = true;
 | 
				
			||||||
 | 
					    this.parent = null;
 | 
				
			||||||
 | 
					    for (let name in options) {
 | 
				
			||||||
 | 
					      if (options.hasOwnProperty(name)) {
 | 
				
			||||||
 | 
					        this[name] = options[name];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.level = 0;
 | 
				
			||||||
 | 
					    this.childNodes = [];
 | 
				
			||||||
 | 
					    this.leftChildNodes = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.parent) {
 | 
				
			||||||
 | 
					      this.level = this.parent.level + 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const store = this.store;
 | 
				
			||||||
 | 
					    if (!store) {
 | 
				
			||||||
 | 
					      throw new Error('[Node]store is required!');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    store.registerNode(this);
 | 
				
			||||||
 | 
					    if (this.data) {
 | 
				
			||||||
 | 
					      this.setData(this.data, isLeftChild);
 | 
				
			||||||
 | 
					      if (store.defaultExpandAll || !store.showCollapsable) {
 | 
				
			||||||
 | 
					        this.expanded = true;
 | 
				
			||||||
 | 
					        this.leftExpanded = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!Array.isArray(this.data)) {
 | 
				
			||||||
 | 
					      markNodeData(this, this.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!this.data) return;
 | 
				
			||||||
 | 
					    const defaultExpandedKeys = store.defaultExpandedKeys;
 | 
				
			||||||
 | 
					    const key = store.key;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      key &&
 | 
				
			||||||
 | 
					      defaultExpandedKeys &&
 | 
				
			||||||
 | 
					      defaultExpandedKeys.indexOf(this.key) !== -1
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.expand(null, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      key &&
 | 
				
			||||||
 | 
					      store.currentNodeKey !== undefined &&
 | 
				
			||||||
 | 
					      this.key === store.currentNodeKey
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      store.currentNode = this;
 | 
				
			||||||
 | 
					      store.currentNode.isCurrent = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.updateLeafState();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setData(data, isLeftChild) {
 | 
				
			||||||
 | 
					    if (!Array.isArray(data)) {
 | 
				
			||||||
 | 
					      markNodeData(this, data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const store = this.store;
 | 
				
			||||||
 | 
					    this.data = data;
 | 
				
			||||||
 | 
					    this.childNodes = [];
 | 
				
			||||||
 | 
					    let children;
 | 
				
			||||||
 | 
					    if (this.level === 0 && this.data instanceof Array) {
 | 
				
			||||||
 | 
					      children = this.data;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      children = getPropertyFromData(this, 'children') || [];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (let i = 0, j = children.length; i < j; i++) {
 | 
				
			||||||
 | 
					      this.insertChild({ data: children[i] }, null, null, isLeftChild);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  get key() {
 | 
				
			||||||
 | 
					    const nodeKey = this.store.key;
 | 
				
			||||||
 | 
					    if (this.data) return this.data[nodeKey];
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  get label() {
 | 
				
			||||||
 | 
					    return getPropertyFromData(this, 'label');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // 是否是 OKR 飞书模式
 | 
				
			||||||
 | 
					  hasLeftChild() {
 | 
				
			||||||
 | 
					    const store = this.store;
 | 
				
			||||||
 | 
					    return store.onlyBothTree && store.direction === 'horizontal';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  insertChild(child, index, batch, isLeftChild) {
 | 
				
			||||||
 | 
					    if (!child) throw new Error('insertChild error: child is required.');
 | 
				
			||||||
 | 
					    if (!(child instanceof Node)) {
 | 
				
			||||||
 | 
					      if (!batch) {
 | 
				
			||||||
 | 
					        const children = this.getChildren(true);
 | 
				
			||||||
 | 
					        if (children.indexOf(child.data) === -1) {
 | 
				
			||||||
 | 
					          if (index === undefined || index === null || index < 0) {
 | 
				
			||||||
 | 
					            children.push(child.data);
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            children.splice(index, 0, child.data);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      objectAssign(child, {
 | 
				
			||||||
 | 
					        parent: this,
 | 
				
			||||||
 | 
					        store: this.store,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      child = new Node(child, isLeftChild);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    child.level = this.level + 1;
 | 
				
			||||||
 | 
					    if (index === undefined || index === null || index < 0) {
 | 
				
			||||||
 | 
					      this.childNodes.push(child);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.childNodes.splice(index, 0, child);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.updateLeafState();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getChildren(forceInit = false) {
 | 
				
			||||||
 | 
					    // this is data
 | 
				
			||||||
 | 
					    if (this.level === 0) return this.data;
 | 
				
			||||||
 | 
					    const data = this.data;
 | 
				
			||||||
 | 
					    if (!data) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const props = this.store.props;
 | 
				
			||||||
 | 
					    let children = 'children';
 | 
				
			||||||
 | 
					    if (props) {
 | 
				
			||||||
 | 
					      children = props.children || 'children';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (data[children] === undefined) {
 | 
				
			||||||
 | 
					      data[children] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (forceInit && !data[children]) {
 | 
				
			||||||
 | 
					      data[children] = [];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return data[children];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  updateLeafState() {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      this.store.lazy === true &&
 | 
				
			||||||
 | 
					      this.loaded !== true &&
 | 
				
			||||||
 | 
					      typeof this.isLeafByUser !== 'undefined'
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.isLeaf = this.isLeafByUser;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const childNodes = this.childNodes;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      !this.store.lazy ||
 | 
				
			||||||
 | 
					      (this.store.lazy === true && this.loaded === true)
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.isLeaf = !childNodes || childNodes.length === 0;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.isLeaf = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  updateLeftLeafState() {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      this.store.lazy === true &&
 | 
				
			||||||
 | 
					      this.loaded !== true &&
 | 
				
			||||||
 | 
					      typeof this.isLeafByUser !== 'undefined'
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.isLeaf = this.isLeafByUser;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const childNodes = this.leftChildNodes;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      !this.store.lazy ||
 | 
				
			||||||
 | 
					      (this.store.lazy === true && this.loaded === true)
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.isLeaf = !childNodes || childNodes.length === 0;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.isLeaf = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // 节点的收起
 | 
				
			||||||
 | 
					  collapse() {
 | 
				
			||||||
 | 
					    this.expanded = false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // 节点的展开
 | 
				
			||||||
 | 
					  expand(callback, expandParent) {
 | 
				
			||||||
 | 
					    const done = () => {
 | 
				
			||||||
 | 
					      if (expandParent) {
 | 
				
			||||||
 | 
					        let parent = this.parent;
 | 
				
			||||||
 | 
					        while (parent.level > 0) {
 | 
				
			||||||
 | 
					          parent.isLeftChild
 | 
				
			||||||
 | 
					            ? (parent.leftExpanded = true)
 | 
				
			||||||
 | 
					            : (parent.expanded = true);
 | 
				
			||||||
 | 
					          parent = parent.parent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.isLeftChild ? (this.leftExpanded = true) : (this.expanded = true);
 | 
				
			||||||
 | 
					      if (callback) callback();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    done();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  removeChild(child) {
 | 
				
			||||||
 | 
					    const children = this.getChildren() || [];
 | 
				
			||||||
 | 
					    const dataIndex = children.indexOf(child.data);
 | 
				
			||||||
 | 
					    if (dataIndex > -1) {
 | 
				
			||||||
 | 
					      children.splice(dataIndex, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const index = this.childNodes.indexOf(child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (index > -1) {
 | 
				
			||||||
 | 
					      this.store && this.store.deregisterNode(child);
 | 
				
			||||||
 | 
					      child.parent = null;
 | 
				
			||||||
 | 
					      this.childNodes.splice(index, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.updateLeafState();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  insertBefore(child, ref) {
 | 
				
			||||||
 | 
					    let index;
 | 
				
			||||||
 | 
					    if (ref) {
 | 
				
			||||||
 | 
					      index = this.childNodes.indexOf(ref);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.insertChild(child, index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  insertAfter(child, ref) {
 | 
				
			||||||
 | 
					    let index;
 | 
				
			||||||
 | 
					    if (ref) {
 | 
				
			||||||
 | 
					      index = this.childNodes.indexOf(ref);
 | 
				
			||||||
 | 
					      if (index !== -1) index += 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.insertChild(child, index);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								components/AiOkrTree/model/transition.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								components/AiOkrTree/model/transition.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					.okr-fade-in-enter,.okr-fade-in-leave-active,.okr-fade-in-linear-enter,.okr-fade-in-linear-leave,.okr-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.okr-fade-in-linear-enter-active,.okr-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.okr-fade-in-enter-active,.okr-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.okr-zoom-in-center-enter-active,.okr-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.okr-zoom-in-center-enter,.okr-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.okr-zoom-in-top-enter-active,.okr-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.okr-zoom-in-top-enter,.okr-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.okr-zoom-in-bottom-enter-active,.okr-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.okr-zoom-in-bottom-enter,.okr-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.okr-zoom-in-left-enter-active,.okr-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.okr-zoom-in-left-enter,.okr-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.okr-list-enter-active,.okr-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.okr-list-enter,.okr-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.okr-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}
 | 
				
			||||||
							
								
								
									
										176
									
								
								components/AiOkrTree/model/tree-store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								components/AiOkrTree/model/tree-store.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					import Node from "./node";
 | 
				
			||||||
 | 
					import { getNodeKey } from "./util";
 | 
				
			||||||
 | 
					export default class TreeStore {
 | 
				
			||||||
 | 
					  constructor(options) {
 | 
				
			||||||
 | 
					    this.currentNode = null;
 | 
				
			||||||
 | 
					    this.currentNodeKey = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let option in options) {
 | 
				
			||||||
 | 
					      if (options.hasOwnProperty(option)) {
 | 
				
			||||||
 | 
					        this[option] = options[option];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.nodesMap = {};
 | 
				
			||||||
 | 
					    this.root = new Node(
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        data: this.data,
 | 
				
			||||||
 | 
					        store: this
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      false
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (this.root.store.onlyBothTree) {
 | 
				
			||||||
 | 
					      if (!this.leftData)
 | 
				
			||||||
 | 
					        throw new Error("[Tree] leftData is required in onlyBothTree");
 | 
				
			||||||
 | 
					      if (this.leftData) {
 | 
				
			||||||
 | 
					        this.isLeftChilds = new Node(
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            data: this.leftData,
 | 
				
			||||||
 | 
					            store: this
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          true
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if (this.isLeftChilds) {
 | 
				
			||||||
 | 
					          this.root.childNodes[0].leftChildNodes = this.isLeftChilds.childNodes[0].childNodes;
 | 
				
			||||||
 | 
					          this.root.childNodes[0].leftExpanded = this.isLeftChilds.childNodes[0].leftExpanded;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  filter(value, childName = "childNodes") {
 | 
				
			||||||
 | 
					    this.filterRight(value, childName);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // 过滤默认节点
 | 
				
			||||||
 | 
					  filterRight(value, childName) {
 | 
				
			||||||
 | 
					    const filterNodeMethod = this.filterNodeMethod;
 | 
				
			||||||
 | 
					    const traverse = function(node, childName) {
 | 
				
			||||||
 | 
					      let childNodes;
 | 
				
			||||||
 | 
					      if (node.root) {
 | 
				
			||||||
 | 
					        childNodes = node.root.childNodes[0][childName];
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        childNodes = node.childNodes;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      childNodes.forEach(child => {
 | 
				
			||||||
 | 
					        child.visible = filterNodeMethod.call(child, value, child.data, child);
 | 
				
			||||||
 | 
					        traverse(child, childName);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!node.visible && childNodes.length) {
 | 
				
			||||||
 | 
					        let allHidden = true;
 | 
				
			||||||
 | 
					        allHidden = !childNodes.some(child => child.visible);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (node.root) {
 | 
				
			||||||
 | 
					          node.root.visible = allHidden === false;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          node.visible = allHidden === false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!value) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (node.visible) node.expand();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    traverse(this, childName);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  registerNode(node) {
 | 
				
			||||||
 | 
					    const key = this.key;
 | 
				
			||||||
 | 
					    if (!key || !node || !node.data) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const nodeKey = node.key;
 | 
				
			||||||
 | 
					    if (nodeKey !== undefined) this.nodesMap[node.key] = node;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  deregisterNode(node) {
 | 
				
			||||||
 | 
					    const key = this.key;
 | 
				
			||||||
 | 
					    if (!key || !node || !node.data) return;
 | 
				
			||||||
 | 
					    node.childNodes.forEach(child => {
 | 
				
			||||||
 | 
					      this.deregisterNode(child);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    delete this.nodesMap[node.key];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  setData(newVal) {
 | 
				
			||||||
 | 
					    const instanceChanged = newVal !== this.root.data;
 | 
				
			||||||
 | 
					    if (instanceChanged) {
 | 
				
			||||||
 | 
					      this.root.setData(newVal);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.root.updateChildren();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  updateChildren(key, data) {
 | 
				
			||||||
 | 
					    const node = this.nodesMap[key];
 | 
				
			||||||
 | 
					    if (!node) return;
 | 
				
			||||||
 | 
					    const childNodes = node.childNodes;
 | 
				
			||||||
 | 
					    for (let i = childNodes.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					      const child = childNodes[i];
 | 
				
			||||||
 | 
					      this.remove(child.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (let i = 0, j = data.length; i < j; i++) {
 | 
				
			||||||
 | 
					      const child = data[i];
 | 
				
			||||||
 | 
					      this.append(child, node.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getNode(data) {
 | 
				
			||||||
 | 
					    if (data instanceof Node) return data;
 | 
				
			||||||
 | 
					    const key = typeof data !== "object" ? data : getNodeKey(this.key, data);
 | 
				
			||||||
 | 
					    return this.nodesMap[key] || null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  setDefaultExpandedKeys(keys) {
 | 
				
			||||||
 | 
					    keys = keys || [];
 | 
				
			||||||
 | 
					    this.defaultExpandedKeys = keys;
 | 
				
			||||||
 | 
					    keys.forEach(key => {
 | 
				
			||||||
 | 
					      const node = this.getNode(key);
 | 
				
			||||||
 | 
					      if (node) node.expand(null, true);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  setCurrentNode(currentNode) {
 | 
				
			||||||
 | 
					    const prevCurrentNode = this.currentNode;
 | 
				
			||||||
 | 
					    if (prevCurrentNode) {
 | 
				
			||||||
 | 
					      prevCurrentNode.isCurrent = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.currentNode = currentNode;
 | 
				
			||||||
 | 
					    this.currentNode.isCurrent = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  setUserCurrentNode(node) {
 | 
				
			||||||
 | 
					    const key = node.key;
 | 
				
			||||||
 | 
					    const currNode = this.nodesMap[key];
 | 
				
			||||||
 | 
					    this.setCurrentNode(currNode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  setCurrentNodeKey(key) {
 | 
				
			||||||
 | 
					    if (key === null || key === undefined) {
 | 
				
			||||||
 | 
					      this.currentNode && (this.currentNode.isCurrent = false);
 | 
				
			||||||
 | 
					      this.currentNode = null;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const node = this.getNode(key);
 | 
				
			||||||
 | 
					    if (node) {
 | 
				
			||||||
 | 
					      this.setCurrentNode(node);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  getCurrentNode() {
 | 
				
			||||||
 | 
					    return this.currentNode;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  remove(data) {
 | 
				
			||||||
 | 
					    const node = this.getNode(data);
 | 
				
			||||||
 | 
					    if (node && node.parent) {
 | 
				
			||||||
 | 
					      if (node === this.currentNode) {
 | 
				
			||||||
 | 
					        this.currentNode = null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      node.parent.removeChild(node);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  append(data, parentData) {
 | 
				
			||||||
 | 
					    const parentNode = parentData ? this.getNode(parentData) : this.root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (parentNode) {
 | 
				
			||||||
 | 
					      parentNode.insertChild({ data });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  insertBefore(data, refData) {
 | 
				
			||||||
 | 
					    const refNode = this.getNode(refData);
 | 
				
			||||||
 | 
					    refNode.parent.insertBefore({ data }, refNode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  insertAfter(data, refData) {
 | 
				
			||||||
 | 
					    const refNode = this.getNode(refData);
 | 
				
			||||||
 | 
					    refNode.parent.insertAfter({ data }, refNode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								components/AiOkrTree/model/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								components/AiOkrTree/model/util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					export const NODE_KEY = "$treeNodeId";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const markNodeData = function(node, data) {
 | 
				
			||||||
 | 
					  if (!data || data[NODE_KEY]) return;
 | 
				
			||||||
 | 
					  Object.defineProperty(data, NODE_KEY, {
 | 
				
			||||||
 | 
					    value: node.id,
 | 
				
			||||||
 | 
					    enumerable: false,
 | 
				
			||||||
 | 
					    configurable: false,
 | 
				
			||||||
 | 
					    writable: false
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getNodeKey = function(key, data) {
 | 
				
			||||||
 | 
					  if (!key) return data[NODE_KEY];
 | 
				
			||||||
 | 
					  return data[key];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const findNearestComponent = (element, componentName) => {
 | 
				
			||||||
 | 
					  let target = element;
 | 
				
			||||||
 | 
					  while (target && target.tagName !== "BODY") {
 | 
				
			||||||
 | 
					    if (target.__vue__ && target.__vue__.$options.name === componentName) {
 | 
				
			||||||
 | 
					      return target.__vue__;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    target = target.parentNode;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return null;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Reference in New Issue
	
	Block a user