@lambo-design-mobile/workflow-approve 1.0.0-beta.1

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,308 @@
1
+ <template>
2
+ <div>
3
+ <div id="headTitle" class="headTitle">
4
+ <div class="van-nav-bar__content">
5
+ <div class="van-nav-bar__title">指定办理人</div>
6
+ </div>
7
+ <van-search
8
+ show-action
9
+ placeholder="请输入姓名查询"
10
+ v-model="searchForm.userName"
11
+ @search="onSearch"
12
+ >
13
+ <template #left-icon>
14
+ <van-icon class="iconfont" class-prefix='icon' name="tqm-search" color="#0068FF" size="20px"></van-icon>
15
+ </template>
16
+ <template #right-icon>
17
+ <div @click="onSearch" class="todo-search">搜索</div>
18
+ </template>
19
+ <template #action>
20
+ <van-badge :dot="searchFilterBadge">
21
+ <van-icon @click="searchFilterShow = !searchFilterShow;" name="filter-o" color="#666666" size="25px"/>
22
+ </van-badge>
23
+ </template>
24
+ </van-search>
25
+ </div>
26
+ <van-popup v-model="searchFilterShow" ref="searchPopup" position="top"
27
+ get-container="#headTitle" style="position: absolute;margin-top: 104px"
28
+ :overlay-style="{ position:'absolute',marginTop: '104px'}" transition="none">
29
+ <div style="padding: 12px">
30
+ <van-form>
31
+ <van-field clearable v-model="searchForm.organId" label="组织ID" readonly />
32
+ <van-field clearable v-model="searchForm.organTitle" label="组织名称" readonly />
33
+ <van-field clearable v-model="searchForm.userId" label="用户ID" placeholder="请输入用户ID"/>
34
+ <van-field name="radio" label="是否管理员">
35
+ <template #input>
36
+ <van-radio-group v-model="searchForm.isAdmin" direction="horizontal">
37
+ <van-radio name="">全部</van-radio>
38
+ <van-radio name="1">是</van-radio>
39
+ <van-radio name="0">否</van-radio>
40
+ </van-radio-group>
41
+ </template>
42
+ </van-field>
43
+ <div style="display: flex;justify-content: space-around;padding-top:10px">
44
+ <span @click="resetSearch" class="resetSearch">重置</span>
45
+ <span @click="onSearch" class="submitForm">查询</span>
46
+ </div>
47
+ </van-form>
48
+ </div>
49
+ </van-popup>
50
+ <div id="listContent">
51
+ <van-list v-model="loading" style="padding-top: 15px"
52
+ :finished="finished"
53
+ finished-text="没有更多了"
54
+ @load="handleLoad()">
55
+ <select-handle-card ref="selectHandleCard" :person-list="personList.rows"
56
+ :result.sync="checkResult">
57
+ </select-handle-card>
58
+ </van-list>
59
+ </div>
60
+ <div v-if="checkResult.length > 0" class="custom-bottom-bar">
61
+ <div class="bar-item" @click="handleSelect('cancel')">取消</div>
62
+ <div class="bar-item approve" @click="handleSelect('select')">选择</div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+ import SelectHandleCard from "./SelectHandleCard.vue";
69
+ import {getOrgRootTree, getUserList} from "../api";
70
+
71
+ export default {
72
+ name: "SelectHandle",
73
+ components: {SelectHandleCard},
74
+ data() {
75
+ return {
76
+ searchFilterShow: false,
77
+ searchFilterBadge: false,
78
+ searchForm: {
79
+ userId: '',
80
+ userName: '',
81
+ organId: '',
82
+ organTitle: '',
83
+ directChild: '',
84
+ isAdmin: '',
85
+ },
86
+
87
+ loading: false,
88
+ finished: false,
89
+ personList: {
90
+ total: 0,
91
+ rows: []
92
+ },
93
+ checkResult: [], // 需要传递到子组件的 checkResult
94
+ }
95
+ },
96
+ methods: {
97
+ handleLoad() {
98
+ console.log("触发加载")
99
+ getOrgRootTree().then(res => {
100
+ const result = res.data;
101
+ if (result.code === 1) {
102
+ this.searchForm.organId = result.data[0].organId;
103
+ this.searchForm.organTitle = result.data[0].organName;
104
+
105
+ const offset = this.personList.rows.length;
106
+ const limit = 10;
107
+
108
+ getUserList(offset, limit, this.searchForm).then(res => {
109
+
110
+ const result = res.data;
111
+ if (result.code === "1") {
112
+
113
+ //返回的数据添加到 personList 中
114
+ this.personList.rows = this.personList.rows.concat(result.data.rows);
115
+ this.personList.total = result.data.total;
116
+
117
+ } else {
118
+ console.error('Failed to load data');
119
+ }
120
+
121
+ this.loading = false;
122
+ this.finished = this.personList.rows.length >= this.personList.total;
123
+
124
+ }).catch(error => {
125
+ console.error('Error fetching data:', error);
126
+ this.loading = false;
127
+ });
128
+ }
129
+ })
130
+ },
131
+ onSearch() {
132
+ // 如果搜索弹框是打开的
133
+ if (this.searchFilterShow) {
134
+ // 关闭搜索弹框
135
+ this.searchFilterShow = false;
136
+ // 监听 `searchFilterShow` 的变化,并在关闭动画完成后执行操作
137
+ this.$nextTick(() => {
138
+ if (this.$refs.searchPopup) {
139
+ this.$refs.searchPopup.$once('closed', () => {
140
+ // 在关闭动画完成后执行重置和加载操作
141
+ this.resetAndLoadPersonList();
142
+ });
143
+ }
144
+ });
145
+ } else {
146
+ // 如果搜索弹框已经是关闭的,直接执行重置和加载操作
147
+ this.resetAndLoadPersonList();
148
+ }
149
+ },
150
+ resetSearch() {
151
+ // 遍历 searchForm 对象的每个属性,将其值置为空
152
+ for (let key in this.searchForm) {
153
+ // eslint-disable-next-line no-prototype-builtins
154
+ if (this.searchForm.hasOwnProperty(key)) {
155
+ if (key !== "organId" && key !== "organTitle") {
156
+ this.searchForm[key] = '';
157
+ }
158
+ }
159
+ }
160
+ },
161
+ resetAndLoadPersonList() {
162
+ this.personList.total = 0;
163
+ this.personList.rows = [];
164
+ this.handleLoad();
165
+ },
166
+ handleSelect(handle) {
167
+ if (handle === 'select') {
168
+ // 触发自定义事件 'selectHandle',并传递 this.checkResult
169
+ this.$emit('selectHandle', this.checkResult);
170
+ } else {
171
+ this.checkResult = [];
172
+ }
173
+ },
174
+ checkSearchForm() {
175
+ this.searchFilterBadge = Object.values(this.searchForm).some(value => value !== '');
176
+ },
177
+ },
178
+ watch: {
179
+ // 监听 searchForm 的每一个字段的变化
180
+ searchForm: {
181
+ handler: 'checkSearchForm',
182
+ deep: true // 深度监听
183
+ }
184
+ }
185
+ }
186
+ </script>
187
+
188
+ <style scoped>
189
+ .todo-search {
190
+ display: flex;
191
+ justify-content: center;
192
+ align-items: center;
193
+
194
+ color: white;
195
+ width: 58px;
196
+ height: 30px;
197
+ background: linear-gradient(90deg, #0096FF, #1677FF);
198
+ border-radius: 6px;
199
+ }
200
+
201
+ .todo-search:active {
202
+ background: linear-gradient(90deg, rgba(0, 150, 255, 0.8), rgba(22, 119, 255, 0.79));
203
+ }
204
+
205
+ .van-search {
206
+ border-radius: 6px;
207
+ }
208
+
209
+ .van-search__content {
210
+ border-radius: 6px;
211
+ }
212
+
213
+ .van-nav-bar__content {
214
+ background: white;
215
+ }
216
+
217
+ .van-badge__wrapper {
218
+ display: flex;
219
+ }
220
+
221
+ .van-search__action {
222
+ display: flex;
223
+ align-items: center;
224
+ padding: 5px 5px;
225
+ transition: background-color 0.3s ease; /* 添加过渡效果 */
226
+ }
227
+
228
+ .van-search__action:active {
229
+ border-radius: 6px;
230
+ background-color: rgba(0, 0, 0, 0.1); /* 点击时显示半透明背景 */
231
+ }
232
+
233
+ ::v-deep .van-field__left-icon {
234
+ display: flex;
235
+ align-items: center;
236
+ }
237
+
238
+ .custom-bottom-bar {
239
+ position: fixed;
240
+ bottom: 0;
241
+ width: 100%;
242
+ display: flex;
243
+ justify-content: space-around;
244
+ background-color: #fff;
245
+ padding: 10px 0;
246
+ border-top: 1px solid #eaeaea;
247
+ box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.05);
248
+ z-index: 1000;
249
+ }
250
+
251
+ .bar-item {
252
+ flex: 1;
253
+ text-align: center;
254
+ padding: 10px 0;
255
+ font-size: 16px;
256
+ border-radius: 4px;
257
+ margin: 0 20px;
258
+ }
259
+
260
+ .bar-item:active {
261
+ background: #e6e6e6; /* 点击时的背景颜色 */
262
+ }
263
+
264
+ .approve {
265
+ color: #fff;
266
+ background: linear-gradient(90deg, #0096FF, #1677FF);
267
+ border-radius: 9px;
268
+ }
269
+
270
+ .approve:active {
271
+ background: linear-gradient(90deg, rgba(0, 150, 255, 0.8), rgba(22, 119, 255, 0.8));
272
+ }
273
+
274
+ .resetSearch {
275
+ color: black;
276
+ width: 160px;
277
+ height: 35px;
278
+ background: #F2F2F2;
279
+ border-radius: 9px;
280
+ font-size: 14px;
281
+
282
+ display: flex;
283
+ justify-content: center;
284
+ align-items: center;
285
+ }
286
+
287
+ .resetSearch:active {
288
+ background: rgba(242, 242, 242, 0.8);
289
+ }
290
+
291
+ .submitForm {
292
+ color: white;
293
+ width: 160px;
294
+ height: 35px;
295
+ background: linear-gradient(90deg, #0096FF, #1677FF);
296
+ border-radius: 9px;
297
+ font-size: 14px;
298
+
299
+
300
+ display: flex;
301
+ justify-content: center;
302
+ align-items: center;
303
+ }
304
+
305
+ .submitForm:active {
306
+ background: linear-gradient(90deg, rgba(0, 150, 255, 0.8), rgba(22, 119, 255, 0.79));
307
+ }
308
+ </style>
@@ -0,0 +1,135 @@
1
+ <template>
2
+ <div>
3
+ <van-checkbox-group v-model="localResult" :max="1" ref="checkboxGroup">
4
+ <van-cell-group v-for="(item,index) in personList" :key="index"
5
+ style="margin-bottom: 10px;" inset>
6
+ <van-cell value-class="value-status" center size="large"
7
+ :value="item.userName">
8
+ <template #icon>
9
+ <van-checkbox @click="clearLocalResult(item)" style="padding: 0 5px" :name="item"
10
+ icon-size="18px"></van-checkbox>
11
+ </template>
12
+ </van-cell>
13
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell"
14
+ :border="false" title="人员账号"
15
+ :value="item.userId"></van-cell>
16
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell"
17
+ :border="false" title="部门名称"
18
+ :value="item.organName"></van-cell>
19
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell"
20
+ :border="false" title="人员状态">
21
+ <template v-slot:default>
22
+ <span :style="getStatusStyle(item.status)"></span>
23
+ <span :style="{ color: getStatusStyle(item.status)['background-color'] }">
24
+ {{ getStatusText(item.status) }}
25
+ </span>
26
+ </template>
27
+ </van-cell>
28
+ </van-cell-group>
29
+ </van-checkbox-group>
30
+ </div>
31
+ </template>
32
+ <script>
33
+
34
+ export default {
35
+ name: 'SelectHandleCard',
36
+ props: {
37
+ personList: {},
38
+ selectedTask: {
39
+ type: String,
40
+ default: 'pending'
41
+ },
42
+ result: {
43
+ type: Array,
44
+ default: () => []
45
+ }
46
+ },
47
+ data() {
48
+ return {
49
+ localResult: this.result, // 使用 localResult 来绑定 van-checkbox-group
50
+ }
51
+ },
52
+ watch: {
53
+ // 监听 result 属性的变化
54
+ result: {
55
+ handler(newVal) {
56
+ this.localResult = newVal; // 当 result 变化时,更新 localResult
57
+ },
58
+ deep: true
59
+ },
60
+ localResult: {
61
+ handler(newVal) {
62
+ this.$emit('update:result', newVal); // 将 localResult 的变化传递给父组件
63
+ },
64
+ deep: true
65
+ }
66
+ },
67
+ methods: {
68
+ checkAll() {
69
+ this.$refs.checkboxGroup.toggleAll(true);
70
+ },
71
+ toggleAll() {
72
+ this.$refs.checkboxGroup.toggleAll(false);
73
+ },
74
+ clearLocalResult(item) {
75
+ this.localResult = [];
76
+ this.localResult.push(item)
77
+ },
78
+ getStatusText(status) {
79
+ switch (status) {
80
+ case '00':
81
+ return '正常';
82
+ case '01':
83
+ return '初始';
84
+ case '10':
85
+ return '删除';
86
+ case '11':
87
+ return '锁定';
88
+ default:
89
+ return '未知状态';
90
+ }
91
+ },
92
+ getStatusStyle(status) {
93
+ let color = '';
94
+ switch (status) {
95
+ case '00':
96
+ color = 'rgb(25, 190, 107)'; // 绿色
97
+ break;
98
+ case '01':
99
+ color = 'rgb(255, 193, 7)'; // 黄色
100
+ break;
101
+ case '10':
102
+ color = 'rgb(244, 67, 54)'; // 红色
103
+ break;
104
+ case '11':
105
+ color = 'rgb(158, 158, 158)'; // 灰色
106
+ break;
107
+ default:
108
+ color = 'rgb(0, 0, 0)'; // 黑色(未知状态)
109
+ }
110
+ return {
111
+ display: 'inline-block',
112
+ width: '10px',
113
+ height: '10px',
114
+ 'border-radius': '50%',
115
+ 'background-color': color,
116
+ 'margin-right': '5px',
117
+ };
118
+ }
119
+ }
120
+ }
121
+ </script>
122
+ <style scoped>
123
+
124
+ /* 自定义 .van-cell 样式 */
125
+ .custom-cell {
126
+ padding: 5px 16px;
127
+ }
128
+
129
+ /* 自定义 .van-cell 样式 */
130
+ .value-status {
131
+ font-weight: bold; /* 设置文字加粗 */
132
+ text-align: right;
133
+ }
134
+
135
+ </style>
@@ -0,0 +1,233 @@
1
+ <template>
2
+ <div>
3
+ <van-checkbox-group v-model="localResult" ref="checkboxGroup">
4
+ <van-cell-group v-for="(item,index) in todoList" :key="index"
5
+ style="margin-bottom: 10px;" inset>
6
+ <van-cell title-class="title-status" center
7
+ :value-class="[selectedTask === 'pending' ? 'value-pending' : 'value-completed']"
8
+ size="large"
9
+ :value="selectedTask === 'pending' ? (item.handleType === '20'? '待审批':'待办理'): '已处理'">
10
+ <template #title>
11
+ <div @click="handleDetails(item)">{{ item.businessTopic ? item.businessTopic : item.procName }}</div>
12
+ </template>
13
+ <template #icon>
14
+ <van-checkbox v-if="selectedTask === 'pending' & item.handleType === '20'" style="padding: 0 5px"
15
+ :name="item.flowId" icon-size="18px"></van-checkbox>
16
+ </template>
17
+ </van-cell>
18
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell" :border="false"
19
+ title="样品单号"
20
+ :value="item.applyId"></van-cell>
21
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell" :border="false"
22
+ title="流程名称" @click="toggleDetails(index)" :is-link="true"
23
+ :arrow-direction="detailsVisible[index] ? 'down' : ''"
24
+ :value="item.procName"></van-cell>
25
+ <div v-if="detailsVisible[index]">
26
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell" :border="false"
27
+ title="当前环节"
28
+ :value="item.taskName"></van-cell>
29
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell" :border="false" title="申请人"
30
+ :value="item.applyUser ? item.applyUser.split(':')[1] : '未定义'"></van-cell>
31
+ </div>
32
+ <van-cell title-class="list-title" value-class="list-value" class="custom-cell"
33
+ :title="selectedTask === 'pending' ? '发起时间':'审批时间' "
34
+ :value="selectedTask === 'pending' ? formatDate(item.startDate) :formatDate(item.auditDate)">
35
+ </van-cell>
36
+ <van-cell v-if="selectedTask === 'pending'" :key="selectedTask" title=" ">
37
+ <template #right-icon>
38
+ <div class="button-group">
39
+ <van-button class="button" size="small" plain type="info" @click="handleItem(item)">
40
+ {{ item.handleType === '20' ? '审批' : '办理' }}
41
+ </van-button>
42
+ </div>
43
+ </template>
44
+ </van-cell>
45
+ </van-cell-group>
46
+ </van-checkbox-group>
47
+ </div>
48
+ </template>
49
+ <script>
50
+ import {getNodeData} from "../api";
51
+ import {Notify} from "vant";
52
+
53
+ export default {
54
+ name: 'TodoListCard',
55
+ props: {
56
+ todoList: {},
57
+ selectedTask: {
58
+ type: String,
59
+ default: 'pending'
60
+ },
61
+ result: {
62
+ type: Array,
63
+ default: () => []
64
+ },
65
+ // 新增 4 个路由 name 参数
66
+ businessDetailsRouterName: {
67
+ type: String,
68
+ required: true
69
+ },
70
+ processDetailsRouterName: {
71
+ type: String,
72
+ required: true
73
+ },
74
+ businessApprovalRouterName: {
75
+ type: String,
76
+ required: true
77
+ },
78
+ processApprovalRouterName: {
79
+ type: String,
80
+ required: true
81
+ }
82
+ },
83
+ data() {
84
+ return {
85
+ localTodoList: this.todoList,
86
+ detailsVisible: {}, // 用于跟踪每个项目的详细内容是否可见
87
+ localResult: this.result, // 使用 localResult 来绑定 van-checkbox-group
88
+ }
89
+ },
90
+ watch: {
91
+ // 监听 result 属性的变化
92
+ result: {
93
+ handler(newVal) {
94
+ this.localResult = newVal; // 当 result 变化时,更新 localResult
95
+ },
96
+ deep: true
97
+ },
98
+ localResult: {
99
+ handler(newVal) {
100
+ this.$emit('update:result', newVal); // 将 localResult 的变化传递给父组件
101
+ },
102
+ deep: true
103
+ }
104
+ },
105
+ methods: {
106
+ checkAll() {
107
+ this.$refs.checkboxGroup.toggleAll(true);
108
+ },
109
+ toggleAll() {
110
+ this.$refs.checkboxGroup.toggleAll(false);
111
+ },
112
+ handleDetails(item) {
113
+ getNodeData(item.procId, item.taskNode).then(res => {
114
+ const result = res.data;
115
+ if (result.code === '200') {
116
+ if (result.data[0] == null || result.data[0].handleType == null) {
117
+ Notify({type: 'danger', message: '没有为该待办事项指定办理类型'});
118
+ } else {
119
+ // 使用更新后的 prop 名称
120
+ const routeName = result.data[0].handleType === '10'
121
+ ? this.businessDetailsRouterName
122
+ : this.processDetailsRouterName;
123
+
124
+ this.$router.push({
125
+ name: routeName, // 动态使用更新后的路由 name
126
+ query: {
127
+ taskNode: item.taskNode,
128
+ formUrl: item.formUrl,
129
+ applyId: item.applyId,
130
+ procId: item.procId,
131
+ taskId: item.taskId,
132
+ instanceId: item.procInstanceId,
133
+ procName: item.procName,
134
+ appFormUrl: item.appFormUrl,
135
+ appDetailUrl: item.appDetailUrl,
136
+ }
137
+ });
138
+ }
139
+ }
140
+ });
141
+ },
142
+ handleItem(item) {
143
+ getNodeData(item.procId, item.taskNode).then(res => {
144
+ const result = res.data;
145
+ if (result.code === '200') {
146
+ if (result.data[0] == null || result.data[0].handleType == null) {
147
+ Notify({type: 'danger', message: '没有为该待办事项指定办理类型'});
148
+ } else {
149
+ // 使用更新后的 prop 名称
150
+ const routeName = result.data[0].handleType === '10'
151
+ ? this.businessApprovalRouterName
152
+ : this.processApprovalRouterName;
153
+
154
+ this.$router.push({
155
+ name: routeName, // 动态使用更新后的路由 name
156
+ query: {
157
+ taskNode: item.taskNode,
158
+ formUrl: item.formUrl,
159
+ applyId: item.applyId,
160
+ procId: item.procId,
161
+ taskId: item.taskId,
162
+ instanceId: item.procInstanceId,
163
+ procName: item.procName,
164
+ procKey: result.data[0].procKey,
165
+ handleButtons: result.data[0].handleButtons,
166
+ appFormUrl: item.appFormUrl,
167
+ appDetailUrl: item.appDetailUrl,
168
+ }
169
+ });
170
+ }
171
+ }
172
+ });
173
+ },
174
+ formatDate(dateString) {
175
+ const date = new Date(dateString);
176
+ return date.toLocaleString().replace(/\//g, '-')
177
+ },
178
+ toggleDetails(index) {
179
+ this.$set(this.detailsVisible, index, !this.detailsVisible[index]);
180
+ },
181
+ }
182
+ }
183
+ </script>
184
+ <style scoped>
185
+
186
+ .button-group {
187
+ display: flex;
188
+ justify-content: flex-end; /* 使按钮组靠右 */
189
+ gap: 10px; /* 按钮之间的间距 */
190
+ }
191
+
192
+ .button {
193
+ width: 74px;
194
+ height: 35px;
195
+ border-radius: 9px;
196
+ border: 1px solid #0068FF;
197
+ font-size: 14px;
198
+ }
199
+
200
+
201
+ /* 自定义 .van-cell 样式 */
202
+ .custom-cell {
203
+ padding: 5px 16px;
204
+ }
205
+
206
+ /* 自定义 .van-cell 样式 */
207
+ .title-status {
208
+ font-weight: normal; /* 设置文字加粗 */
209
+ }
210
+
211
+ .value-pending {
212
+ color: red;
213
+ flex: 0 0 auto;
214
+ }
215
+
216
+ .value-completed {
217
+ color: #07c160;
218
+ flex: 0 0 auto;
219
+ }
220
+
221
+ .list-title {
222
+ color: #969799;
223
+ }
224
+
225
+ .list-value {
226
+ color: black;
227
+ }
228
+
229
+ .custom-cell .van-cell__title {
230
+ flex: 0 0 auto;
231
+ }
232
+
233
+ </style>