@lambo-design/workflow-approve 1.0.0-beta.4 → 1.0.0-beta.40

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/src/portrait.vue CHANGED
@@ -4,72 +4,121 @@
4
4
  {{ title }}
5
5
  </template>
6
6
  <template slot="page-extend">
7
- <Button type="primary" ghost @click="pageGoBack">返回</Button>
7
+ <slot name="return-button"></slot>
8
8
  </template>
9
- <div class="portrait-lambo-indicator-card" :style="{float: 'left', width: isExpanded ? `calc(100% - ${portraitWidth+10}px)` : '99%'}">
9
+ <div class="portrait-lambo-indicator-card"
10
+ :style="{float: 'left', width: isExpanded && showProcessInfo ? `calc(100% - ${portraitWidth+10}px)` : '99%'}">
10
11
  <slot name="business-content">
11
12
  </slot>
12
13
  </div>
13
14
 
14
- <a @click="isExpanded = !isExpanded" class="arrow-button-container" :style="{right: isExpanded ? portraitWidth+10 + 'px' : '10px'}">
15
+ <a v-if="showProcessInfo" @click="isExpanded = !isExpanded" class="arrow-button-container"
16
+ :style="{right: isExpanded ? portraitWidth+10 + 'px' : '10px'}">
15
17
  <Icon class="icon-class" v-if="isExpanded" type="ios-arrow-forward"/>
16
18
  <Icon class="icon-class" v-if="!isExpanded" type="ios-arrow-back"/>
17
19
  </a>
18
- <transition name="draw" @before-enter="beforeFlowInfoEnter" @enter="flowInfoEnter"
20
+ <transition v-if="showProcessInfo" name="draw" @before-enter="beforeFlowInfoEnter" @enter="flowInfoEnter"
19
21
  @before-leave="beforeFlowInfoLeave" @leave="flowInfoLeave">
20
- <lamboIndicatorCard v-if="isExpanded" class="portrait-lambo-indicator-card" :style="{width: portraitWidth + 'px', float: 'right'}" :hasExtend="false">
22
+ <lamboIndicatorCard v-if="isExpanded" class="portrait-lambo-indicator-card"
23
+ :style="{width: portraitWidth + 'px', float: 'right'}" :hasExtend="false">
21
24
  <div slot="content-title">流程信息</div>
22
- <a @click="auditShow = !auditShow">
23
- <Title v-if="!handleButtons || handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile')">
25
+ <a v-if="!isDetail" @click="auditShow = !auditShow">
26
+ <Title
27
+ v-if="handleButtons && (handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile'))">
24
28
  <a style="color: #989898">
25
- <Icon v-if="auditShow" type="ios-arrow-down"/>
26
- <Icon v-if="!auditShow" type="ios-arrow-up"/>
27
- 审批信息
29
+ <Icon v-if="auditShow" type="ios-arrow-down"/>
30
+ <Icon v-if="!auditShow" type="ios-arrow-up"/>
31
+ {{ handleName }}信息
28
32
  </a>
29
33
  </Title>
30
34
  </a>
31
- <transition name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
35
+ <transition v-if="!isDetail" name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave"
36
+ @leave="leave">
32
37
  <div class="box" v-show="auditShow">
33
38
  <Form ref="auditOpinion" justify="center" :label-width="100" :model="form"
34
- v-if="!handleButtons || handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile')"
39
+ v-if="handleButtons && handleButtons.includes('auditOpinion')"
35
40
  style="margin: 10px 0 0 10px;" :rules="ruleValidate">
36
- <FormItem label="审批意见:" prop="auditOpinion" >
37
- <AuditOpinion v-model="form.auditOpinion" :attachmentFile="handleButtons.includes('attachmentFile')" :attachmentdata="fileList"
41
+ <FormItem :label="auditOpinionTitle" prop="auditOpinion">
42
+ <AuditOpinion v-model="form.auditOpinion" :attachment-file="handleButtons.includes('attachmentFile')"
43
+ :attachmentdata="fileList" :default-audit-opinion="defaultAuditOpinion"
38
44
  :smart-flow-server-context="smartFlowServerContext"></AuditOpinion>
39
45
  </FormItem>
40
46
  </Form>
47
+ <Form ref="auditOpinion" justify="center" :label-width="100"
48
+ v-if="handleButtons && !handleButtons.includes('auditOpinion') && handleButtons.includes('attachmentFile')"
49
+ style="margin: 10px 0 0 10px;">
50
+ <FormItem style="min-height: 70px">
51
+ <Tooltip placement="bottom" max-width="200">
52
+ <div style="font-size: smaller" slot="content">支持扩展名:.pdf .doc .docx .txt .xls .xlsx .jpg .jpeg
53
+ .png .gif
54
+ </div>
55
+ <UploadFile @upload-result="uploadFile" :multiple="true"
56
+ :oss-server-context="smartFlowServerContext"
57
+ :oss-file-put-url="ossFilePutUrl"></UploadFile>
58
+ </Tooltip>
59
+ </FormItem>
60
+ </Form>
61
+ </div>
62
+ </transition>
63
+ <a v-if="taskNode && isDetail && hisAuditOpinion[0].auditOpinion" @click="auditShow = !auditShow">
64
+ <Title
65
+ v-if="handleButtons && (handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile'))">
66
+ <a style="color: #989898">
67
+ <Icon v-if="auditShow" type="ios-arrow-down"/>
68
+ <Icon v-if="!auditShow" type="ios-arrow-up"/>
69
+ {{ handleName }}信息
70
+ </a>
71
+ </Title>
72
+ </a>
73
+ <transition v-if="taskNode && isDetail && hisAuditOpinion[0].auditOpinion" name="draw" @before-enter="beforeEnter"
74
+ @enter="enter" @before-leave="beforeLeave" @leave="leave">
75
+ <div class="box" v-show="auditShow">
76
+ <Form ref="auditOpinion" justify="center" :model="form"
77
+ v-if="handleButtons && handleButtons.includes('auditOpinion')"
78
+ style="margin: 10px 0 0 10px;" :rules="ruleValidate">
79
+ <FormItem style="margin-left: -60px">
80
+ <Card v-for="(item, index) in hisAuditOpinion" :key="index">
81
+ <Row>
82
+ <Col span="12" style="word-wrap: break-word">{{ item.auditOpinion }}</Col>
83
+ <Col span="2"></Col>
84
+ <Col span="10">{{ item.auditTime }}</Col>
85
+ </Row>
86
+ </Card>
87
+ </FormItem>
88
+ </Form>
41
89
  </div>
42
90
  </transition>
43
91
  <a @click="historyShow = !historyShow">
44
- <Title v-if="!handleButtons || handleButtons.includes('auditHistory')">
92
+ <Title v-if="handleButtons && handleButtons.includes('auditHistory')">
45
93
  <a style="color: #989898">
46
- <Icon v-if="historyShow" type="ios-arrow-down"/>
47
- <Icon v-if="!historyShow" type="ios-arrow-up"/>
48
- 审批记录
94
+ <Icon v-if="historyShow" type="ios-arrow-down"/>
95
+ <Icon v-if="!historyShow" type="ios-arrow-up"/>
96
+ {{ handleName }}记录
49
97
  </a>
50
98
  </Title>
51
99
  </a>
52
100
  <transition name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
53
101
  <div class="box" v-show="historyShow">
54
- <Card class="process-history" dis-hover :bordered="false"
55
- v-if="!handleButtons || handleButtons.includes('auditHistory')">
56
- <processHistory :portrait-width="portraitWidth" :list="processHistory"
102
+ <Card class="process-history" :style="processHistoryHeight" dis-hover :bordered="false"
103
+ v-if="handleButtons && handleButtons.includes('auditHistory')">
104
+ <processHistory :portrait-width="portraitWidth" :list="processHistory" :done-page="isDetail" :push-button="pushButton"
57
105
  :smart-flow-server-context="smartFlowServerContext"></processHistory>
58
106
  </Card>
59
107
  </div>
60
108
  </transition>
61
109
 
62
110
  <a @click="attachListShow = !attachListShow">
63
- <Title v-if="(!handleButtons || handleButtons.includes('attachmentFile')) && attachmentList.length > 0">
111
+ <Title v-if="handleButtons && handleButtons.includes('attachmentFile') && attachmentList.length > 0">
64
112
  <a style="color: #989898">
65
- <Icon v-if="attachListShow" type="ios-arrow-down"/>
66
- <Icon v-if="!attachListShow" type="ios-arrow-up"/>
67
- 查看附件
113
+ <Icon v-if="attachListShow" type="ios-arrow-down"/>
114
+ <Icon v-if="!attachListShow" type="ios-arrow-up"/>
115
+ 查看附件
68
116
  </a>
69
117
  </Title>
70
118
  </a>
71
119
  <transition name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
