diff --git a/imt-ui/src/components/VueOkrTree/index.js b/imt-ui/src/components/VueOkrTree/index.js new file mode 100644 index 0000000..7bb36f5 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/index.js @@ -0,0 +1 @@ +export { default as VueOkrTree } from "./vue-okr-tree/OkrTree.vue"; diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTree.vue b/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTree.vue new file mode 100644 index 0000000..669ed23 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTree.vue @@ -0,0 +1,742 @@ + + + + diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTreeNode.vue b/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTreeNode.vue new file mode 100644 index 0000000..6170687 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/OkrTreeNode.vue @@ -0,0 +1,473 @@ + + diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle-red.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle-red.png new file mode 100644 index 0000000..a94160d Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle-red.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle.png new file mode 100644 index 0000000..f43ccdb Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/circle.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond-red.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond-red.png new file mode 100644 index 0000000..f0b7237 Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond-red.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond.png new file mode 100644 index 0000000..b2ffb18 Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/diamond.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle-red.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle-red.png new file mode 100644 index 0000000..44a3238 Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle-red.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle.png new file mode 100644 index 0000000..6b01bec Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/rectangle.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle-red.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle-red.png new file mode 100644 index 0000000..d429acb Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle-red.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle.png b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle.png new file mode 100644 index 0000000..4886c93 Binary files /dev/null and b/imt-ui/src/components/VueOkrTree/vue-okr-tree/imgs/trigle.png differ diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/merge.js b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/merge.js new file mode 100644 index 0000000..66ebbfd --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/merge.js @@ -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; +} diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/node.js b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/node.js new file mode 100644 index 0000000..2c6c3a0 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/node.js @@ -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); + } +} diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/transition.css b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/transition.css new file mode 100644 index 0000000..2769719 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/transition.css @@ -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)} \ No newline at end of file diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/tree-store.js b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/tree-store.js new file mode 100644 index 0000000..32a8df6 --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/tree-store.js @@ -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); + } +} diff --git a/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/util.js b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/util.js new file mode 100644 index 0000000..e53acac --- /dev/null +++ b/imt-ui/src/components/VueOkrTree/vue-okr-tree/model/util.js @@ -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; +}; diff --git a/imt-ui/src/views/system/inspectionPlan/inspectionPlanTree.vue b/imt-ui/src/views/system/inspectionPlan/inspectionPlanTree.vue new file mode 100644 index 0000000..f0be81f --- /dev/null +++ b/imt-ui/src/views/system/inspectionPlan/inspectionPlanTree.vue @@ -0,0 +1,214 @@ + + + \ No newline at end of file