@lambo-design/workflow-approve 1.0.0-beta.14 → 1.0.0-beta.141

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,552 @@
1
+ <template>
2
+ <div class="process-info-content">
3
+ <a v-if="!isDetail && !auditOpinionOnly" @click="auditShow = !auditShow">
4
+ <Title
5
+ v-if="handleButtons && (handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile'))">
6
+ <a style="color: #989898">
7
+ <Icon v-if="auditShow" type="ios-arrow-down"/>
8
+ <Icon v-if="!auditShow" type="ios-arrow-up"/>
9
+ 办理信息
10
+ </a>
11
+ </Title>
12
+ </a>
13
+ <transition v-if="!isDetail" name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave"
14
+ @leave="leave">
15
+ <div class="box" v-show="auditShow">
16
+ <Form ref="auditOpinion" justify="center" :label-width="100" :model="form"
17
+ v-if="handleButtons && handleButtons.includes('auditOpinion')"
18
+ style="margin: 5px 0 0 10px;" :rules="ruleValidate">
19
+ <FormItem label="办理意见" prop="auditOpinion">
20
+ <AuditOpinion v-model="form.auditOpinion" :audit-opinion-only="auditOpinionOnly" :attachment-file="handleButtons.includes('attachmentFile')"
21
+ :attachmentdata="fileList" :default-audit-opinion="defaultAuditOpinion"
22
+ :smart-flow-server-context="smartFlowServerContext" @handle-file="handleFile"></AuditOpinion>
23
+ </FormItem>
24
+ </Form>
25
+ <Form ref="auditOpinion" justify="center" :label-width="100"
26
+ v-if="handleButtons && !handleButtons.includes('auditOpinion') && handleButtons.includes('attachmentFile')"
27
+ style="margin: 10px 0 0 10px;">
28
+ <FormItem style="min-height: 70px">
29
+ <Tooltip placement="bottom" max-width="200">
30
+ <div style="font-size: smaller" slot="content">支持扩展名:.pdf .doc .docx .txt .xls .xlsx .jpg .jpeg
31
+ .png .gif
32
+ </div>
33
+ <UploadFile @upload-result="uploadFile" :multiple="true"
34
+ :oss-server-context="smartFlowServerContext"
35
+ :oss-file-put-url="ossFilePutUrl"></UploadFile>
36
+ </Tooltip>
37
+ </FormItem>
38
+ </Form>
39
+ </div>
40
+ </transition>
41
+ <a v-if="taskNode && isDetail && hisAuditOpinion[0].auditOpinion" @click="auditShow = !auditShow">
42
+ <Title
43
+ v-if="handleButtons && (handleButtons.includes('auditOpinion') || handleButtons.includes('attachmentFile'))">
44
+ <a style="color: #989898">
45
+ <Icon v-if="auditShow" type="ios-arrow-down"/>
46
+ <Icon v-if="!auditShow" type="ios-arrow-up"/>
47
+ 办理信息
48
+ </a>
49
+ </Title>
50
+ </a>
51
+ <transition v-if="taskNode && isDetail && hisAuditOpinion[0].auditOpinion" name="draw"
52
+ @before-enter="beforeEnter"
53
+ @enter="enter" @before-leave="beforeLeave" @leave="leave">
54
+ <div class="box" v-show="auditShow">
55
+ <Form ref="auditOpinion" justify="center" :model="form"
56
+ v-if="handleButtons && handleButtons.includes('auditOpinion')"
57
+ style="margin: 10px 0 0 10px;" :rules="ruleValidate">
58
+ <FormItem style="margin-left: -60px">
59
+ <Card v-for="(item, index) in hisAuditOpinion" :key="index">
60
+ <Row style="display: flex">
61
+ <Col span="24">
62
+ <div style="word-wrap: break-word;">
63
+ <span>{{ item.auditOpinion }}</span>
64
+ <div style="position: absolute; right: 0;bottom: -18px;color: grey">{{ item.auditTime }}</div>
65
+ </div>
66
+ </Col>
67
+ </Row>
68
+ </Card>
69
+ </FormItem>
70
+ </Form>
71
+ </div>
72
+ </transition>
73
+ <a @click="historyShow = !historyShow">
74
+ <Title v-if="handleButtons && handleButtons.includes('auditHistory')">
75
+ <a style="color: #989898">
76
+ <Icon v-if="historyShow" type="ios-arrow-down"/>
77
+ <Icon v-if="!historyShow" type="ios-arrow-up"/>
78
+ 历史记录
79
+ </a>
80
+ </Title>
81
+ </a>
82
+ <transition name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
83
+ <div class="box" v-show="historyShow">
84
+ <Card class="process-history" :style="processHistoryHeight" dis-hover :bordered="false"
85
+ v-if="handleButtons && handleButtons.includes('auditHistory')">
86
+ <processHistory :portrait-width="processInfoWidth" :list="processHistory" :done-page="isDetail"
87
+ :push-button="pushButton" :history-sort-by="historySortBy"
88
+ :smart-flow-server-context="smartFlowServerContext"></processHistory>
89
+ </Card>
90
+ </div>
91
+ </transition>
92
+ <a @click="attachListShow = !attachListShow">
93
+ <Title v-if="handleButtons && handleButtons.includes('attachmentFile') && attachmentList.length > 0 && attachListShow">
94
+ <a style="color: #989898">
95
+ <Icon v-if="attachListShow" type="ios-arrow-down"/>
96
+ <Icon v-if="!attachListShow" type="ios-arrow-up"/>
97
+ 查看附件
98
+ </a>
99
+ </Title>
100
+ </a>
101
+ <transition v-if="handleButtons && handleButtons.includes('attachmentFile') && attachmentList.length > 0 && attachListShow" name="draw" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
102
+ <div class="box" v-if="!inHorizontal">
103
+ <div v-for="(item, index) in attachmentList" :key="index">
104
+ <Card dis-hover class="attach-card">
105
+ <List item-layout="vertical">
106
+ <ListItem style="margin-top: -8px">
107
+ <Row style="display: flex; align-items: center;">
108
+ <!-- 左边:图片 -->
109
+ <Col span="4" style="margin-top: -25px">
110
+ <avatar v-if="item.fileType === 'image'" icon="ios-image-outline" class="attach-avatar"
111
+ style="background-color: #005aff"
112
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
113
+ :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
114
+ <avatar v-else-if="item.fileType === 'doc'" icon="ios-document-outline" class="attach-avatar"
115
+ style="background-color: #005aff"
116
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
117
+ :size="portraitWidth >= 600 ? 'middle' : 'small'">
118
+ </avatar>
119
+ <avatar v-else-if="item.fileType === 'xlsx'" icon="ios-document-outline" class="attach-avatar"
120
+ style="background-color: #19be6b"
121
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
122
+ :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
123
+ <avatar v-else-if="item.fileType === 'pdf'" icon="ios-document-outline" class="attach-avatar"
124
+ style="background-color: #ed4014"
125
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
126
+ :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
127
+ <avatar v-else icon="ios-document-outline" class="attach-avatar"
128
+ :style="portraitWidth >= 600 ? 'margin-left: 10px' : ''"
129
+ :size="portraitWidth >= 600 ? 'middle' : 'small'"></avatar>
130
+ </Col>
131
+ <!-- 右边:附件信息 -->
132
+ <Col span="20">
133
+ <Row>
134
+ <tooltip>
135
+ <span class="attach-name-style"> {{ item.attachName }}</span>
136
+ <div slot="content" style="white-space: normal"> {{ item.attachName }}</div>
137
+ </tooltip>
138
+ </Row>
139
+ <Row style="margin-top: 3px">
140
+ <span style="color: #005aff; font-size: 13px;">{{ item.uploadUserName }}</span>
141
+ <Divider style="background-color:#808695;height: 1em;margin: 4px 9px 0 6px;"
142
+ type="vertical"/>
143
+ <span style="color: #808695;font-size: 13px"
144
+ >{{ showTaskNode(item.taskId) }}</span>
145
+ </Row>
146
+ <Row style="margin-bottom: -10px; margin-top: 10px">
147
+ <template>
148
+ <Button @click="getAttach(item)" size="small">下载</Button>
149
+ <Button v-if="item.showPreview" ghost type="primary" @click="preViewAttach(item)"
150
+ style="margin-left: 10px" size="small">预览
151
+ </Button>
152
+ </template>
153
+ </Row>
154
+ </Col>
155
+ </Row>
156
+
157
+ </ListItem>
158
+ </List>
159
+ </Card>
160
+ </div>
161
+ </div>
162
+ <div class="box" v-else style="margin: 20px">
163
+ <LamboPagingTable :requestSuccessCodes="requestSuccessCodes" :pageDisable="true" ref="table" :dataUrl="dataUrl" :columns="tableColumn"></LamboPagingTable>
164
+ </div>
165
+ </transition>
166
+ <Modal title="查看附件" v-model="modalVisible" fullscreen scrollable :mask="false">
167
+ <img :src="imageUrl" v-if="modalVisible" alt="" style="width: 100%">
168
+ <div slot="footer">
169
+ <Button type="primary" @click="modalVisible = false">关闭</Button>
170
+ </div>
171
+ </Modal>
172
+ <Modal title="查看附件" v-model="modalDocx" fullscreen scrollable :mask="false">
173
+ <div ref="file"></div>
174
+ </Modal>
175
+ </div>
176
+ </template>
177
+
178
+ <script>
179
+ import ajax from "@lambo-design/shared/utils/ajax";
180
+ import axios from "axios";
181
+ import Title from './title'
182
+ import processHistory from './history'
183
+ import AuditOpinion from './opinion'
184
+ import UploadFile from '@lambo-design/upload-file'
185
+ import {operateBtn} from "@lambo-design/shared/utils/assist";
186
+ import LamboPagingTable from '@lambo-design/paging-table'
187
+ import { WorkflowInfoButtons } from "../utils/const";
188
+
189
+ // 引入docx-preview插件
190
+ let docx = require('docx-preview')
191
+
192
+ export default {
193
+ name: "process-info",
194
+ components: {
195
+ Title,
196
+ processHistory,
197
+ AuditOpinion,
198
+ UploadFile,
199
+ LamboPagingTable,
200
+ },
201
+ props: {
202
+ value: {
203
+ type: String,
204
+ required: false,
205
+ default: ''
206
+ },
207
+ isDetail: {
208
+ type: Boolean,
209
+ required: false,
210
+ default: false
211
+ },
212
+ procId: {
213
+ type: String,
214
+ required: true,
215
+ },
216
+ taskNode: {
217
+ type: String,
218
+ required: true,
219
+ },
220
+ applyId: {
221
+ type: String,
222
+ required: true,
223
+ },
224
+ taskId: {
225
+ type: String,
226
+ required: false,
227
+ default: '',
228
+ },
229
+ // 默认审批意见
230
+ defaultAuditOpinion: {
231
+ type: String,
232
+ required: false,
233
+ default: '',
234
+ },
235
+ //详情页催办按钮
236
+ pushButton: {
237
+ type: Boolean,
238
+ required: false,
239
+ default: true,
240
+ },
241
+ //组件宽度
242
+ portraitWidth: {
243
+ type: Number,
244
+ default: 400
245
+ },
246
+ //是否显示竖向布局
247
+ inHorizontal: {
248
+ type: Boolean,
249
+ default: false
250
+ },
251
+ //审批名称
252
+ handleName: {
253
+ type: String,
254
+ default: '审批',
255
+ },
256
+ //操作按钮
257
+ handleButtons: {
258
+ type: [Array, String],
259
+ default: () => ([])
260
+ },
261
+ //审批历史
262
+ processHistory: {
263
+ type: Array,
264
+ default: () => ([])
265
+ },
266
+ //审批历史默认排序规则
267
+ historySortBy: {
268
+ type: String,
269
+ default: 'time'
270
+ },
271
+ smartFlowServerContext: {
272
+ type: String,
273
+ default: '/api/smart-flow-server',
274
+ },
275
+ },
276
+ data(){
277
+ return{
278
+ auditShow: true,
279
+ historyShow: true,
280
+ attachListShow: true,
281
+ modalVisible: false,
282
+ modalDocx: false,
283
+ imageUrl: '',
284
+ processInfoWidth: 400,
285
+ fileList: [],
286
+ attachmentList: [],
287
+ requestSuccessCodes: [200, "200"],
288
+ dataUrl: this.smartFlowServerContext + '/manage/processDone/getAttachmentList?procId='+this.procId + '&applyId=' + this.applyId,
289
+ form: {
290
+ auditOpinion: '',
291
+ },
292
+ hisAuditOpinion: [{
293
+ auditOpinion: '',
294
+ auditTime: '',
295
+ }],
296
+ ossFilePutUrl: '/manage/oss/file/put',
297
+ ruleValidate: {
298
+ auditOpinion: [{ required: true, trigger: 'blur', message: '意见不能为空' }],
299
+ assignee: [{ required: true, trigger: 'blur', message: '办理人不能为空' }],
300
+ candidateGroups: [{ required: true, trigger: 'blur', message: '候选人不能为空' }],
301
+ },
302
+ }
303
+ },
304
+ computed: {
305
+ auditOpinionOnly(){
306
+ const otherInfoButton = [WorkflowInfoButtons.AttachmentFile, WorkflowInfoButtons.AuditHistory]
307
+ return this.inHorizontal && this.handleButtons && this.handleButtons.includes('auditOpinion') && !otherInfoButton.some(key => this.handleButtons.includes(key))
308
+ },
309
+ processHistoryHeight() {
310
+ if (this.inHorizontal) return ''
311
+ let str = ''
312
+ const hasAuditOpinion = this.taskNode && this.handleButtons && this.handleButtons.includes('auditOpinion')
313
+ const hasAttachmentFile = this.handleButtons && this.handleButtons.includes('auditHistory') && this.attachmentList.length > 0
314
+ const isDetail = this.isDetail && !this.hisAuditOpinion[0].auditOpinion.length > 0
315
+ if (hasAuditOpinion && !hasAttachmentFile && !isDetail) {
316
+ str += 'height: 43vh'
317
+ } else if (hasAuditOpinion && hasAttachmentFile && !isDetail) {
318
+ str += 'height: 40vh'
319
+ } else {
320
+ str += 'height: 67vh'
321
+ }
322
+ return str
323
+ },
324
+ tableColumn() {
325
+ let column = [];
326
+ let self = this;
327
+ column.push({
328
+ title: '序号',
329
+ type: 'index',
330
+ width: 70,
331
+ align: 'center',
332
+ });
333
+ column.push({
334
+ title: '附件名称', key: 'fileName', minWidth: 150, align: 'center',
335
+ render(h, {row}) {
336
+ const index= row.fileName.lastIndexOf(".");
337
+ const fileName=row.fileName.substr(0,index)
338
+ return h("span",fileName)
339
+
340
+ }
341
+ });
342
+ column.push({
343
+ title: '附件类型', width: 100, align: 'center',
344
+ render:(h,{row})=>{
345
+ const index= row.fileName.lastIndexOf(".");
346
+ const fileType=row.fileName.substr(index+1)
347
+ return h("span",fileType)
348
+ }
349
+ });
350
+
351
+ column.push({
352
+ title: "上传人姓名",
353
+ key: "uploadUserName",
354
+ width: 170,
355
+ align: "center",
356
+ });
357
+
358
+ column.push({
359
+ title: "节点名称",
360
+ key: "taskName",
361
+ width: 170,
362
+ align: "center",
363
+ });
364
+
365
+ column.push({
366
+ title: "操作", width: 160, align: 'center', tooltip: true,
367
+ render: (h, {row}) => {
368
+ const index= row.fileName.lastIndexOf(".");
369
+ const fileType=row.fileName.substr(index+1).toLowerCase()
370
+ // const typeList=['jpg','pdf','gif','png','docx']
371
+ //由于pdf预览显示乱码 暂时不提供pdf预览功能
372
+ const typeList=['jpg','gif','png','docx']
373
+ if (typeList.indexOf(fileType)!==-1){
374
+ return h("div", [
375
+ operateBtn(this, h, row, "下载", () => {
376
+ this.getAttach(row);
377
+ }, "primary"),
378
+ operateBtn(this, h, row, "预览", () => {
379
+ this.preViewAttach(row);
380
+ }, "primary")
381
+ ]);
382
+ }else {
383
+ return h("div", [
384
+ operateBtn(this, h, row, "下载", () => {
385
+ this.getAttach(row);
386
+ }, "primary")
387
+ ]);
388
+ }
389
+
390
+ }
391
+
392
+ });
393
+
394
+ return column;
395
+ },
396
+ },
397
+ methods: {
398
+
399
+ imgPreview(url) {
400
+ this.imageUrl = url
401
+ this.modalVisible = true
402
+ },
403
+ preViewAttach(row) {
404
+ let reg = /\.(gif|jpg|jpeg|bmp|png|PNG)$/
405
+ let regs = /\.(pdf)$/
406
+ if (reg.test(row.fileName)) {
407
+ let url = this.smartFlowServerContext + '/manage/oss/file/get/' + row.fileId
408
+ this.imgPreview(url)
409
+ } else if (regs.test(row.fileName)) {
410
+ window.open(this.smartFlowServerContext + '/manage/oss/file/getFileStream?fileId=' + row.fileId, '_blank')
411
+ } else {
412
+ this.modalDocx = true
413
+ axios({
414
+ method: 'get',
415
+ responseType: 'blob', // 因为是流文件,所以要指定blob类型
416
+ url: this.smartFlowServerContext + '/manage/oss/file/get/' + row.fileId// 一个word下载文件的接口
417
+ }).then(({ data }) => {
418
+ docx.renderAsync(data, this.$refs.file, null, {
419
+ className: 'docx', //默认和文档样式类的类名/前缀
420
+ inWrapper: true, //启用围绕文档内容呈现包装器
421
+ ignoreWidth: false, //禁用页面的渲染宽度
422
+ ignoreHeight: false, //禁用页面的渲染高度
423
+ ignoreFonts: false, //禁用字体渲染
424
+ breakPages: true, //在分页符上启用分页
425
+ ignoreLastRenderedPageBreak: true, //在lastRenderedPageBreak元素上禁用分页
426
+ experimental: false, //启用实验功能(制表符停止计算)
427
+ trimXmlDeclaration: true, //如果为true,则在解析之前将从xml文档中删除xml声明
428
+ useBase64URL: false, //如果为true,图像、字体等将转换为base 64 URL,否则使用URL.createObjectURL
429
+ useMathMLPolyfill: false, //包括用于铬、边等的MathML多填充。
430
+ showChanges: false, //启用文档更改的实验渲染(插入/删除)
431
+ debug: false, //启用额外的日志记录
432
+ })
433
+ }
434
+ )
435
+ }
436
+ },
437
+ getAttach(row) {
438
+ window.open(this.smartFlowServerContext + '/manage/oss/file/get/' + row.fileId, '_blank')
439
+ },
440
+ showTaskNode(taskId) {
441
+ if (this.processHistory.length > 0) {
442
+ let task = null
443
+ this.processHistory.some(itemList => {
444
+ task = itemList.find(item => item.taskId === taskId)
445
+ return task !== undefined
446
+ })
447
+ return task ? task.taskName : ''
448
+ }
449
+ return ''
450
+ },
451
+ getAttachList(taskId) {
452
+ const self = this
453
+ const param = {
454
+ taskId: taskId,
455
+ procId: this.procId,
456
+ applyId: this.applyId
457
+ }
458
+ ajax.get(self.smartFlowServerContext + '/manage/processDone/getAttachmentList', { params: param }).then(function (resp) {
459
+ self.attachmentList = resp.data.data.rows
460
+ self.attachmentList.forEach(item => {
461
+ const index = item.fileName.lastIndexOf('.')
462
+ const fileType = item.fileName.substr(index + 1).toLowerCase()
463
+ const imageList = ['jpg', 'gif', 'png', 'svg']
464
+ const docList = ['doc', 'docx']
465
+ const zipList = ['rar', 'zip']
466
+ const typeList = ['jpg', 'gif', 'png', 'docx']
467
+ item.fileType = imageList.indexOf(fileType) !== -1 ? 'image' : docList.indexOf(fileType) !== -1 ? 'doc' : zipList.indexOf(fileType) !== -1 ? 'zip' : fileType
468
+ item.showPreview = typeList.indexOf(fileType) !== -1
469
+ })
470
+ }).catch(err => {
471
+ console.log(err)
472
+ })
473
+ },
474
+ uploadFile(file) {
475
+ const self = this
476
+ self.fileList = []
477
+ file.forEach(item => {
478
+ self.fileList.push({
479
+ fileName: item.fileName,
480
+ fileId: item.fileCode,
481
+ })
482
+ })
483
+ this.$emit('upload-file', self.fileList)
484
+ },
485
+ handleFile(file){
486
+ this.$emit('upload-file', file)
487
+ },
488
+
489
+ //折叠动画效果
490
+ beforeEnter(el) {
491
+ el.style.height = '0'
492
+ },
493
+ enter(el, done) {
494
+ setTimeout(() => {
495
+ el.style.height = el.scrollHeight + 'px'
496
+ }, 0)
497
+
498
+ el.addEventListener('transitionend', done)
499
+ },
500
+ beforeLeave(el) {
501
+ el.style.height = el.scrollHeight + 'px'
502
+ },
503
+ leave(el, done) {
504
+ setTimeout(() => {
505
+ el.style.height = '0'
506
+ }, 0)
507
+
508
+ el.addEventListener('transitionend', done)
509
+ },
510
+
511
+ beforeFlowInfoEnter(el) {
512
+ el.style.transform = 'translateX(100%)'
513
+ },
514
+ flowInfoEnter(el, done) {
515
+ const transitionDuration = 0.5
516
+ el.style.transition = `transform ${transitionDuration}s`
517
+ el.style.transform = 'translateX(0)'
518
+ el.addEventListener('transitionend', done)
519
+ },
520
+ beforeFlowInfoLeave(el) {
521
+ el.style.transform = 'translateX(0)'
522
+ },
523
+ flowInfoLeave(el, done) {
524
+ const transitionDuration = 0.5
525
+ el.style.transition = `transform ${transitionDuration}s`
526
+ el.style.transform = 'translateX(100%)'
527
+ el.addEventListener('transitionend', done)
528
+ },
529
+ },
530
+ mounted() {
531
+ this.getAttachList(this.taskId)
532
+ this.processInfoWidth = this.inHorizontal ? 1000 : this.portraitWidth
533
+ this.form.auditOpinion = this.value;
534
+ },
535
+ watch: {
536
+ 'form.auditOpinion'(val) {
537
+ this.$emit('input', val)
538
+ },
539
+ value(newVal) {
540
+ this.form.auditOpinion = newVal;
541
+ },
542
+ defaultAuditOpinion(val) {
543
+ this.auditOpinion = this.defaultAuditOpinion
544
+ this.$emit('input', val)
545
+ }
546
+ }
547
+ }
548
+ </script>
549
+
550
+ <style scoped>
551
+
552
+ </style>