72
- <div class="box" v-show="(!handleButtons || handleButtons.includes('attachmentFile')) && attachmentList.length > 0 && attachListShow">
120
+ <div class="box"
121
+ v-show="handleButtons && handleButtons.includes('auditHistory') && attachmentList.length > 0 && attachListShow">
73
122
  <div v-for="(item, index) in attachmentList" :key="index">
74
123
  <Card dis-hover class="attach-card">
75
124
  <List item-layout="vertical">
@@ -77,16 +126,25 @@
77
126
  <Row style="display: flex; align-items: center;">
78
127
  <!-- 左边:图片 -->
79
128
  <Col span="4" style="margin-top: -25px">
80
- <avatar v-if="item.fileType === 'image'" icon="ios-image-outline" class="attach-avatar" style="background-color: #005aff" :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
129
+ <avatar v-if="item.fileType === 'image'" icon="ios-image-outline" class="attach-avatar"
130
+ style="background-color: #005aff"
131
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
81
132
  :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
82
- <avatar v-else-if="item.fileType === 'doc'" icon="ios-document-outline" class="attach-avatar" style="background-color: #005aff" :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
133
+ <avatar v-else-if="item.fileType === 'doc'" icon="ios-document-outline" class="attach-avatar"
134
+ style="background-color: #005aff"
135
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
83
136
  :size="portraitWidth >= 600 ? 'middle' : 'small'">
84
137
  </avatar>
85
- <avatar v-else-if="item.fileType === 'xlsx'" icon="ios-document-outline" class="attach-avatar" style="background-color: #19be6b" :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
138
+ <avatar v-else-if="item.fileType === 'xlsx'" icon="ios-document-outline" class="attach-avatar"
139
+ style="background-color: #19be6b"
140
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
86
141
  :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
87
- <avatar v-else-if="item.fileType === 'pdf'" icon="ios-document-outline" class="attach-avatar" style="background-color: #ed4014" :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
142
+ <avatar v-else-if="item.fileType === 'pdf'" icon="ios-document-outline" class="attach-avatar"
143
+ style="background-color: #ed4014"
144
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
88
145
  :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
89
- <avatar v-else icon="ios-document-outline" class="attach-avatar" :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
146
+ <avatar v-else icon="ios-document-outline" class="attach-avatar"
147
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
90
148
  :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
91
149
  </Col>
92
150
  <!-- 右边:附件信息 -->
@@ -122,59 +180,145 @@
122
180
  </div>
123
181
  </transition>
124
182
  <Modal title="查看附件" v-model="modalVisible" fullscreen scrollable :mask="false">
125
- <img :src="imageUrl" v-if="modalVisible" alt="" style="width: 100%">
183
+ <img :src="imageUrl" v-if="modalVisible" alt="" style="width: 100%">
126
184
  <div slot="footer">
127
185
  <Button type="primary" @click="modalVisible = false">关闭</Button>
128
186
  </div>
129
187
  </Modal>
130
188
  <Modal title="查看附件" v-model="modalDocx" fullscreen scrollable :mask="false">
131
- <div ref="file" ></div>
132
- </Modal>
133
- <Modal v-model="modal1" title="选择节点"
134
- @on-cancel="cancel"
135
- @on-ok="ok">
136
- <Table border
137
- :data="allNode"
138
- :columns="nodeColumn"
139
- highlight-row
140
- @on-current-change="selectNode">
141
- </Table>
142
- </Modal>
143
- <assigneeBox ref="assigneeHelpBox" :executionCompleted="executionCompleted" @update-selected="handleSelectedUser"
144
- :data="assigneeBoxData" :smart-flow-server-context="smartFlowServerContext" :upms-server-context="upmsServerContext"/>
145
- <Modal v-model="modalBoxShow" width="1000" title="流程跟踪图">
146
- <Workflow_Diagram ref="processTrace" :instanceId="process.instanceId" :applyId="process.applyId"
147
- :procId="process.procId"
148
- :tableData="process.tableData" :hisAudit="hisAudit"
149
- :smart-flow-server-context="smartFlowServerContext">
150
- </Workflow_Diagram>
189
+ <div ref="file"></div>
151
190
  </Modal>
152
191
  </lamboIndicatorCard>
153
192
  </transition>
193
+
194
+ <Modal v-model="modal1" title="选择节点"
195
+ @on-cancel="cancel"
196
+ @on-ok="doPass">
197
+ <Table border
198
+ :data="allNode"
199
+ :columns="nodeColumn"
200
+ highlight-row
201
+ @on-current-change="selectNode">
202
+ </Table>
203
+ </Modal>
204
+ <assigneeBox ref="assigneeHelpBox" :execution-completed="executionCompleted"
205
+ @update-selected="handleSelectedUser" @update-next-node-assignee="updateNextNodeAssignee"
206
+ :data="assigneeBoxData" :smart-flow-server-context="smartFlowServerContext"
207
+ :upms-server-context="upmsServerContext"/>
208
+ <Modal v-model="modalBoxShow" width="1000" title="流程跟踪图">
209
+ <Workflow_Diagram ref="processTrace" :instanceId="process.instanceId" :applyId="process.applyId"
210
+ :procId="process.procId" :table-columns="diagramTableColumns"
211
+ :tableData="process.tableData" :hisAudit="hisAudit" :approve-detail-show-way="approveDetailShowWay"
212
+ :smart-flow-server-context="smartFlowServerContext">
213
+ </Workflow_Diagram>
214
+ </Modal>
215
+ <Modal v-model="appointBoxShow" title="下一环节设置"
216
+ @on-cancel="appointBoxShow = false" width="600"
217
+ @on-ok="appointOk">
218
+ <Card v-for="(item,index) of nextNodesFormList" :key="index" style="margin-bottom: 10px"
219
+ v-if="handleButtons && (handleButtons.includes('appointHandler') || handleButtons.includes('appointTimeoutTime'))">
220
+ <Form ref="appointBox" justify="center" :label-width="100" :model="item"
221
+ style="margin: 10px 0 0 10px;" :rules="ruleValidate">
222
+ <div v-if="handleButtons && handleButtons.includes('appointHandler')">
223
+ <FormItem label="下一环节:">
224
+ {{ item.name }}
225
+ </FormItem>
226
+ <FormItem label="人员类型:" v-if="!item.isMultiInstance">
227
+ <RadioGroup v-model="item.actionType">
228
+ <Radio label="ASSIGNEE">办理人</Radio>
229
+ <Radio label="CAND">候选人</Radio>
230
+ </RadioGroup>
231
+ </FormItem>
232
+ <FormItem label="办理人员:" prop="assignee" v-if="!item.isMultiInstance && item.actionType === 'ASSIGNEE'">
233
+ <Input v-model="item.assigneeName"
234
+ placeholder="请选择办理人"
235
+ style="width: 68%"
236
+ icon="md-apps"
237
+ @on-focus="readingRangeClick(item)"
238
+ @on-click="readingRangeClick(item)"/>
239
+ </FormItem>
240
+ <FormItem label="候选人员:" prop="candidateGroups" v-if="!item.isMultiInstance && item.actionType === 'CAND'">
241
+ <Input v-model="item.candidateNames"
242
+ placeholder="请选择候选人"
243
+ style="width: 68%"
244
+ icon="md-apps"
245
+ @on-focus="candidateGroupsReadingRangeClick(item)"
246
+ @on-click="candidateGroupsReadingRangeClick(item)"/>
247
+ </FormItem>
248
+ <FormItem label="候选人员:" v-if="item.isMultiInstance && item.actionType === 'CAND'">
249
+ </FormItem>
250
+ <countersingersBox style="margin-bottom: 10px" v-model="item.candidateNames" v-if="item.isMultiInstance && item.actionType === 'CAND'"
251
+ :item="item" :permScope="permScope" @update-cand-groups="updateCandGroups" :upms-server-context="upmsServerContext" :smart-flow-server-context="smartFlowServerContext"/>
252
+ </div>
253
+ <div v-if="handleButtons && handleButtons.includes('appointTimeoutTime')">
254
+ <Row>
255
+ <Col span="12">
256
+ <FormItem label="停留时间:">
257
+ <Input v-model="item.remainDay" style="width: 100px" type="number" :min="0"></Input>
258
+
259
+ </FormItem>
260
+ </Col>
261
+ <Col span="12">
262
+ <FormItem>
263
+ <Input v-model="item.remainTime" style="margin-left: -140px; width: 100px" type="number"
264
+ :min="0"></Input>
265
+ 小时 自动处理
266
+ </FormItem>
267
+ </Col>
268
+ </Row>
269
+ <Row>
270
+ <Col span="12">
271
+ <FormItem label="任务提前:">
272
+ <Input v-model="item.inAdvanceDay" style="width: 100px" type="number" :min="0"></Input>
273
+
274
+ </FormItem>
275
+ </Col>
276
+ <Col span="12">
277
+ <FormItem>
278
+ <Input v-model="item.inAdvanceTime" style="margin-left: -140px;width: 100px" type="number"
279
+ :min="0"></Input>
280
+ 小时 标红预警
281
+ </FormItem>
282
+ </Col>
283
+ </Row>
284
+ <FormItem label="处理方式:">
285
+ <Select v-model="item.processing" style="width:200px" placeholder="自动同意">
286
+ <Option v-for="item in handleTypeList" :value="item.value" :key="item.value">
287
+ {{ item.label }}
288
+ </Option>
289
+ </Select>
290
+ </FormItem>
291
+ </div>
292
+ </Form>
293
+ </Card>
294
+ </Modal>
295
+ <candidateGroupsHelpBox ref="candidateGroupsHelpBox" :show="candidateGroupsHelpBoxShow" @update-cand-groups="updateCandGroups"
296
+ :upms-server-context="upmsServerContext" :smart-flow-server-context="smartFlowServerContext"/>
154
297
  <template slot="page-footer">
