@lambo-design-mobile/workflow-approve 1.0.0-beta.2 → 1.0.0-beta.3

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.
@@ -0,0 +1,111 @@
1
+ <template>
2
+ <div>
3
+ <div class="van-nav-bar__content">
4
+ <div class="van-nav-bar__title">{{ title }}</div>
5
+ </div>
6
+ <div v-if="idList.length > 0">
7
+ <van-checkbox-group v-model="result">
8
+ <van-cell-group>
9
+ <van-cell
10
+ v-for="(item, index) in list"
11
+ clickable
12
+ :key="item.id"
13
+ :title="item.name"
14
+ @click="toggle(index)"
15
+ >
16
+ <template #right-icon>
17
+ <van-checkbox :name="item" ref="checkboxes" />
18
+ </template>
19
+ </van-cell>
20
+ </van-cell-group>
21
+ </van-checkbox-group>
22
+ </div>
23
+ <div v-else>
24
+ <van-empty description="流程类型未定义权限范围" />
25
+ </div>
26
+ <div class="custom-bottom-bar">
27
+ <div class="bar-item" @click="selectNormalListHandle('cancel')">取消</div>
28
+ <div class="bar-item approve" @click="selectNormalListHandle('select')">选择</div>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script>
34
+ export default {
35
+ name: "SelectNormalList",
36
+ props: {
37
+ title: {
38
+ type: String,
39
+ default: ''
40
+ },
41
+ idList: {
42
+ type: Array,
43
+ default: () => [],
44
+ required: true,
45
+ },
46
+ parseFunction: {
47
+ type: Function,
48
+ required: true,
49
+ default: (idList) => idList.map(id => ({ id, name: `Name for ${id}` })) // 示例默认解析
50
+ },
51
+ },
52
+ data() {
53
+ return {
54
+ list: [],
55
+ result: [],
56
+ };
57
+ },
58
+ created() {
59
+ // 使用传入的解析函数获取 list 数据
60
+ this.parseFunction(this.idList).then((parsedList) => {
61
+ this.list = parsedList;
62
+ });
63
+ },
64
+ methods: {
65
+ toggle(index) {
66
+ this.$refs.checkboxes[index].toggle();
67
+ },
68
+ selectNormalListHandle(handle) {
69
+ this.$emit('selectNormalListHandle', handle, this.result);
70
+ },
71
+ },
72
+ };
73
+ </script>
74
+
75
+ <style scoped>
76
+ .custom-bottom-bar {
77
+ position: fixed;
78
+ bottom: 0;
79
+ width: 100%;
80
+ display: flex;
81
+ justify-content: space-around;
82
+ background-color: #fff;
83
+ padding: 10px 0;
84
+ border-top: 1px solid #eaeaea;
85
+ box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.05);
86
+ z-index: 1000;
87
+ }
88
+
89
+ .bar-item {
90
+ flex: 1;
91
+ text-align: center;
92
+ padding: 10px 0;
93
+ font-size: 16px;
94
+ border-radius: 4px;
95
+ }
96
+
97
+ .bar-item:active {
98
+ background-color: #e6e6e6;
99
+ }
100
+
101
+ .approve {
102
+ color: #fff;
103
+ background: linear-gradient(90deg, #0096FF, #1677FF);
104
+ border-radius: 9px;
105
+ margin: 0 20px;
106
+ }
107
+
108
+ .approve:active {
109
+ background: linear-gradient(90deg, rgba(0, 150, 255, 0.8), rgba(22, 119, 255, 0.8));
110
+ }
111
+ </style>
@@ -0,0 +1,216 @@
1
+ <template>
2
+ <div>
3
+ <div class="van-nav-bar__content">
4
+ <div class="van-nav-bar__title">选择组织</div>
5
+ </div>
6
+ <div v-if="this.organizeIdList.length > 0 || allOrganize === true">
7
+ <Tree
8
+ :data="data"
9
+ :showCheckBox="showCheckBox"
10
+ @onChecked="handleChecked"
11
+ @onExpand="handleExpand"
12
+ @onSelect="handleSelect"
13
+ :loadData="handleLoadData"
14
+ ref="tree"
15
+ >
16
+ </Tree>
17
+ </div>
18
+ <div v-else>
19
+ <van-empty description="流程类型未定义权限范围"/>
20
+ </div>
21
+ <div class="custom-bottom-bar">
22
+ <div class="bar-item" @click="selectOrganizeHandle('cancel')">取消</div>
23
+ <div class="bar-item approve" @click="selectOrganizeHandle('select')">选择</div>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script>
29
+ import Tree from "./tree/Tree.vue";
30
+ import {getOrgan, getOrgRootTree, getOrgSubNodes} from "../api";
31
+
32
+ export default {
33
+ name: "CustomTree",
34
+ components: {
35
+ Tree
36
+ },
37
+ props: {
38
+ showCheckBox: {
39
+ type: Boolean,
40
+ default: true
41
+ },
42
+ allOrganize: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+ organizeIdList: {
47
+ type: Array,
48
+ default: () => []
49
+ }
50
+ },
51
+ data() {
52
+ return {
53
+ organizeData: [] // 初始化为空数组
54
+ };
55
+ },
56
+ methods: {
57
+ getCheckedNodes() {
58
+ return this.$refs.tree.getCheckedNodes();
59
+ },
60
+ getCheckedChildrenNodes() {
61
+ return this.$refs.tree.getCheckedChildrenNodes();
62
+ },
63
+ formatTree(arr) {
64
+ function findParents(arr) {
65
+ const map = arr.reduce((obj, cur) => {
66
+ let id = cur["id"];
67
+ obj[id] = id;
68
+ return obj;
69
+ }, {});
70
+ return arr.filter((item) => !map[item.parentId]);
71
+ }
72
+
73
+ let parents = findParents(arr);
74
+
75
+ function findChildren(parents) {
76
+ if (!parents) return;
77
+ parents.forEach((p) => {
78
+ arr.forEach((item) => {
79
+ if (p.id === item.parentId) {
80
+ if (!p.children) {
81
+ p.children = [];
82
+ }
83
+ p.children.push(item);
84
+ }
85
+ });
86
+ findChildren(p.children);
87
+ });
88
+ }
89
+
90
+ findChildren(parents);
91
+ return parents;
92
+ },
93
+ handleChecked(v) {
94
+ this.$emit('handleChecked', v); // 发射 checked 事件到父组件
95
+ },
96
+ handleExpand(v) {
97
+ this.$emit('handleExpand', v); // 发射 expand 事件到父组件
98
+ },
99
+ handleSelect(v) {
100
+ this.$emit('handleSelect', v); // 发射 select 事件到父组件
101
+ },
102
+ handleLoadData(node, callback) {
103
+ getOrgSubNodes(node.id).then((res) => {
104
+ const result = res.data;
105
+ if (result.code === 1) {
106
+ callback(
107
+ result.data.map((item) => {
108
+ return {
109
+ children: [],
110
+ title: item.organName,
111
+ id: item.organCode,
112
+ parentId: item.parentId,
113
+ checked: false,
114
+ expand: false
115
+ };
116
+ }),
117
+ (res) => {
118
+ console.log(res)
119
+ }
120
+ );
121
+ } else {
122
+ callback(
123
+ [], (res) => {
124
+ console.log(res)
125
+ });
126
+ }
127
+ });
128
+ },
129
+ selectOrganizeHandle(handle) {
130
+ this.$emit('selectOrganizeHandle', handle, this.getCheckedNodes());
131
+ },
132
+
133
+ },
134
+ computed: {
135
+ data() {
136
+ return this.formatTree(this.organizeData);
137
+ }
138
+ },
139
+ created() {
140
+ if (this.organizeIdList.length > 0) {
141
+ this.organizeIdList.forEach((item) => {
142
+ getOrgan(item).then((res) => {
143
+ const result = res.data;
144
+ if (result.code === 1) {
145
+ // 确保 result.data 是一个对象
146
+ const newItem = {
147
+ children: [],
148
+ title: result.data.organName,
149
+ id: result.data.organCode,
150
+ parentId: result.data.parentId,
151
+ checked: false,
152
+ expand: false
153
+ };
154
+ // 添加单个新项到 organizeData 数组
155
+ this.organizeData.push(newItem);
156
+ }
157
+ }).catch((error) => {
158
+ console.error("getOrgan 请求失败:", error);
159
+ });
160
+ });
161
+ } else {
162
+ getOrgRootTree().then((res) => {
163
+ const result = res.data;
164
+ if (result.code === 1) {
165
+ this.organizeData = result.data.map((item) => {
166
+ return {
167
+ children: [],
168
+ title: item.organName,
169
+ id: item.organCode,
170
+ parentId: item.parentId,
171
+ checked: false,
172
+ expand: false
173
+ };
174
+ });
175
+ }
176
+ });
177
+ }
178
+ }
179
+ };
180
+ </script>
181
+ <style scoped>
182
+ .custom-bottom-bar {
183
+ position: fixed;
184
+ bottom: 0;
185
+ width: 100%;
186
+ display: flex;
187
+ justify-content: space-around;
188
+ background-color: #fff;
189
+ padding: 10px 0;
190
+ border-top: 1px solid #eaeaea;
191
+ box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.05);
192
+ z-index: 1000;
193
+ }
194
+
195
+ .bar-item {
196
+ flex: 1;
197
+ text-align: center;
198
+ padding: 10px 0;
199
+ font-size: 16px;
200
+ border-radius: 4px;
201
+ }
202
+
203
+ .bar-item:active {
204
+ background-color: #e6e6e6; /* 点击时的背景颜色 */
205
+ }
206
+
207
+ .approve {
208
+ color: #fff;
209
+ background: linear-gradient(90deg, #0096FF, #1677FF);
210
+ border-radius: 9px;
211
+ }
212
+
213
+ .approve:active {
214
+ background: linear-gradient(90deg, rgba(0, 150, 255, 0.8), rgba(22, 119, 255, 0.8));
215
+ }
216
+ </style>
@@ -131,6 +131,7 @@ export default {
131
131
  taskId: item.taskId,
132
132
  instanceId: item.procInstanceId,
133
133
  procName: item.procName,
134
+ procType: item.procType,
134
135
  procKey: result.data[0].procKey,
135
136
  handleButtons: result.data[0].handleButtons,
136
137
  appFormUrl: item.appFormUrl,
@@ -163,6 +164,7 @@ export default {
163
164
  taskId: item.taskId,
164
165
  instanceId: item.procInstanceId,
165
166
  procName: item.procName,
167
+ procType: item.procType,
166
168
  procKey: result.data[0].procKey,
167
169
  handleButtons: result.data[0].handleButtons,
168
170
  appFormUrl: item.appFormUrl,
@@ -60,16 +60,12 @@
60
60
  <!--审批详情弹出框-->
61
61
  <van-dialog v-model="showTaskNodeDetail" title="审批详情">
62
62
  <van-cell-group>
63
- <van-cell class="custom-cell" :border="false" title="审批节点:"
64
- :value="nodeDetail.taskName"></van-cell>
65
- <van-cell class="custom-cell" :border="false" title="审批人:"
66
- :value="nodeDetail.auditName"></van-cell>
67
- <van-cell class="custom-cell" :border="false" title="申请人:"
68
- :value="nodeDetail.applyUser ? nodeDetail.applyUser.split(':')[1] : '未定义'"></van-cell>
69
- <van-cell class="custom-cell"
70
- :title="nodeDetail.startDate ? '发起时间:':'审批时间:' "
71
- :value="nodeDetail.startDate ? nodeDetail.startDate : nodeDetail.auditDate">
72
- </van-cell>
63
+
64
+ <van-field readonly input-align="right" label="审批节点:" :value="nodeDetail.taskName" />
65
+ <van-field readonly input-align="right" label="审批人:" :value="nodeDetail.auditName" />
66
+ <van-field readonly input-align="right" label="申请人:" :value="nodeDetail.applyUser ? nodeDetail.applyUser.split(':')[1] : '未定义'" />
67
+ <van-field readonly input-align="right" :label="nodeDetail.startDate ? '发起时间:':'审批时间:' "
68
+ :value="nodeDetail.startDate ? nodeDetail.startDate : nodeDetail.auditDate" />
73
69
  <van-cell title="审批结果:" class="custom-cell" :border="false">
74
70
  <template v-slot:default>
75
71
  <van-tag :type="getAuditStatus(nodeDetail.auditResult).type">
@@ -338,6 +334,13 @@ export default {
338
334
 
339
335
  }
340
336
 
337
+ ::v-deep .van-dialog__header {
338
+ padding: 10px 0;
339
+ font-weight: 500;
340
+ line-height: 24px;
341
+ text-align: center;
342
+ }
343
+
341
344
  .record-item {
342
345
  position: relative;
343
346
  margin-bottom: 20px;
@@ -401,12 +404,8 @@ export default {
401
404
  margin-right: 5px;
402
405
  }
403
406
 
404
- .van-cell__title {
405
- flex: 1 0 auto;
406
- }
407
-
408
407
  .van-cell__value {
409
- flex: 0 1 auto;
408
+ flex: 0 auto;
410
409
  }
411
410
 
412
411
  </style>
@@ -0,0 +1,190 @@
1
+ <script>
2
+ import { broadCastMixins } from './util';
3
+ export default {
4
+ name: 'Node', // 这个很关键,递归组件必须有name
5
+ render() {
6
+ let showCheckBox = this.showCheckBox;
7
+ let data = this.data;
8
+ let loadData = this.loadData
9
+ return (
10
+ <div>
11
+ <ul class={'tree-ul'}>
12
+ <li class={'tree-li'} onClick={(e) => this.handleSelect(e)}>
13
+ {showCheckBox && (
14
+ <van-checkbox
15
+ class={'checkbox'}
16
+ icon-size={'18px'}
17
+ value={data.checked}
18
+ onClick={(e) => this.handleCheck(e, data)}
19
+ />
20
+ )}
21
+
22
+ {/*如果没有插槽则默认使用显示内容*/}
23
+
24
+ {this.$scopedSlots.default ? (
25
+ this.$scopedSlots.default({
26
+ data: data
27
+ })
28
+ ) : (
29
+ <span>{data.title}</span>
30
+ )}
31
+ <span class={'tree-expand'}>
32
+ {this.showLoading ? (
33
+ <van-loading class={'tree-loading'} color={'#1989fa'}/>
34
+ ) : (
35
+ ''
36
+ )}
37
+ {this.showArrow ? (
38
+ <van-icon
39
+ name={this.arrowType}
40
+ onClick={(e) => this.handleExpand(e)}
41
+ />
42
+ ) : (
43
+ ''
44
+ )}
45
+ </span>
46
+ {data.expand &&
47
+ data.children.map((item, index) => {
48
+ return (
49
+ <Node key={index} data={item} showCheckBox={showCheckBox} loadData={loadData}>
50
+ {this.$scopedSlots.default}
51
+ </Node>
52
+ );
53
+ })}
54
+ </li>
55
+ </ul>
56
+ </div>
57
+ );
58
+ },
59
+ props: {
60
+ data: {
61
+ type: Object,
62
+ default() {
63
+ return {};
64
+ }
65
+ },
66
+ showCheckBox: {
67
+ type: Boolean,
68
+ default: false
69
+ },
70
+ loadData: {
71
+ type: Function
72
+ }
73
+ },
74
+ mixins: [broadCastMixins],
75
+ computed: {
76
+ showArrow() {
77
+ // 1.如果数据没有children,说明是子组件,就不用展示下拉箭头
78
+ // 2.如果开启了异步加载,在loading的时候,不显示箭头
79
+ return (
80
+ (this.data.children &&
81
+ this.data.children.length &&
82
+ !this.showLoading) ||
83
+ (this.data.children &&
84
+ !this.data.children.length &&
85
+ this.loadData &&
86
+ !this.showLoading)
87
+ );
88
+ },
89
+ showLoading() {
90
+ // 判断是否有loading属性,并且判断你是否在开启状态
91
+ return 'loading' in this.data && this.data.loading;
92
+ },
93
+ arrowType() {
94
+ //箭头方向,van组件提供的属性
95
+ return this.showArrow && this.data.expand ? 'arrow-down' : 'arrow';
96
+ }
97
+ },
98
+ methods: {
99
+ handleCheck(e) {
100
+ e.cancelBubble = true;
101
+ this.$set(this.data, 'checked', !this.data.checked);
102
+ this.broadCast('handleCheck', this.data);
103
+ }, //勾选方法
104
+ handleExpand(e) {
105
+ e.cancelBubble = true;
106
+ let node = this.data;
107
+ if (node.children && node.children.length === 0) {
108
+ if (this.loadData) {
109
+ this.$set(node, 'loading', true); // 显示loading
110
+ this.loadData(node, (arr, callback) => {
111
+ // 这个loadData回调函数,由外部组件调用的时候传入arr和callback
112
+ if (arr.length) {
113
+ // 如果外部传入的数组不为空
114
+ // 把arr作为当前父级节点的children
115
+ this.$set(node, 'children', arr);
116
+ this.$nextTick(() => {
117
+ //展开操作
118
+ this.handleExpand(e);
119
+ //执行外部传入的回调函数,成功的时候
120
+ callback('suc', node);
121
+ });
122
+ } else {
123
+ // 如果返回的是为空数组,则执行失败的回调
124
+ callback('falid');
125
+ }
126
+ this.$set(node, 'loading', false); //关闭loading
127
+ });
128
+ }
129
+ return;
130
+ }
131
+ this.$set(this.data, 'expand', !this.data.expand);
132
+ this.broadCast('handleExpand', this.data);
133
+ },
134
+ handleSelect(e) {
135
+ e.cancelBubble = true;
136
+ this.broadCast('handleSelect', this.data);
137
+ } //点击列表
138
+ },
139
+
140
+ };
141
+ </script>
142
+
143
+ <style scoped>
144
+ .tree-ul,
145
+ .tree-li {
146
+ font-size: 16px;
147
+ list-style: none;
148
+ margin-left: 10px;
149
+ position: relative;
150
+ height: auto;
151
+ }
152
+
153
+ .tree-ul {
154
+ margin: 15px auto;
155
+ box-sizing: border-box;
156
+ }
157
+
158
+ .tree-li {
159
+ position: relative;
160
+ width: 100%;
161
+ box-sizing: border-box;
162
+ margin: 6px 3px;
163
+ padding-right: 3px;
164
+ padding-left: 10px;
165
+ }
166
+
167
+ .tree-expand {
168
+ height: 20px;
169
+ cursor: pointer;
170
+ position: absolute;
171
+ top: 4px;
172
+ right: 0;
173
+ margin: auto;
174
+ }
175
+
176
+ .checkbox {
177
+ display: inline-block !important;
178
+ vertical-align: middle;
179
+ margin-right: 4px;
180
+ }
181
+
182
+ .tree-loading {
183
+ width: 20px;
184
+ height: 20px;
185
+ position: absolute;
186
+ top: 0;
187
+ right: 0;
188
+ margin: auto;
189
+ }
190
+ </style>