Compare commits
2 Commits
e005d1c06d
...
4a0a4ffe47
Author | SHA1 | Date | |
---|---|---|---|
4a0a4ffe47 | |||
1cea7aae79 |
@ -70,6 +70,7 @@
|
|||||||
"vue-count-to": "1.0.13",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-cropper": "0.5.8",
|
"vue-cropper": "0.5.8",
|
||||||
"vue-meta": "^2.4.0",
|
"vue-meta": "^2.4.0",
|
||||||
|
"vue-okr-tree": "^1.0.17",
|
||||||
"vue-quill-editor": "^3.0.6",
|
"vue-quill-editor": "^3.0.6",
|
||||||
"vue-router": "3.4.9",
|
"vue-router": "3.4.9",
|
||||||
"vue-video-player": "^5.0.2",
|
"vue-video-player": "^5.0.2",
|
||||||
@ -95,7 +96,7 @@
|
|||||||
"eslint-plugin-prettier": "^3.1.0",
|
"eslint-plugin-prettier": "^3.1.0",
|
||||||
"eslint-plugin-vue": "9.0.0",
|
"eslint-plugin-vue": "9.0.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^8.1.0",
|
||||||
"html-webpack-plugin": "^5.6.0",
|
"html-webpack-plugin": "^4.5.2",
|
||||||
"lint-staged": "12.5.0",
|
"lint-staged": "12.5.0",
|
||||||
"runjs": "4.4.2",
|
"runjs": "4.4.2",
|
||||||
"sass": "1.32.13",
|
"sass": "1.32.13",
|
||||||
|
1
imt-ui/src/components/VueOkrTree/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as VueOkrTree } from "./vue-okr-tree/OkrTree.vue";
|
742
imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTree.vue
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
<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: "OkrTree",
|
||||||
|
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: 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);
|
||||||
|
},
|
||||||
|
leftData(newVal) {
|
||||||
|
this.store.setLeftData(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 lang="scss">
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
.org-chart-node-label {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
background-image: url("./imgs/rectangle.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: none !important;
|
||||||
|
// border: 1px solid black;
|
||||||
|
// border-radius: 8px;
|
||||||
|
box-shadow: 5px 5px 10px 0 rgba(0, 0, 0, 0.5);
|
||||||
|
background-position: center;
|
||||||
|
&.red {
|
||||||
|
background-image: url("./imgs/rectangle-red.png");
|
||||||
|
}
|
||||||
|
&.diamondType {
|
||||||
|
background-image: url("./imgs/diamond.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: none !important;
|
||||||
|
background-position: center;
|
||||||
|
padding: 12px 24px;
|
||||||
|
&.red {
|
||||||
|
background-image: url("./imgs/diamond-red.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.trigle {
|
||||||
|
background-image: url("./imgs/trigle.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: none !important;
|
||||||
|
background-position: center;
|
||||||
|
padding: 14px 30px 2px 30px;
|
||||||
|
&.red {
|
||||||
|
background-image: url("./imgs/trigle-red.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.circle {
|
||||||
|
background-image: url("./imgs/circle.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: none !important;
|
||||||
|
background-position: center;
|
||||||
|
&.red {
|
||||||
|
background-image: url("./imgs/circle-red.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.trigleReverse {
|
||||||
|
background-image: url("./imgs/trigle.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: none !important;
|
||||||
|
background-position: center;
|
||||||
|
padding: 14px 30px 2px 30px;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
&.red {
|
||||||
|
background-image: url("./imgs/trigle-red.png");
|
||||||
|
}
|
||||||
|
.label-innner {
|
||||||
|
display: inline-block;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.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>
|
473
imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTreeNode.vue
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
<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"
|
||||||
|
:style="{
|
||||||
|
visibility: node.leftExpanded ? '' : 'hidden',
|
||||||
|
height: node.leftExpanded ? '' : '0',
|
||||||
|
}"
|
||||||
|
v-if="showLeftChildNode"
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="label-innner"
|
||||||
|
:style="computeInnerStyle"
|
||||||
|
>
|
||||||
|
<node-content :node="node">
|
||||||
|
<slot>
|
||||||
|
{{ node.label }}
|
||||||
|
</slot>
|
||||||
|
</node-content></span>
|
||||||
|
</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"
|
||||||
|
:style="{
|
||||||
|
visibility: node.expanded ? '' : 'hidden',
|
||||||
|
height: node.expanded ? '' : '0',
|
||||||
|
}"
|
||||||
|
v-if="!isLeftChildNode && node.childNodes && node.childNodes.length > 0"
|
||||||
|
>
|
||||||
|
<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";
|
||||||
|
import _ from "lodash";
|
||||||
|
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
|
||||||
|
);
|
||||||
|
},
|
||||||
|
computeInnerStyle() {
|
||||||
|
let color = _.get(this.node, ["data", "nodeFontColor"]);
|
||||||
|
let borderShape = _.get(this.node, ["data", "nodeShapeType"]);
|
||||||
|
let obj = { color };
|
||||||
|
if (borderShape === "diamond") {
|
||||||
|
// obj = Object.assign(obj, {
|
||||||
|
// display: "inline-block",
|
||||||
|
// transform: "skewX(-30deg)",
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
// 节点的宽度
|
||||||
|
computeLabelStyle() {
|
||||||
|
// console.log("this.node", this.node);
|
||||||
|
let { labelWidth = "auto", labelHeight = "auto" } = this;
|
||||||
|
if (typeof labelWidth === "number") {
|
||||||
|
labelWidth = `${labelWidth}px`;
|
||||||
|
}
|
||||||
|
if (typeof labelHeight === "number") {
|
||||||
|
labelHeight = `${labelHeight}px`;
|
||||||
|
}
|
||||||
|
// let borderColor = _.get(this.node, ["data", "nodeBorderColor"]);
|
||||||
|
let borderShape = _.get(this.node, ["data", "nodeShapeType"]);
|
||||||
|
let obj = {
|
||||||
|
width: labelWidth,
|
||||||
|
height: labelHeight,
|
||||||
|
// border: `1px solid ${borderColor}`,
|
||||||
|
};
|
||||||
|
// if (borderShape === "circle") {
|
||||||
|
// obj = Object.assign(obj, { borderRadius: "50%" });
|
||||||
|
// }
|
||||||
|
// if (borderShape === "diamond") {
|
||||||
|
// // obj = Object.assign(obj, {
|
||||||
|
// // transform: "skewX(30deg)",
|
||||||
|
// // });
|
||||||
|
// obj = Object.assign(obj, {
|
||||||
|
// backgroundImage: require("@/assets/images/okrTree/diamond.png"),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
if (borderShape === "trigle-correct") {
|
||||||
|
}
|
||||||
|
if (borderShape === "trigle-reverse") {
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
computeLabelClass() {
|
||||||
|
let clsArr = [];
|
||||||
|
let borderShape = _.get(this.node, ["data", "nodeShapeType"]);
|
||||||
|
let borderColor = _.get(this.node, ["data", "nodeBorderColor"]);
|
||||||
|
if (borderColor === "red") {
|
||||||
|
clsArr.push("red");
|
||||||
|
}
|
||||||
|
if (borderShape === "diamond") {
|
||||||
|
clsArr.push("diamondType");
|
||||||
|
}
|
||||||
|
if (borderShape === "trigle") {
|
||||||
|
clsArr.push("trigle");
|
||||||
|
}
|
||||||
|
if (borderShape === "trigleReverse") {
|
||||||
|
clsArr.push("trigleReverse");
|
||||||
|
}
|
||||||
|
if (borderShape === "circle") {
|
||||||
|
clsArr.push("circle");
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
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>
|
After Width: | Height: | Size: 3.9 KiB |
BIN
imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
BIN
imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 611 B |
BIN
imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle.png
Normal file
After Width: | Height: | Size: 609 B |
After Width: | Height: | Size: 1.9 KiB |
BIN
imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
14
imt-ui/src/components/VueOkrTree/vue-okr-tree/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
imt-ui/src/components/VueOkrTree/vue-okr-tree/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);
|
||||||
|
}
|
||||||
|
}
|
@ -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)}
|
@ -0,0 +1,180 @@
|
|||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setLeftData(this.leftData);
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
this.setLeftData(this.leftData)
|
||||||
|
}
|
||||||
|
setLeftData(leftData) {
|
||||||
|
if (this.root.store.onlyBothTree) {
|
||||||
|
if (!leftData)
|
||||||
|
throw new Error("[Tree] leftData is required in onlyBothTree");
|
||||||
|
if (this.leftData) {
|
||||||
|
this.isLeftChilds = new Node(
|
||||||
|
{
|
||||||
|
data: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
imt-ui/src/components/VueOkrTree/vue-okr-tree/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;
|
||||||
|
};
|
@ -279,12 +279,13 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const res = await GatewayInfoApi.getGatewayInfo(id);
|
const res = await GatewayInfoApi.getGatewayInfo(id);
|
||||||
this.formData = res.data;
|
this.formData = res.data;
|
||||||
this.title = "修改机床网关信息";
|
this.dialogTitle = "修改机床网关信息";
|
||||||
} finally {
|
} finally {
|
||||||
this.formLoading = false;
|
this.formLoading = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.dialogTitle = "新增机床网关信息";
|
||||||
}
|
}
|
||||||
this.title = "新增机床网关信息";
|
|
||||||
},
|
},
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
async submitForm() {
|
async submitForm() {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
:title="dialogTitle"
|
:title="dialogTitle"
|
||||||
:visible.sync="dialogVisible"
|
:visible.sync="dialogVisible"
|
||||||
width="45%"
|
width="55%"
|
||||||
v-dialogDrag
|
v-dialogDrag
|
||||||
append-to-body
|
append-to-body
|
||||||
>
|
>
|
||||||
@ -13,12 +13,11 @@
|
|||||||
:model="formData"
|
:model="formData"
|
||||||
:rules="formRules"
|
:rules="formRules"
|
||||||
v-loading="formLoading"
|
v-loading="formLoading"
|
||||||
label-width="100px"
|
label-width="110px"
|
||||||
>
|
>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="this.formData.parentInspectionId != 0"
|
label="点检方案父节点"
|
||||||
label="父节点点检方案"
|
|
||||||
prop="parentInspectionId"
|
prop="parentInspectionId"
|
||||||
>
|
>
|
||||||
<!-- <el-input
|
<!-- <el-input
|
||||||
@ -156,7 +155,10 @@ export default {
|
|||||||
"inspectionPlanId",
|
"inspectionPlanId",
|
||||||
"parentInspectionId"
|
"parentInspectionId"
|
||||||
);
|
);
|
||||||
console.log("inspectionOptions:", this.inspectionOptions);
|
this.inspectionOptions.push({
|
||||||
|
inspectionPlanId: 0,
|
||||||
|
inspectionName: "无",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 转换菜单数据结构 */
|
/** 转换菜单数据结构 */
|
||||||
@ -186,12 +188,13 @@ export default {
|
|||||||
} finally {
|
} finally {
|
||||||
this.formLoading = false;
|
this.formLoading = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.dialogTitle = "新增点检方案";
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.formData.status = CommonStatusEnum.ENABLE;
|
||||||
|
this.formData.parentInspectionId = this.pid;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.dialogTitle = "新增点检方案";
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.formData.status = CommonStatusEnum.ENABLE;
|
|
||||||
this.formData.parentInspectionId = this.pid;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
async submitForm() {
|
async submitForm() {
|
||||||
|
@ -94,7 +94,6 @@
|
|||||||
>
|
>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
label="基础点检名"
|
label="基础点检名"
|
||||||
align="center"
|
|
||||||
prop="inspectionName"
|
prop="inspectionName"
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
@ -170,6 +169,7 @@
|
|||||||
import * as InspectionPlanApi from "@/api/system/inspection/plan";
|
import * as InspectionPlanApi from "@/api/system/inspection/plan";
|
||||||
import InspectionPlanForm from "./InspectionPlanForm.vue";
|
import InspectionPlanForm from "./InspectionPlanForm.vue";
|
||||||
import { getDictDatas, DICT_TYPE } from "@/utils/dict";
|
import { getDictDatas, DICT_TYPE } from "@/utils/dict";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "InspectionPlan",
|
name: "InspectionPlan",
|
||||||
components: {
|
components: {
|
||||||
@ -188,7 +188,7 @@ export default {
|
|||||||
// 点检方案列表
|
// 点检方案列表
|
||||||
list: [],
|
list: [],
|
||||||
// 是否展开,默认全部展开
|
// 是否展开,默认全部展开
|
||||||
isExpandAll: true,
|
isExpandAll: false,
|
||||||
// 重新渲染表格状态
|
// 重新渲染表格状态
|
||||||
refreshTable: true,
|
refreshTable: true,
|
||||||
// 选中行
|
// 选中行
|
||||||
|
214
imt-ui/src/views/system/inspectionPlan/inspectionPlanTree.vue
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading">
|
||||||
|
<el-checkbox-group
|
||||||
|
v-model="selectedTreeList"
|
||||||
|
@change="selectedTreeChange"
|
||||||
|
>
|
||||||
|
<el-checkbox
|
||||||
|
v-for="(tree,index) in treeData"
|
||||||
|
:key="tree.inspectionPlanId"
|
||||||
|
:label="tree.inspectionPlanId"
|
||||||
|
style="display:flex;align-items:center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="component-wrapper"
|
||||||
|
style="margin:0 3%;"
|
||||||
|
>
|
||||||
|
<vue-okr-tree
|
||||||
|
class="custom-tree"
|
||||||
|
:data="objToList(tree)"
|
||||||
|
node-key="nodeId"
|
||||||
|
direction="horizontal"
|
||||||
|
:props="props"
|
||||||
|
show-collapsable
|
||||||
|
default-expand-all
|
||||||
|
:current-lable-class-name="renderCurrentClass"
|
||||||
|
@node-click="nodeClick"
|
||||||
|
></vue-okr-tree>
|
||||||
|
</div>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { VueOkrTree } from "@/components/VueOkrTree/index.js";
|
||||||
|
import * as InspectionPlanApi from "@/api/system/inspection/plan";
|
||||||
|
import alipayChannelFormVue from "../../pay/app/components/alipayChannelForm.vue";
|
||||||
|
export default {
|
||||||
|
name: "InspectionPlanForm",
|
||||||
|
components: {
|
||||||
|
VueOkrTree,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
treeData: [
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
label: "XXX科技有限公司",
|
||||||
|
value: "a",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
label: "产品研发部",
|
||||||
|
value: "b",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
label: "研发-前端",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
label: "研发-后端",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
label: "UI设计",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
label: "产品经理",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
label: "销售部",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
label: "销售一部",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
label: "销售二部",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
label: "财务部",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
label: "HR人事",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
expandAll: false,
|
||||||
|
horizontal: true,
|
||||||
|
collapsable: true,
|
||||||
|
loading: false,
|
||||||
|
props: {
|
||||||
|
label: "inspectionName",
|
||||||
|
},
|
||||||
|
selectedTreeList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// this.toggleExpand(this.data, true);
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
nodeClick(obj, node) {
|
||||||
|
console.log("点击obj:", obj);
|
||||||
|
console.log("点击node:", node);
|
||||||
|
},
|
||||||
|
renderCurrentClass(node) {
|
||||||
|
return "label-bg-blue";
|
||||||
|
},
|
||||||
|
selectedTreeChange() {
|
||||||
|
console.log("选择:", this.selectedTreeList);
|
||||||
|
},
|
||||||
|
objToList(obj) {
|
||||||
|
return [obj];
|
||||||
|
},
|
||||||
|
/** 查询列表 */
|
||||||
|
async getList() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
const res = await InspectionPlanApi.getInspectionPlanList();
|
||||||
|
this.treeData = this.handleTree(
|
||||||
|
res.data,
|
||||||
|
"inspectionPlanId",
|
||||||
|
"parentInspectionId"
|
||||||
|
);
|
||||||
|
console.log("treeData:", this.treeData);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderLabelClass(node) {
|
||||||
|
return node.label.length < 16 ? "companyItem" : "companyHItem";
|
||||||
|
},
|
||||||
|
toggleExpand(data, val) {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
data.forEach((item) => {
|
||||||
|
this.$set(item, "expand", val);
|
||||||
|
if (item.children) {
|
||||||
|
this.toggleExpand(item.children, val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$set(data, "expand", val);
|
||||||
|
if (data.children) {
|
||||||
|
this.toggleExpand(data.children, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onExpand: function (e, data) {
|
||||||
|
if ("expand" in data) {
|
||||||
|
data.expand = !data.expand;
|
||||||
|
|
||||||
|
if (!data.expand && data.children) {
|
||||||
|
console.log("kkkkkkkkkkk");
|
||||||
|
this.collapse(data.children);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$set(data, "expand", true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collapse: function (list) {
|
||||||
|
var _this = this;
|
||||||
|
console.log(list, "kkkkkkk");
|
||||||
|
list.forEach(function (child) {
|
||||||
|
console.log(child, "kkkkkkkkkk");
|
||||||
|
if (child.expand) {
|
||||||
|
child.expand = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.children && _this.collapse(child.children);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleNodeClick(e, data) {
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
// renderContent: function (h, data) {
|
||||||
|
// console.log(data, "kkkkk");
|
||||||
|
// return h("div", [h("span", data.label), h("br"), h("span", "已完成")]);
|
||||||
|
// },
|
||||||
|
// renderContent(h, { node, data, store }) {
|
||||||
|
// console.log("data:", data.$treeNodeId);
|
||||||
|
// return h(
|
||||||
|
// "span",
|
||||||
|
// {
|
||||||
|
// style: {
|
||||||
|
// margin: "0 10px",
|
||||||
|
// color: data.$treeNodeId % 2 === 0 ? "#f00" : "#000", // 使用颜色区分节点
|
||||||
|
// fontSize: "16px",
|
||||||
|
// fontFamily: "Arial, sans-serif",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// data.inspectionName
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.label-bg-blue {
|
||||||
|
background: #1989fa;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|