@lambo-design-mobile/workflow-approve 1.0.0-beta.1 → 1.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -3
- package/README.md +2 -38
- package/api.js +55 -3
- package/package.json +3 -3
- package/src/ApprovalNodeCell.vue +114 -0
- package/src/FlowApproval.vue +262 -151
- package/src/SelectHandle.vue +83 -39
- package/src/SelectHandleCard.vue +19 -6
- package/src/SelectNormalList.vue +111 -0
- package/src/SelectOrganize.vue +216 -0
- package/src/TodoListCard.vue +6 -2
- package/src/WorkflowDiagram.vue +18 -108
- package/src/assets/icon/iconfont.css +12 -4
- package/src/assets/icon/iconfont.js +1 -1
- package/src/assets/icon/iconfont.json +14 -0
- package/src/assets/icon/iconfont.ttf +0 -0
- package/src/assets/icon/iconfont.woff +0 -0
- package/src/assets/icon/iconfont.woff2 +0 -0
- package/src/js/global.js +19 -0
- package/src/tree/Node.vue +190 -0
- package/src/tree/Tree.vue +212 -0
- package/src/tree/util.js +74 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
|
|
2
|
+
<script>
|
|
3
|
+
import Node from './Node';
|
|
4
|
+
import {
|
|
5
|
+
broadCastMixins
|
|
6
|
+
} from './util';
|
|
7
|
+
export default {
|
|
8
|
+
name:"Tree",
|
|
9
|
+
render() {
|
|
10
|
+
let data = this.stateTree;
|
|
11
|
+
let showCheckBox = this.showCheckBox;
|
|
12
|
+
let loadData = this.loadData
|
|
13
|
+
return (
|
|
14
|
+
<div class={'tree'}>
|
|
15
|
+
{data && data.length
|
|
16
|
+
? data.map((item, index) => {
|
|
17
|
+
return (
|
|
18
|
+
<Node
|
|
19
|
+
class={'tree-node'}
|
|
20
|
+
key={index}
|
|
21
|
+
data={item}
|
|
22
|
+
showCheckBox={showCheckBox}
|
|
23
|
+
loadData={loadData}
|
|
24
|
+
>
|
|
25
|
+
|
|
26
|
+
{/*这里是插槽*/}
|
|
27
|
+
{this.$scopedSlots.default}
|
|
28
|
+
</Node>
|
|
29
|
+
);
|
|
30
|
+
})
|
|
31
|
+
: ''}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
},
|
|
35
|
+
components: {
|
|
36
|
+
Node
|
|
37
|
+
},
|
|
38
|
+
mixins: [broadCastMixins],
|
|
39
|
+
data() {
|
|
40
|
+
return {
|
|
41
|
+
stateTree: this.data,
|
|
42
|
+
flatTreeMap: {}
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
props: {
|
|
46
|
+
data: {
|
|
47
|
+
// 外部传入的数据
|
|
48
|
+
type: Array,
|
|
49
|
+
default () {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
showCheckBox: {
|
|
54
|
+
// 配置项,是否显示checkbox
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false
|
|
57
|
+
},
|
|
58
|
+
loadData: {
|
|
59
|
+
// 配置项,异步加载数据的回调方法,
|
|
60
|
+
type: Function
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
watch: {
|
|
64
|
+
data: {
|
|
65
|
+
deep: true,
|
|
66
|
+
handler() {
|
|
67
|
+
this.stateTree = this.data
|
|
68
|
+
|
|
69
|
+
this.flatTreeMap = this.transferFlatTree();
|
|
70
|
+
this.updateCheckedNodesChildren()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
methods: {
|
|
75
|
+
transferFlatTree() {
|
|
76
|
+
let keyCount = 0; // 定义一个key
|
|
77
|
+
//treeArr为树形结构数组,parent为父级
|
|
78
|
+
function flat(treeArr, parent = '') {
|
|
79
|
+
//如果没有值,则返回空对象
|
|
80
|
+
if (!treeArr && !treeArr.length) return {};
|
|
81
|
+
// 因为我们要把数据格式化成一个哈希表结构,也就是对象,所以用了个reduce方便处理
|
|
82
|
+
return treeArr.reduce((obj, cur) => {
|
|
83
|
+
//cur就是数组当前的元素,是个对象,我们给他添加一个属性nodeKey,key的值为keyCount
|
|
84
|
+
let nodeKey = keyCount;
|
|
85
|
+
cur.nodeKey = nodeKey;
|
|
86
|
+
//插入obj对象
|
|
87
|
+
obj[nodeKey] = {
|
|
88
|
+
nodeKey: keyCount,
|
|
89
|
+
parent,
|
|
90
|
+
// ...cur
|
|
91
|
+
node: cur // 把当前节点赋值给属性node
|
|
92
|
+
};
|
|
93
|
+
// 为了保证每一个key都是唯一,每次都要累加
|
|
94
|
+
keyCount++;
|
|
95
|
+
if (cur.children && cur.children.length) {
|
|
96
|
+
//如果有子节点 进行一次递归
|
|
97
|
+
obj = { ...obj,
|
|
98
|
+
...flat(cur.children, cur)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return obj;
|
|
102
|
+
}, {});
|
|
103
|
+
}
|
|
104
|
+
return flat(this.stateTree); // 返回出格式化后的对象
|
|
105
|
+
},
|
|
106
|
+
updateCheckedNodesChildren() {
|
|
107
|
+
// 获取勾选的节点,
|
|
108
|
+
const checkedNodes = this.getCheckedNodes();
|
|
109
|
+
checkedNodes.forEach((node) => {
|
|
110
|
+
// 勾选的节点的子节点也进行勾选
|
|
111
|
+
this.updateTreeDown(node.node, true);
|
|
112
|
+
// 获取到所有已选节点的父几节点
|
|
113
|
+
// const parentKey = this.flatTreeMap[node.nodeKey].parent.nodeKey;
|
|
114
|
+
// // 如果为顶部节点则返回
|
|
115
|
+
// if (!parentKey && parentKey !== 0) return;
|
|
116
|
+
// //获取父几节点
|
|
117
|
+
// const parent = this.flatTreeMap[parentKey].node
|
|
118
|
+
// // 如果当前节点已经勾选
|
|
119
|
+
// const childHasCheckSetter =
|
|
120
|
+
// typeof node.checked != 'undefined' && node.checked;
|
|
121
|
+
// console.log(childHasCheckSetter && parent.checked != node.checked)
|
|
122
|
+
// if (childHasCheckSetter && parent.checked != node.checked) { //如果父节点和子节点存在差异
|
|
123
|
+
// this.updateTreeUp(node.nodeKey); // update tree upwards
|
|
124
|
+
// }
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
updateTreeUp(nodeKey) {
|
|
128
|
+
// 获取该节点parent节点的nodeKey
|
|
129
|
+
const parentKey = this.flatTreeMap[nodeKey].parent.nodeKey;
|
|
130
|
+
//如果没有则返回,递归停止判断,如果没有父级节点则不继续递归
|
|
131
|
+
if (typeof parentKey == 'undefined') return;
|
|
132
|
+
// 获取当前nodeKey的节点数据
|
|
133
|
+
const node = this.flatTreeMap[nodeKey].node
|
|
134
|
+
// 获取parent的节点数据
|
|
135
|
+
const parent = this.flatTreeMap[parentKey].node
|
|
136
|
+
// 如果勾选状态一样则返回,不用做任何操作
|
|
137
|
+
if (node.checked == parent.checked) return;
|
|
138
|
+
// 否则,当子节点有勾选时,判断他的同级节点是不是都是勾选状态,如果是,则父级节点勾选
|
|
139
|
+
// 如果同级节点有些没有勾选,则返回falst,父级节点不勾选
|
|
140
|
+
if (node.checked == true) {
|
|
141
|
+
// 如果当前已勾选,则父几全部勾选
|
|
142
|
+
// this.$set(
|
|
143
|
+
// parent,
|
|
144
|
+
// 'checked',
|
|
145
|
+
// parent['children'].every((node) => node.checked)
|
|
146
|
+
// );
|
|
147
|
+
} else {
|
|
148
|
+
// 如果当前节点不勾选则父级节点不勾选
|
|
149
|
+
this.$set(parent, 'checked', false);
|
|
150
|
+
}
|
|
151
|
+
// 向上递归,直到根节点
|
|
152
|
+
this.updateTreeUp(parentKey);
|
|
153
|
+
},
|
|
154
|
+
handleCheck(v) {
|
|
155
|
+
if (!this.flatTreeMap[v.nodeKey]) return;
|
|
156
|
+
const node = this.flatTreeMap[v.nodeKey]
|
|
157
|
+
this.$set(node, 'checked', v.checked);
|
|
158
|
+
this.updateTreeUp(v.nodeKey);
|
|
159
|
+
this.updateTreeDown(v, v.checked);
|
|
160
|
+
// 定义勾选方法
|
|
161
|
+
this.$emit('onChecked', v);
|
|
162
|
+
},
|
|
163
|
+
handleSelect(v) {
|
|
164
|
+
// 定义点击节点方法
|
|
165
|
+
this.$emit('onSelect', v);
|
|
166
|
+
},
|
|
167
|
+
handleExpand(v) {
|
|
168
|
+
// 定义点击展开方法
|
|
169
|
+
this.$emit('onExpand', v);
|
|
170
|
+
},
|
|
171
|
+
getCheckedNodes() {
|
|
172
|
+
// 获取勾选的节点
|
|
173
|
+
return Object.values(this.flatTreeMap).filter(
|
|
174
|
+
(item) => item.node.checked
|
|
175
|
+
);
|
|
176
|
+
},
|
|
177
|
+
getCheckedChildrenNodes() {
|
|
178
|
+
// 仅获取勾选的子节点
|
|
179
|
+
return Object.values(this.flatTreeMap).filter(
|
|
180
|
+
(item) => item.node.checked && !item.node.children
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
// node为当前勾选的节点,checked为否勾选的值
|
|
184
|
+
updateTreeDown(node, checked) {
|
|
185
|
+
this.$set(node, 'checked', checked); // 先设置它的勾选状态
|
|
186
|
+
if (node['children']) {
|
|
187
|
+
// 如果有子节点
|
|
188
|
+
// node['children'].forEach((child) => {
|
|
189
|
+
// //则进行一次递归,让子节点也设置同样的勾选值
|
|
190
|
+
// this.updateTreeDown(child, checked);
|
|
191
|
+
// });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
created() {
|
|
196
|
+
this.on('handleCheck', this.handleCheck);
|
|
197
|
+
this.on('handleSelect', this.handleSelect);
|
|
198
|
+
this.on('handleExpand', this.handleExpand);
|
|
199
|
+
|
|
200
|
+
this.flatTreeMap = this.transferFlatTree();
|
|
201
|
+
this.updateCheckedNodesChildren()
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
</script>
|
|
205
|
+
|
|
206
|
+
<style scoped>
|
|
207
|
+
.tree-node {
|
|
208
|
+
font-size: 30px;
|
|
209
|
+
width: 90%;
|
|
210
|
+
margin: 0 auto;
|
|
211
|
+
}
|
|
212
|
+
</style>
|
package/src/tree/util.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 发布订阅模式,
|
|
3
|
+
* 消息发布中心
|
|
4
|
+
* @class BroadCast
|
|
5
|
+
*/
|
|
6
|
+
class BroadCast {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.listMap = {}; // 存储监听者
|
|
9
|
+
}
|
|
10
|
+
emit(k, v) {
|
|
11
|
+
// 发布消息函数,k为监听者的key,v为需要传值的value
|
|
12
|
+
this.listMap[k] &&
|
|
13
|
+
this.listMap[k].map((fn) => {
|
|
14
|
+
fn.call(null, v);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
on(k, fn) {
|
|
18
|
+
// 添加监听者,,k为监听者的key,fn为执行的回调函数
|
|
19
|
+
if (!this.listMap[k]) {
|
|
20
|
+
this.listMap[k] = [];
|
|
21
|
+
}
|
|
22
|
+
this.listMap[k].push(fn);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const broadCast = new BroadCast();
|
|
27
|
+
export const broadCastMixins = {
|
|
28
|
+
methods: {
|
|
29
|
+
// 定义broadcast发布消息方法
|
|
30
|
+
broadCast(k, v) {
|
|
31
|
+
broadCast.emit(k, v);
|
|
32
|
+
},
|
|
33
|
+
on(k, fn) {
|
|
34
|
+
// 定义接收消息方法
|
|
35
|
+
broadCast.on(k, fn);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const formatTree = (arr) => {
|
|
41
|
+
console.log(arr);
|
|
42
|
+
// 有可能存在多个最外层的父级节点,先把他们找出来
|
|
43
|
+
function findParents(arr) {
|
|
44
|
+
// arr为原数组
|
|
45
|
+
//通过reduce方法把数组转换成对象,作为一个哈希表(说白了就是个对象)存储他们的id
|
|
46
|
+
const map = arr.reduce((obj, cur) => {
|
|
47
|
+
let id = cur['id']; // 获取每一项的id
|
|
48
|
+
obj[id] = id;
|
|
49
|
+
return obj;
|
|
50
|
+
}, {});
|
|
51
|
+
// 最后做一次筛选,找出最外层的父级节点数据
|
|
52
|
+
return arr.filter((item) => !map[item.parentId]);
|
|
53
|
+
}
|
|
54
|
+
let parents = findParents(arr); // 获取最外层父级节点
|
|
55
|
+
// 查找每个parents 对应的子孙节点,此处开始递归
|
|
56
|
+
function findChildren(parents) {
|
|
57
|
+
if (!parents) return;
|
|
58
|
+
parents.forEach((p) => {
|
|
59
|
+
arr.forEach((item) => {
|
|
60
|
+
// 如果原数组arr里面的每一项中的parentId恒等于父级的某一个节点的id,则把它推进父级的children数组里面
|
|
61
|
+
if (p.id === item.parentId) {
|
|
62
|
+
if (!p.children) {
|
|
63
|
+
p.children = [];
|
|
64
|
+
}
|
|
65
|
+
p.children.push(item);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// 最后进行一次递归,找儿子们的儿子们
|
|
69
|
+
findChildren(p.children);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
findChildren(parents);
|
|
73
|
+
return parents;
|
|
74
|
+
};
|