155
298
  <div>
156
299
  <slot name="footer-button"></slot>
157
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo70')"
300
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo70') && !isDetail"
158
301
  :disabled="disable" :loading="loading" @click="audit('70')">驳回到原点
159
302
  </Button>
160
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo40')"
161
- :disabled="disable" :loading="loading" @click="audit('40')">驳回到上一级
303
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo40') && !isDetail"
304
+ :disabled="disable" :loading="loading" @click="audit('40')">驳回上一节点
162
305
  </Button>
163
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo90')"
306
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo90') && !isDetail"
164
307
  :disabled="disable" :loading="loading" @click="audit('90')">驳回指定节点
165
308
  </Button>
166
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo80')"
309
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo80') && !isDetail"
167
310
  :disabled="disable" :loading="loading" @click="audit('80')">跳转指定节点
168
311
  </Button>
169
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo82')"
312
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo82') && !isDetail"
170
313
  :disabled="disable" :loading="loading" @click="audit('82')">指定他人处理
171
314
  </Button>
172
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo50')"
315
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo50') && !isDetail"
173
316
  :disabled="disable" :loading="loading" @click="audit('50')">直接结束流程
174
317
  </Button>
175
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('processTrace')"
176
- @click="processPrint" >流程跟踪图</Button>
177
- <Button style="margin-left: 10px;" v-if="!handleButtons || handleButtons.includes('auditTo30')"
318
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('processTrace')"
319
+ @click="processPrint">流程跟踪图
320
+ </Button>
321
+ <Button style="margin-left: 10px;" v-if="handleButtons && handleButtons.includes('auditTo30') && !isDetail"
178
322
  :disabled="disable" :loading="loading" type="primary" @click="audit('30')">通过
179
323
  </Button>
180
324
  </div>
@@ -188,14 +332,17 @@ import LamboPageContainer from '@lambo-design/page-container'
188
332
  import LamboIndicatorCard from '@lambo-design/indicator-card'
189
333
  import Workflow_Diagram from './workflow-diagram'
190
334
  import ajax from "@lambo-design/shared/utils/ajax";
191
- import { operateBtn } from '@lambo-design/shared/utils/assist';
192
335
  import bus from '@lambo-design/shared/utils/bus';
193
336
  import Title from "./components/title";
194
337
  import processHistory from "./components/history";
195
338
  import assigneeBox from "./components/assignee-box";
339
+ import CandidateGroupsHelpBox from "./components/candidate-groups-box";
340
+ import CountersingersBox from "./components/countersigners-box"
196
341
  import LamboPagingTable from "@lambo-design/paging-table";
197
342
  import AuditOpinion from "./components/opinion";
198
343
  import axios from "axios";
344
+ import UploadFile from "@lambo-design/upload-file";
345
+ import {timestampToTime} from "@lambo-design/shared/utils/date";
199
346
 
200
347
  // 引入docx-preview插件
201
348
  let docx = require('docx-preview');
@@ -203,6 +350,11 @@ let docx = require('docx-preview');
203
350
 
204
351
  export default {
205
352
  props: {
353
+ isDetail: {
354
+ type: Boolean,
355
+ required: false,
356
+ default: false
357
+ },
206
358
  width: {
207
359
  type: Number,
208
360
  required: false,
@@ -220,6 +372,39 @@ export default {
220
372
  type: String,
221
373
  required: true,
222
374
  },
375
+ taskId: {
376
+ type: String,
377
+ required: false,
378
+ default: '',
379
+ },
380
+ auditGroup: {
381
+ type: String,
382
+ required: false,
383
+ default: '',
384
+ },
385
+ defaultAuditOpinion: {
386
+ type: String,
387
+ required: false,
388
+ default: '',
389
+ },
390
+ //详情页催办按钮
391
+ pushButton: {
392
+ type: Boolean,
393
+ required: false,
394
+ default: true,
395
+ },
396
+ //流程跟踪图附件列
397
+ showAttachmentFile: {
398
+ type: Boolean,
399
+ required: false,
400
+ default: true,
401
+ },
402
+ //流程跟踪图审批详情触发方式
403
+ approveDetailShowWay: {
404
+ type: String,
405
+ required: false,
406
+ default: 'click',
407
+ },
223
408
  //业务表单保存方法
224
409
  businessFormSave: {
225
410
  type: Function,
@@ -229,8 +414,9 @@ export default {
229
414
  executionCompleted: {
230
415
  type: Function,
231
416
  required: false,
417
+ default: () => {}
232
418
  },
233
- title:{
419
+ title: {
234
420
  type: String,
235
421
  default: "流程办理"
236
422
  },
@@ -251,11 +437,15 @@ export default {
251
437
  assigneeBox,
252
438
  LamboPagingTable,
253
439
  AuditOpinion,
254
- LamboIndicatorCard
440
+ LamboIndicatorCard,
441
+ UploadFile,
442
+ CandidateGroupsHelpBox,
443
+ CountersingersBox
255
444
  },
256
445
  data() {
257
446
  return {
258
447
  isExpanded: true,
448
+ showProcessInfo: true,
259
449
  portraitWidth: 0,
260
450
  requestSuccessCodes: [200, "200"],
261
451
  auditShow: true,
@@ -272,10 +462,20 @@ export default {
272
462
  auditParams: {},
273
463
  modal1: false,
274
464
  modalBoxShow: false,
465
+ candidateGroupsHelpBoxShow: false,
466
+ appointBoxShow: false,
467
+ autoOpenNode: '0',
468
+ nextNodesOldSettings: [],
469
+ nextNodesFormList: [],
275
470
  hisNode: [],
276
471
  processHistory: [],
472
+ permScope: '',
473
+ organTreeType: '00',
474
+ defaultOrganTreeType: '00',
277
475
  ruleValidate: {
278
- auditOpinion: [{required: true, trigger: "blur", message: "审批意见不能为空"}]
476
+ auditOpinion: [{required: true, trigger: "blur", message: '意见不能为空'}],
477
+ assignee: [{required: true, trigger: "blur", message: "办理人不能为空"}],
478
+ candidateGroups: [{required: true, trigger: "blur", message: "候选人不能为空"}],
279
479
  },
280
480
  form: {
281
481
  auditOpinion: '',
@@ -283,14 +483,22 @@ export default {
283
483
  loading: false,
284
484
  disable: false,
285
485
  instanceId: '',
286
- taskId: '',
486
+ curTaskId: '',
287
487
  handleButtons: [],
488
+ handleName: '',
489
+ auditOpinionTitle: '',
288
490
  auditResult: '',
491
+ curAuditGroup: '',
289
492
  custChange: 'auditInfo',
290
493
  auditInfo: "auditInfo",
291
494
  auditProcess: "auditProcess",
292
495
  fileList: [],
496
+ ossFilePutUrl: '/manage/oss/file/put',
293
497
  hisAudit: [],
498
+ hisAuditOpinion: [{
499
+ auditOpinion: '',
500
+ auditTime: '',
501
+ }],
294
502
  datas: {
295
503
  orgName: "",
296
504
  orgId: ""
@@ -307,26 +515,58 @@ export default {
307
515
  procId: ''
308
516
  },
309
517
  handleButtonsNames: {
310
- '30': '同意',
311
- '70': '驳回原点',
518
+ '30': '通过',
519
+ '70': '驳回到原点',
312
520
  '40': '驳回上一节点',
313
521
  '90': '驳回指定节点',
314
522
  '80': '跳转指定节点',
315
- '82': '转办',
316
- '50': '人工终止'
523
+ '82': '指定他人处理',
524
+ '50': '直接结束流程'
317
525
  },
526
+ handleTypeList: [
527
+ {
528
+ value: '00',
529
+ label: '只预警不处理'
530
+ },
531
+ {
532
+ value: '10',
533
+ label: '自动同意'
534
+ },
535
+ {
536
+ value: '20',
537
+ label: '直接终止流程'
538
+ },
539
+ {
540
+ value: '90',
541
+ label: '自动驳回'
542
+ }
543
+ ],
318
544
  }
319
545
 
320
546
  },
321
547
 
322
548
  mounted() {
323
549
  this.getWidth()
324
- if (this.procId){
550
+ if (this.procId) {
325
551
  this.initData()
326
552
  }
327
553
 
328
554
  },
329
555
  computed: {
556
+ processHistoryHeight() {
557
+ let str = '';
558
+ const hasAuditOpinion = this.taskNode && this.handleButtons && this.handleButtons.includes('auditOpinion')
559
+ const hasAttachmentFile = this.handleButtons && this.handleButtons.includes('auditHistory') && this.attachmentList.length > 0
560
+ const isDetail = this.isDetail && !this.hisAuditOpinion[0].auditOpinion.length > 0
561
+ if (hasAuditOpinion && !hasAttachmentFile && !isDetail) {
562
+ str += "height: 43vh"
563
+ } else if (hasAuditOpinion && hasAttachmentFile && !isDetail) {
564
+ str += "height: 40vh"
565
+ } else {
566
+ str += "height: 67vh"
567
+ }
568
+ return str;
569
+ },
330
570
  nodeColumn: function () {
331
571
  let column = []
332
572
  column.push({title: '序号', type: 'index', width: 70, align: 'center', fixed: 'left'});
@@ -349,7 +589,7 @@ export default {
349
589
  props: {
350
590
  color: '#ff9900'
351
591
  }
352
- }, '未审批')
592
+ }, `未${params.row.handleName ? params.row.handleName : '审批'}`)
353
593
  ])
354
594
  } else {
355
595
  if (params.row.auditResult == '30' && params.row.taskNode != this.taskNode) {
@@ -358,7 +598,7 @@ export default {
358
598
  props: {
359
599
  color: '#19be6b'
360
600
  }
361
- }, '已审批通过')
601
+ }, `已${params.row.handleName ? params.row.handleName : '审批'}通过`)
362
602
  ])
363
603
  } else if (params.row.auditResult == '40' && params.row.taskNode != this.taskNode) {
364
604
  return h('div', [
@@ -384,7 +624,7 @@ export default {
384
624
  }
385
625
  }, '已跳转到指定节点')
386
626
  ])
387
- } else if (params.row.auditResult == '80' && params.row.taskNode != this.taskNode) {
627
+ } else if (params.row.auditResult == '90' && params.row.taskNode != this.taskNode) {
388
628
  return h('div', [
389
629
  h('tag', {
390
630
  props: {
@@ -419,7 +659,116 @@ export default {
419
659
  })
420
660
  return column
421
661
  },
662
+ diagramTableColumns: function () {
663
+ let column = []
664
+ column.push({title: '序号', type: 'index', width: 60});
665
+ column.push({title: `${this.handleName}节点`, key: 'taskName', minWidth: 130})
666
+ column.push({title: `${this.handleName}人`, key: 'auditName', minWidth: 150, tooltip: true})
667
+ column.push({
668
+ title: `${this.handleName}结果`, key: 'auditResult', minWidth: 150, align: 'center',
669
+ render: (h, {row, column, index}) => {
670
+ let label = "";
671
+ let tagColor = "";
672
+ if (row.auditResult == '00'){
673
+ label = '流程发起';
674
+ tagColor = 'green'; // 绿色
675
+ }
676
+ else if (row.auditResult == '30'){
677
+ label = '通过';
678
+ tagColor = 'green'; // 绿色
679
+ }
680
+ else if (row.auditResult == '40'){
681
+ label = '驳回到上一级';
682
+ tagColor = 'volcano'; // 火红色
683
+ }
684
+ else if (row.auditResult == '50'){
685
+ label = '驳回到原点';
686
+ tagColor = 'red'; // 红色
687
+ }
688
+ else if (row.auditResult == '51'){
689
+ label = '流程终止';
690
+ tagColor = 'purple'; // 紫色
691
+ }
692
+ else if (row.auditResult == '60'){
693
+ label = '撤回';
694
+ tagColor = 'blue'; // 蓝色
695
+ }
696
+ else if (row.auditResult == '80'){
697
+ label = '跳转到指定节点';
698
+ tagColor = 'cyan'; // 青色
699
+ }
700
+ else if (row.auditResult == '90'){
701
+ label = '驳回到指定节点';
702
+ tagColor = 'magenta'; // 品红色
703
+ }
704
+ else{
705
+ label = '待审核';
706
+ tagColor = 'orange'; // 默认橙色
707
+ }
708
+ return h('Tag', {
709
+ props: {
710
+ color: tagColor,
711
+ value: row.auditResult
712
+ }
713
+ }, label);
714
+ }
715
+ })
716
+ column.push({
717
+ title: `${this.handleName}时间`, key: 'auditTime', minWidth: 150,
718
+ render: (h, {row}) => {
719
+ const displayDate = row.startDate || row.auditDate;
720
+ return h('span', displayDate);
721
+ }
722
+ })
723
+ column.push({
724
+ title: `${this.handleName}意见`, key: 'auditComment', minWidth: 180, tooltip: true,
725
+ render: (h, {row, column, index}) => {
726
+ let label = "";
727
+ if (row.auditComment == '' || row.auditComment == null) label = '无';
728
+ else label = row.auditComment;
729
+ return h('Label', {
730
+ props: {
731
+ value: row.auditComment
732
+ }
733
+ }, label)
734
+ }
735
+ })
736
+ if (this.showAttachmentFile){
737
+ column.push({
738
+ title: `附件`, key: 'fileList', minWidth: 200,
739
+ render: (h, { row }) => {
740
+ if (!row.fileList || row.fileList.length === 0) {
741
+ return h('span', '无'); // 如果没有附件,显示“无”
742
+ }
743
+
744
+ //显示所有附件
745
+ return h('div', row.fileList.map(file => {
746
+ return h('a', {
747
+ style: {
748
+ display: 'block',
749
+ marginTop: '5px',
750
+ marginRight:'5px',
751
+ whiteSpace: 'nowrap',
752
+ overflow: 'hidden',
753
+ textOverflow: 'ellipsis',
754
+ maxWidth: '100px',
755
+ },
756
+ attrs: {
757
+ title: file.attachName // 鼠标悬停时显示完整名称
758
+ },
759
+ on: {
760
+ click: () => {
761
+ this.getAttach(file);
762
+ }
763
+ },
764
+ }, file.attachName);
765
+ }));
766
+ }
767
+ })
768
+ }
422
769
 
770
+ return column
771
+ },
423
772
  },
424
773
  provide() {
425
774
  return {
@@ -433,50 +782,105 @@ export default {
433
782
  }
434
783
  this.portraitWidth = this.width
435
784
  },
436
- initData(){
437
- this.getAttachList()
438
- this.getTaskId()
785
+ initData() {
786
+ if (!this.isDetail) {
787
+ this.getTodoTask()
788
+ } else {
789
+ this.getDoneTask()
790
+ }
439
791
  this.getHandleButtons()
440
- this.getHisAudit();
441
- this.getProcessHistory();
442
792
  },
443
- saveBusinessForm() {
444
- this.businessFormSave(() => {
793
+ getTodoTask() {
794
+ const self = this
795
+ let param = {
796
+ procId: this.procId,
797
+ applyId: this.applyId,
798
+ taskNode: this.taskNode,
799
+ taskId: this.taskId,
800
+ auditGroup: this.auditGroup
801
+ }
802
+ ajax.get(self.smartFlowServerContext + "/manage/processTodo/list", {params: param}).then(function (resp) {
803
+ if (resp.data.code === '200') {
804
+ self.curTaskId = resp.data.data.rows[0].taskId
805
+ self.instanceId = resp.data.data.rows[0].procInstanceId
806
+ self.curAuditGroup = resp.data.data.rows[0].auditGroup
807
+ let procType = resp.data.data.rows[0].procType
808
+ ajax.get(self.smartFlowServerContext + "/manage/processType/lists?proType=" + procType)
809
+ .then(resp => {
810
+ let data = resp.data.data.rows
811
+ self.permScope = data[0].permScope
812
+ self.defaultOrganTreeType = data[0].organTreeType ? data[0].organTreeType : '00'
813
+ self.getNodeOrganTreeType(procType)
814
+ }).catch(err => {
815
+ console.log(err);
816
+ })
817
+ self.getAttachList(self.curTaskId)
818
+ self.getHisAudit(self.curTaskId);
819
+ self.getProcessHistory(self.curTaskId);
820
+ } else {
821
+ self.$Message.error(resp.data.message)
822
+ }
823
+ }).catch((err) => {
824
+ console.log(err)
445
825
  })
446
826
  },
447
- getAttachList() {
827
+ getNodeOrganTreeType(procType){
448
828
  const self = this
449
- const param = {
829
+ let param = {
830
+ procType: procType,
450
831
  procId: this.procId,
451
- applyId: this.applyId
832
+ taskNode: this.taskNode
452
833
  }
453
- ajax.get(self.smartFlowServerContext + '/manage/processDone/getAttachmentList', {params: param}).then(function (resp) {
454
- self.attachmentList = resp.data.data.rows
455
- self.attachmentList.forEach(item => {
456
- const index = item.fileName.lastIndexOf(".")
457
- const fileType = item.fileName.substr(index + 1).toLowerCase()
458
- const imageList = ['jpg', 'gif', 'png', 'svg']
459
- const docList = ['doc', 'docx']
460
- const zipList = ['rar', 'zip']
461
- const typeList = ['jpg', 'gif', 'png', 'docx']
462
- item.fileType = imageList.indexOf(fileType) !== -1 ? 'image' : docList.indexOf(fileType) !== -1 ? 'doc' : zipList.indexOf(fileType) !== -1 ? 'zip' : fileType
463
- item.showPreview = typeList.indexOf(fileType) !== -1
464
- })
465
- }).catch(err => {
466
- console.log(err);
834
+ ajax.get(self.smartFlowServerContext + "/manage/processTodo/getNodeOrganTreeType", {params: param}).then(function (resp) {
835
+ if (resp.data.code === '200') {
836
+ self.organTreeType = resp.data.data ? resp.data.data : self.defaultOrganTreeType
837
+ } else {
838
+ self.$Message.error(resp.data.message)
839
+ }
840
+ }).catch((err) => {
841
+ console.log(err)
467
842
  })
468
843
  },
469
- getTaskId() {
844
+ getDoneTask() {
470
845
  const self = this
471
846
  let param = {
472
847
  procId: this.procId,
473
848
  applyId: this.applyId,
474
- taskNode:this.taskNode
849
+ taskNode: this.taskNode,
850
+ taskId: this.taskId,
851
+ auditGroup: this.auditGroup
475
852
  }
476
- ajax.get(self.smartFlowServerContext + "/manage/processTodo/list", {params: param}).then(function (resp) {
853
+ ajax.get(self.smartFlowServerContext + "/manage/processDone/getDoneDetail", {params: param}).then(function (resp) {
477
854
  if (resp.data.code === '200') {
478
- self.taskId = resp.data.data.rows[0].taskId
479
- self.instanceId = resp.data.data.rows[0].procInstanceId
855
+ let rows = resp.data.data.rows
856
+ if (rows.length > 0) {
857
+ self.curAuditGroup = rows[0].auditGroup
858
+ self.hisAuditOpinion = []
859
+ let taskList = resp.data.data.rows
860
+ taskList.forEach(item => {
861
+ self.hisAuditOpinion.push({
862
+ auditOpinion: item.auditComment,
863
+ auditTime: timestampToTime(item.auditDate)
864
+ })
865
+ })
866
+ self.curTaskId = taskList[0].taskId
867
+ self.instanceId = taskList[0].procInstanceId
868
+ } else {
869
+ ajax.get(self.smartFlowServerContext + "/manage/processTodo/list", {params: param}).then(function (todoResp) {
870
+ if (todoResp.data.code === '200') {
871
+ self.curTaskId = todoResp.data.data.rows[0].taskId
872
+ self.instanceId = todoResp.data.data.rows[0].procInstanceId
873
+ self.curAuditGroup = todoResp.data.data.rows[0].auditGroup
874
+ } else {
875
+ self.$Message.error(todoResp.data.message)
876
+ }
877
+ }).catch((err) => {
878
+ console.log(err)
879
+ })
880
+ }
881
+ self.getAttachList(self.curTaskId)
882
+ self.getHisAudit(self.curTaskId);
883
+ self.getProcessHistory(self.curTaskId);
480
884
  } else {
481
885
  self.$Message.error(resp.data.message)
482
886
  }
@@ -493,6 +897,11 @@ export default {
493
897
  ajax.post(self.smartFlowServerContext + '/manage/approvalCenter/getNodeData', param).then(function (resp) {
494
898
  if (resp.data.code === '200') {
495
899
  self.handleButtons = resp.data.data[0].handleButtons
900
+ self.handleName = resp.data.data[0].handleName ? resp.data.data[0].handleName : '审批'
901
+ self.auditOpinionTitle = resp.data.data[0].handleName ? resp.data.data[0].handleName + '意见' : '审批意见'
902
+ if (!self.handleButtons || (!self.handleButtons.includes('auditOpinion') && !self.handleButtons.includes('attachmentFile') && !self.handleButtons.includes('auditHistory'))){
903
+ self.showProcessInfo = false
904
+ }
496
905
  } else {
497
906
  self.$Message.error(resp.data.message)
498
907
  }
@@ -500,33 +909,212 @@ export default {
500
909
  console.log(err)
501
910
  })
502
911
  },
503
- handleSaveResult(saveResult) {
504
- if (saveResult) {
505
- this.executeButtonAction((execResult, instanceId, taskId) => {
506
- if (this.executionCompleted) {
507
- this.executionCompleted(execResult, instanceId, taskId);
912
+ getNextNodes(){
913
+ const self = this
914
+ self.nextNodesFormList = []
915
+ self.nextNodesOldSettings = []
916
+ let param = {
917
+ procId: this.procId,
918
+ taskNode: this.taskNode
919
+ }
920
+ ajax.post(self.smartFlowServerContext + '/manage/processTodo/getNextNodes', param).then(function (resp) {
921
+ if (resp.data.code === '200') {
922
+ let nextNodeForm = {}
923
+ let nextNodeOldForm = {}
924
+ let data = resp.data.data
925
+ for (let i = 0; i < data.length; i++) {
926
+ nextNodeOldForm = {
927
+ id: data[i].id,
928
+ assignee: data[i].assignee ? data[i].assignee.id : '',
929
+ timeLimit: data[i].timeLimit,
930
+ }
931
+ nextNodeForm = {
932
+ id: data[i].id,
933
+ name: data[i].name,
934
+ orgTreeType: data[i].orgTreeType,
935
+ assignee: data[i].assignee ? data[i].assignee.id : '',
936
+ assigneeName: data[i].assignee ? data[i].assignee.name : '',
937
+ candidateGroups: '',
938
+ isMultiInstance: data[i].isMultiInstance,
939
+ actionType: 'ASSIGNEE',
940
+ remainDay : 0,
941
+ remainTime : 0,
942
+ inAdvanceDay : 0,
943
+ inAdvanceTime : 0,
944
+ processing : '00'
945
+ }
946
+ //显示具体候选人信息
947
+ if (data[i].candidateGroups){
948
+ nextNodeForm.actionType = 'CAND'
949
+ let names = [];
950
+ let candidates = {};
951
+ for (let groupName in data[i].candidateGroups) {
952
+ if (data[i].candidateGroups.hasOwnProperty(groupName)) {
953
+ let group = data[i].candidateGroups[groupName];
954
+ group.forEach(item => {
955
+ names.push(item.name);
956
+ });
957
+ candidates[groupName] = group.map(item => item.id + ':' + item.name).join(',');
958
+ }
959
+ }
960
+ nextNodeForm.candidateNames = names.join(',');
961
+ nextNodeForm.candidates = candidates;
962
+ nextNodeOldForm.candidates = candidates;
963
+ }
964
+ if (data[i].timeLimit) {
965
+ let expireTime = data[i].timeLimit.split(";")[0].split(":")[1]
966
+ let warningTime = data[i].timeLimit.split(";")[1].split(":")[1]
967
+ let handleType = data[i].timeLimit.split(";")[2].split(":")[1]
968
+ let days = expireTime.slice(0, expireTime.indexOf("D")) //过期天
969
+ let hourOfDay = expireTime.slice(expireTime.indexOf("D") + 1, expireTime.indexOf("H")) //过期小时
970
+ let daysWarn = warningTime.slice(0, warningTime.indexOf("D")) //警告天
971
+ let hourOfDayWarn = warningTime.slice(warningTime.indexOf("D") + 1, warningTime.indexOf("H")) //警告小时
972
+ nextNodeForm.remainDay = parseInt(days)
973
+ nextNodeForm.remainTime = parseInt(hourOfDay)
974
+ nextNodeForm.inAdvanceDay = parseInt(daysWarn)
975
+ nextNodeForm.inAdvanceTime = parseInt(hourOfDayWarn)
976
+ nextNodeForm.processing = handleType
977
+ }
978
+ self.nextNodesFormList.push(nextNodeForm)
979
+ self.nextNodesOldSettings.push(nextNodeOldForm)
508
980
  }
509
- });
981
+ } else {
982
+ self.$Message.error(resp.data.message)
983
+ }
984
+ }).catch((err) => {
985
+ console.log(err)
986
+ })
987
+ },
988
+ getAttachList(taskId) {
989
+ const self = this
990
+ const param = {
991
+ taskId: taskId,
992
+ procId: this.procId,
993
+ applyId: this.applyId
994
+ }
995
+ ajax.get(self.smartFlowServerContext + '/manage/processDone/getAttachmentList', {params: param}).then(function (resp) {
996
+ self.attachmentList = resp.data.data.rows
997
+ self.attachmentList.forEach(item => {
998
+ const index = item.fileName.lastIndexOf(".")
999
+ const fileType = item.fileName.substr(index + 1).toLowerCase()
1000
+ const imageList = ['jpg', 'gif', 'png', 'svg']
1001
+ const docList = ['doc', 'docx']
1002
+ const zipList = ['rar', 'zip']
1003
+ const typeList = ['jpg', 'gif', 'png', 'docx']
1004
+ item.fileType = imageList.indexOf(fileType) !== -1 ? 'image' : docList.indexOf(fileType) !== -1 ? 'doc' : zipList.indexOf(fileType) !== -1 ? 'zip' : fileType
1005
+ item.showPreview = typeList.indexOf(fileType) !== -1
1006
+ })
1007
+ }).catch(err => {
1008
+ console.log(err);
1009
+ })
1010
+ },
1011
+ getHisAudit(taskId) {
1012
+ let self = this
1013
+ let params = {
1014
+ applyId: self.applyId,
1015
+ instanceId: self.instanceId,
1016
+ procId: self.procId,
1017
+ taskId: taskId
1018
+ }
1019
+ ajax.get(self.smartFlowServerContext + '/manage/processTodo/getHisAudit', {params: params}).then(function (resp) {
1020
+ if (resp.data.code === '200') {
1021
+ self.hisAudit = resp.data.data
1022
+ let uniqueDataMap = {};
1023
+ self.hisAudit.forEach((item) => {
1024
+ uniqueDataMap[item["taskNode"]] = item;
1025
+ })
1026
+ self.hisNode = Object.values(uniqueDataMap);
1027
+
1028
+ }
1029
+ })
1030
+ },
1031
+ getProcessHistory(taskId) {
1032
+ let self = this
1033
+ let params = {
1034
+ applyId: self.applyId,
1035
+ instanceId: self.instanceId,
1036
+ procId: self.procId,
1037
+ taskId: taskId
1038
+ }
1039
+ ajax.get(self.smartFlowServerContext + '/manage/processTodo/getProcessHis', {params: params}).then(function (resp) {
1040
+ if (resp.data.code === '200') {
1041
+ self.processHistory = resp.data.data
1042
+ }
1043
+ })
1044
+ },
1045
+
1046
+ audit: function (auditResult) {
1047
+ let self = this
1048
+ self.auditResult = auditResult
1049
+ self.submit()
1050
+ },
1051
+ submit() {
1052
+ let self = this;
1053
+ self.auditParams = {
1054
+ procId: self.procId,
1055
+ applyId: self.applyId,
1056
+ taskId: self.curTaskId,
1057
+ auditOpinion: self.form.auditOpinion,
1058
+ fileListStr: JSON.stringify(self.fileList),
1059
+ auditResult: self.auditResult,
1060
+ params: JSON.stringify(self.datas),
1061
+ targetTaskNode: self.targetTaskNode,
1062
+ selectedUserId: self.selectedUserId,
1063
+ }
1064
+ if (self.auditResult == '' || self.auditResult == null) {
1065
+ self.$Message.error(`请选择${self.handleName}结果!`);
1066
+ return;
1067
+ }
1068
+ if (self.form.auditOpinion == '' || self.form.auditOpinion == null) {
1069
+ if (!self.handleButtons || self.handleButtons.includes('auditOpinion')) {
1070
+ self.$Message.error(`请输入${self.handleName}意见!`)
1071
+ return;
1072
+ } else {
1073
+ self.auditParams.auditOpinion = self.handleButtonsNames[self.auditResult];
1074
+ }
1075
+ }
1076
+ self.businessFormSave ? self.businessFormSave(self.handleSaveResult) : self.handleSaveResult(true)
1077
+ },
1078
+ handleSaveResult(saveResult, businessParams) {
1079
+ if (saveResult) {
1080
+ this.executeButtonAction(businessParams);
510
1081
  } else {
511
1082
  console.error('保存失败');
512
1083
  }
513
1084
  },
514
- executeButtonAction(callback) {
1085
+ executeButtonAction(businessParams) {
515
1086
  const self = this;
516
- if (self.auditResult == '82') {
1087
+ if (businessParams) {
1088
+ Object.assign(self.datas, businessParams)
1089
+ self.auditParams.params = JSON.stringify(self.datas)
1090
+ }
1091
+ let auditResult = {
1092
+ code: self.auditResult,
1093
+ name: self.handleButtonsNames[self.auditResult]
1094
+ }
1095
+ if (self.auditResult === '82') {
517
1096
  self.assigneeBoxData = self.auditParams
518
- self.$refs.assigneeHelpBox.toggleShowHelpBox();
519
- } else if (self.auditResult == '80') {
1097
+ self.assigneeBoxData.auditResultName = self.handleButtonsNames[self.auditResult]
1098
+ self.assigneeBoxData.instanceId = self.instanceId
1099
+ self.$refs.assigneeHelpBox.toggleShowHelpBox(self.organTreeType, '', 'transferCurTask')
1100
+ } else if (self.auditResult === '80') {
520
1101
  self.getNodesBehind()
521
- } else if (self.auditResult == '90') {
1102
+ } else if (self.auditResult === '90') {
522
1103
  self.getAllPreNodes()
523
- } else if (self.auditResult == '40') {
1104
+ } else if (self.auditResult === '40') {
524
1105
  self.loading = true
525
1106
  self.disable = true
526
1107
  let url = self.smartFlowServerContext + '/manage/processTodo/getPreNode'
527
1108
  ajax.post(url, self.auditParams).then(function (resp) {
528
1109
  let result = resp.data
529
- if (result.code == '30010') {
1110
+ if (result.code == '30013' || result.code == '30014') {
1111
+ //前序节点为子流程或当前节点为子流程第一个节点不可驳回上一级节点
1112
+ self.$Message.warning(result.message)
1113
+ //避免未提示消息直接回调
1114
+ setTimeout(() => {
1115
+ self.executionCompleted(false, null, null, auditResult, self.curTaskId);
1116
+ }, 1000)
1117
+ } else if (result.code == '30010') {
530
1118
  self.$Modal.confirm({
531
1119
  title: "提示",
532
1120
  content: result.message,
@@ -540,13 +1128,17 @@ export default {
540
1128
  self.disable = false
541
1129
  self.$Message.success(result.message);
542
1130
  //后端没有返回数据
543
- callback(true, null, null);
1131
+ setTimeout(() => {
1132
+ self.executionCompleted(true, null, null, auditResult, self.curTaskId);
1133
+ }, 1000)
544
1134
  bus.$emit('triggerTimer')
545
1135
  } else {
546
1136
  self.loading = false
547
1137
  self.disable = false
548
1138
  self.$Message.error(result.message)
549
- callback(false, null, null);
1139
+ setTimeout(() => {
1140
+ self.executionCompleted(false, null, null, auditResult, self.curTaskId);
1141
+ }, 1000)
550
1142
  }
551
1143
  bus.$emit('triggerTimer')
552
1144
  })
@@ -556,6 +1148,14 @@ export default {
556
1148
  self.disable = false
557
1149
  }
558
1150
  })
1151
+ } else if (result.code == '10012') {
1152
+ // 数据同步
1153
+ self.loading = false
1154
+ self.disable = false
1155
+ self.$Message.warning(result.message)
1156
+ setTimeout(() => {
1157
+ self.executionCompleted(true, null, null, auditResult, self.curTaskId)
1158
+ }, 1000)
559
1159
  } else {
560
1160
  self.loading = true
561
1161
  self.disable = true
@@ -566,51 +1166,92 @@ export default {
566
1166
  self.loading = false
567
1167
  self.disable = false
568
1168
  self.$Message.success(result.message);
569
- if (result.data){
570
- callback(true, result.data.processInstanceId, result.data.id)
571
- }else {
572
- callback(true, null, null)
573
- }
1169
+ setTimeout(() => {
1170
+ if (result.data) {
1171
+ let taskIds = result.data.map(item => item.id).join(',');
1172
+ self.executionCompleted(true, result.data[0].processInstanceId, taskIds, auditResult, self.curTaskId)
1173
+ } else {
1174
+ self.executionCompleted(true, null, null, auditResult, self.curTaskId)
1175
+ }
1176
+ }, 1000)
574
1177
  } else {
575
1178
  self.loading = false
576
1179
  self.disable = false
577
1180
  self.$Message.error(result.message)
578
- callback(false, null, null);
1181
+ setTimeout(() => {
1182
+ self.executionCompleted(false, null, null, auditResult, self.curTaskId);
1183
+ }, 1000)
579
1184
  }
580
1185
  bus.$emit('triggerTimer')
581
1186
  })
582
1187
  }
583
1188
  })
1189
+ } else {
1190
+ if (self.auditResult === '30' && (!self.handleButtons || self.handleButtons.includes('appointHandler') || self.handleButtons.includes('appointTimeoutTime'))){
1191
+ self.getNextNodes()
1192
+ self.appointBoxShow = true
1193
+ } else {
1194
+ self.doPass()
1195
+ }
1196
+ }
1197
+ },
1198
+ doPass(){
1199
+ let self = this;
1200
+ this.modal = false
1201
+ let auditResult = {
1202
+ code: self.auditResult,
1203
+ name: self.handleButtonsNames[self.auditResult]
1204
+ }
1205
+ if (self.auditResult === '82' && (self.targetTaskNode == '' || self.targetTaskNode == null)) {
1206
+ self.auditResult = '';
1207
+ self.$Message.error(`请选择${self.handleName}节点!`);
584
1208
  } else {
585
1209
  self.loading = true
586
1210
  self.disable = true
1211
+ self.auditParams.targetTaskNode = self.targetTaskNode
587
1212
  let url = self.smartFlowServerContext + '/manage/processTodo/audit'
588
1213
  ajax.post(url, self.auditParams).then(function (resp) {
589
1214
  let result = resp.data
590
1215
  if (result.code == '200') {
591
1216
  self.loading = false
592
1217
  self.disable = false
1218
+ self.$Message.success(result.message ? result.message : `${self.handleName}成功`);
593
1219
  if (result.data){
594
- callback(true, result.data.processInstanceId, result.data.id)
595
- }else {
596
- callback(true, null, null)
1220
+ let taskIds = result.data.id ? result.data.id : result.data.map(item => item.id).join(',');
1221
+ setTimeout(() => {
1222
+ self.executionCompleted(true, result.data.id ? result.data.processInstanceId : result.data[0].processInstanceId, taskIds, auditResult, self.curTaskId)
1223
+ }, 1000)
1224
+ } else {
1225
+ setTimeout(() => {
1226
+ self.executionCompleted(true, null, null, auditResult, self.curTaskId)
1227
+ }, 1000)
597
1228
  }
598
- self.$Message.success(result.message);
1229
+ } else if (result.code == '10012') {
1230
+ // 数据同步
1231
+ self.loading = false
1232
+ self.disable = false
1233
+ self.$Message.warning(result.message)
1234
+ setTimeout(() => {
1235
+ self.executionCompleted(true, null, null, auditResult, self.curTaskId)
1236
+ }, 1000)
599
1237
  } else if (result.code == '20002') {
600
1238
  // 流程结束
601
1239
  self.loading = false
602
1240
  self.disable = false
603
- callback(true, null, null)
604
1241
  self.$Message.success(result.message)
1242
+ setTimeout(() => {
1243
+ self.executionCompleted(true, '流程已结束', '流程已结束', auditResult, self.curTaskId)
1244
+ }, 1000)
605
1245
  } else {
606
1246
  self.loading = false
607
1247
  self.disable = false
608
- callback(false, null, null)
609
- self.$Message.error(result.message)
1248
+ self.$Message.error(result.message ? result.message : `${self.handleName}失败`)
1249
+ setTimeout(() => {
1250
+ self.executionCompleted(false, null, null, auditResult, self.curTaskId)
1251
+ }, 1000)
610
1252
  }
611
1253
  bus.$emit('triggerTimer')
612
1254
  })
613
-
614
1255
  }
615
1256
  },
616
1257
 
@@ -620,11 +1261,6 @@ export default {
620
1261
  tabsChange(tab) {
621
1262
  console.log(tab)
622
1263
  },
623
- audit: function (auditResult) {
624
- let self = this
625
- self.auditResult = auditResult
626
- self.submit()
627
- },
628
1264
  getAttach(row) {
629
1265
  window.open(this.smartFlowServerContext + "/manage/oss/file/get/" + row.fileId, "_blank");
630
1266
  },
@@ -666,35 +1302,6 @@ export default {
666
1302
  this.imageUrl = url;
667
1303
  this.modalVisible = true;
668
1304
  },
669
- submit() {
670
- let self = this;
671
-
672
- self.auditParams = {
673
- procId: self.procId,
674
- applyId: self.applyId,
675
- taskId: self.taskId,
676
- auditOpinion: self.form.auditOpinion,
677
- fileListStr: JSON.stringify(self.fileList),
678
- auditResult: self.auditResult,
679
- params: JSON.stringify(self.datas),
680
- targetTaskNode: self.targetTaskNode,
681
- selectedUserId: self.selectedUserId,
682
- }
683
- if (self.auditResult == '' || self.auditResult == null) {
684
- self.$Message.error("请选择审批结果!");
685
- return;
686
- }
687
- if (self.form.auditOpinion == '' || self.form.auditOpinion == null) {
688
- if (!self.handleButtons || self.handleButtons.includes('auditOpinion')) {
689
- self.$Message.error("请输入审批意见!")
690
- return;
691
- } else {
692
- self.auditParams.auditOpinion = self.handleButtonsNames[self.auditResult];
693
- }
694
- }
695
-
696
- self.businessFormSave ? self.businessFormSave(self.handleSaveResult) : self.handleSaveResult(true)
697
- },
698
1305
 
699
1306
  //打印流程图信息
700
1307
  processPrint() {
@@ -703,7 +1310,7 @@ export default {
703
1310
  applyId: self.applyId,
704
1311
  instanceId: self.instanceId,
705
1312
  procId: self.procId,
706
- taskId: self.taskId,
1313
+ taskId: self.curTaskId,
707
1314
  }
708
1315
  ajax.get(self.smartFlowServerContext + '/manage/processTodo/getPrintData', {params: params}).then(function (resp) {
709
1316
  let result = resp.data.data
@@ -720,31 +1327,6 @@ export default {
720
1327
  })
721
1328
  },
722
1329
 
723
- pageGoBack() {
724
- bus.$emit('triggerTimer')
725
- window.history.back()
726
- },
727
-
728
- getHisAudit() {
729
- let self = this
730
- let params = {
731
- applyId: self.applyId,
732
- instanceId: self.instanceId,
733
- procId: self.procId,
734
- taskId: self.taskId
735
- }
736
- ajax.get(self.smartFlowServerContext + '/manage/processTodo/getHisAudit', {params: params}).then(function (resp) {
737
- if (resp.data.code === '200') {
738
- self.hisAudit = resp.data.data
739
- let uniqueDataMap = {};
740
- self.hisAudit.forEach((item) => {
741
- uniqueDataMap[item["taskNode"]] = item;
742
- })
743
- self.hisNode = Object.values(uniqueDataMap);
744
-
745
- }
746
- })
747
- },
748
1330
  showTaskNode(taskId) {
749
1331
  if (this.processHistory.length > 0) {
750
1332
  let task = null
@@ -756,70 +1338,10 @@ export default {
756
1338
  }
757
1339
  return ''
758
1340
  },
759
- getProcessHistory() {
760
- let self = this
761
- let params = {
762
- applyId: self.applyId,
763
- instanceId: self.instanceId,
764
- procId: self.procId,
765
- taskId: self.taskId
766
- }
767
- ajax.get(self.smartFlowServerContext + '/manage/processTodo/getProcessHis', {params: params}).then(function (resp) {
768
- if (resp.data.code === '200') {
769
- self.processHistory = resp.data.data
770
- }
771
- })
772
- },
773
1341
  cancel() {
774
1342
  this.modal = false
775
1343
  this.auditResult = '';
776
1344
  },
777
- ok() {
778
- this.modal = false
779
- if (this.targetTaskNode == '' || this.targetTaskNode == null) {
780
- this.auditResult = '';
781
- this.$Message.error("请选择审批节点!");
782
- } else {
783
- let self = this;
784
-
785
- self.auditParams = {
786
- procId: self.procId,
787
- applyId: self.applyId,
788
- taskId: self.taskId,
789
- auditOpinion: self.form.auditOpinion,
790
- fileListStr: JSON.stringify(self.fileList),
791
- auditResult: self.auditResult,
792
- params: JSON.stringify(self.datas),
793
- targetTaskNode: self.targetTaskNode,
794
- selectedUserId: self.selectedUserId,
795
- }
796
- self.loading = true
797
- self.disable = true
798
-
799
- let url = self.smartFlowServerContext + '/manage/processTodo/audit'
800
- ajax.post(url, self.auditParams).then(function (resp) {
801
- let result = resp.data
802
- if (result.code === '200') {
803
- setTimeout(() => {
804
- self.loading = false
805
- self.disable = false
806
- self.$Message.success("审批成功");
807
- if (self.executionCompleted) {
808
- self.executionCompleted(true, result.data.processInstanceId, result.data.id);
809
- }
810
- bus.$emit('triggerTimer')
811
- }, 500)
812
- } else {
813
- self.loading = false
814
- self.disable = false
815
- self.$Message.error(result.message)
816
- if (self.executionCompleted) {
817
- self.executionCompleted(false, null, null);
818
- }
819
- }
820
- })
821
- }
822
- },
823
1345
  selectNode(currentRow, oldCurrentRow) {
824
1346
  let self = this
825
1347
  self.targetTaskNode = currentRow.taskNode
@@ -828,14 +1350,14 @@ export default {
828
1350
  let self = this
829
1351
  let params = {
830
1352
  processDefId: self.procId,
831
- taskId: self.taskId,
1353
+ taskId: self.curTaskId,
832
1354
  }
833
1355
  ajax.get(self.smartFlowServerContext + '/manage/processTodo/getAllPreNodes', {params: params}).then(function (resp) {
834
1356
  if (resp.data.code === '200') {
835
- if (resp.data.data.length > 0){
1357
+ if (resp.data.data.length > 0) {
836
1358
  self.allNode = resp.data.data
837
1359
  self.modal1 = true
838
- }else {
1360
+ } else {
839
1361
  self.$Message.warning('当前流程无前序节点')
840
1362
  }
841
1363
  } else {
@@ -847,14 +1369,14 @@ export default {
847
1369
  let self = this
848
1370
  let params = {
849
1371
  processDefId: self.procId,
850
- taskId: self.taskId,
1372
+ taskId: self.curTaskId,
851
1373
  }
852
1374
  ajax.get(self.smartFlowServerContext + '/manage/processTodo/getNodesBehind', {params: params}).then(function (resp) {
853
1375
  if (resp.data.code === '200') {
854
- if (resp.data.data.length > 0){
1376
+ if (resp.data.data.length > 0) {
855
1377
  self.allNode = resp.data.data
856
1378
  self.modal1 = true
857
- }else {
1379
+ } else {
858
1380
  self.$Message.warning('当前流程无后续节点')
859
1381
  }
860
1382
  } else {
@@ -906,6 +1428,111 @@ export default {
906
1428
  el.style.transform = 'translateX(100%)';
907
1429
  el.addEventListener('transitionend', done);
908
1430
  },
1431
+ uploadFile(file) {
1432
+ const self = this;
1433
+ self.fileList = []
1434
+ file.forEach(item => {
1435
+ self.fileList.push({
1436
+ fileName: item.fileName,
1437
+ fileId: item.fileCode,
1438
+ });
1439
+ })
1440
+ },
1441
+
1442
+ appointOk() {
1443
+ const self = this
1444
+ let oldSettings
1445
+ let params = this.nextNodesFormList.reduce((acc, item) => {
1446
+ acc[item.id] = {
1447
+ needUpdate: 'false',
1448
+ }
1449
+ item.assignee ? acc[item.id].assignee = item.assignee : ''
1450
+ item.candidateGroups ? acc[item.id].candidateGroup = item.candidateGroups : ''
1451
+ let timeLimit = 'expireTime:0D0H;warningTime:0D0H;handleType:00'
1452
+ if(!(item.remainDay === 0 && item.remainTime === 0 && item.inAdvanceDay === 0 && item.inAdvanceTime === 0)) {
1453
+ timeLimit = 'expireTime:' + parseInt(item.remainDay) + "D" + parseInt(item.remainTime) + "H" + ";warningTime:" + parseInt(item.inAdvanceDay) + "D" + parseInt(item.inAdvanceTime) + "H;" + "handleType:" + item.processing;
1454
+ acc[item.id].timeLimit = timeLimit
1455
+ } else {
1456
+ acc[item.id].timeLimit = ''
1457
+ }
1458
+ oldSettings = self.nextNodesOldSettings.filter(oldSetting => oldSetting.id === item.id)[0]
1459
+ if (oldSettings.assignee !== item.assignee || self.checkGroupsUpdate(oldSettings.candidates, item.candidateGroups) || self.checkTimeLimitUpdate(oldSettings.timeLimit, timeLimit)) {
1460
+ acc[item.id].needUpdate = 'true'
1461
+ }
1462
+ return acc;
1463
+ }, {});
1464
+ self.auditParams.nodeConfigMaps = JSON.stringify(params)
1465
+ self.doPass((execResult, instanceId, taskIds, auditResult, curTaskId) => {
1466
+ if (this.executionCompleted) {
1467
+ this.executionCompleted(execResult, instanceId, taskIds, auditResult, curTaskId);
1468
+ }
1469
+ })
1470
+ },
1471
+ checkGroupsUpdate(oldSetting, newSetting) {
1472
+ if (oldSetting && newSetting) {
1473
+ let oldIdList = []
1474
+ for (let [key, value] of Object.entries(oldSetting)) {
1475
+ if (value) {
1476
+ value.split(',').forEach(part => {
1477
+ const [id] = part.split(':');
1478
+ if (id) {
1479
+ oldIdList.push(id);
1480
+ }
1481
+ })
1482
+ }
1483
+ }
1484
+ const regex = /(?:O:|U:|P:|R:|T:)([^,]+)/g;
1485
+ let match;
1486
+ const newIds = [];
1487
+ while ((match = regex.exec(newSetting)) !== null) {
1488
+ newIds.push(...match[1].split(';'))
1489
+ }
1490
+ const allInString = oldIdList.every(item => newIds.includes(item));
1491
+ const hasExtra = newIds.some(item => !oldIdList.includes(item));
1492
+ return !allInString || hasExtra
1493
+ }
1494
+ return false
1495
+ },
1496
+ checkTimeLimitUpdate(oldSetting, newSetting){
1497
+ if (oldSetting && newSetting){
1498
+ return oldSetting !== newSetting
1499
+ }
1500
+ if (!oldSetting){
1501
+ return newSetting !== 'expireTime:0D0H;warningTime:0D0H;handleType:00'
1502
+ }
1503
+ return false
1504
+ },
1505
+ readingRangeClick(item) {
1506
+ let permScope = item.orgTreeType === this.defaultOrganTreeType ? this.permScope : 'all'
1507
+ let orgTreeType = item.orgTreeType ? item.orgTreeType : this.defaultOrganTreeType
1508
+ this.$refs.assigneeHelpBox.toggleShowHelpBox(orgTreeType, permScope, 'transferNextTask', item.id)
1509
+ },
1510
+ candidateGroupsReadingRangeClick(item) {
1511
+ let permScope = item.orgTreeType === this.defaultOrganTreeType ? this.permScope : 'all'
1512
+ let orgTreeType = item.orgTreeType ? item.orgTreeType : this.defaultOrganTreeType
1513
+ this.$refs.candidateGroupsHelpBox.toggleShowHelpBox(permScope, item.candidates, orgTreeType, item.id);
1514
+ },
1515
+ updateCandGroups(newCandGroups, nameStr, detail, nodeId){
1516
+ let oldSettings = this.nextNodesOldSettings.filter(item => item.id === nodeId)[0]
1517
+ if (JSON.stringify(oldSettings.candidates) != JSON.stringify(detail)) {
1518
+ let node = this.nextNodesFormList.filter(item => item.id === nodeId)[0]
1519
+ node.candidateGroups = newCandGroups
1520
+ node.candidateNames = nameStr
1521
+ node.candidates = detail
1522
+ node.needUpdate = true
1523
+ this.$forceUpdate();
1524
+ }
1525
+ },
1526
+ updateNextNodeAssignee(selectedAssigneeId, selectedAssigneeName, nodeId){
1527
+ let oldSettings = this.nextNodesOldSettings.filter(item => item.id === nodeId)[0]
1528
+ if (oldSettings.assignee != selectedAssigneeId) {
1529
+ let node = this.nextNodesFormList.filter(item => item.id === nodeId)[0]
1530
+ node.assignee = selectedAssigneeId
1531
+ node.assigneeName = selectedAssigneeName
1532
+ node.needUpdate = true
1533
+ this.$forceUpdate();
1534
+ }
1535
+ }
909
1536
  },
910
1537
  watch: {
911
1538
  auditOpinionText(label) {
@@ -921,14 +1548,17 @@ export default {
921
1548
 
922
1549
  <style lang="less" scoped>
923
1550
  @import "./styles/css/index.less";
1551
+
924
1552
  /deep/ .ivu-table-row-highlight td {
925
1553
  background-color: #50c1ff !important;
926
1554
  color: #fff !important;
927
1555
  }
928
- /deep/ .ivu-card-body{
1556
+
1557
+ /deep/ .ivu-card-body {
929
1558
  padding: 10px;
930
1559
  }
931
- .page-info /deep/ .page-body{
1560
+
1561
+ .page-info /deep/ .page-body {
932
1562
  overflow-y: hidden;
933
1563
  }
934
1564
  </style>