vue2-client 1.2.16 → 1.2.19

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.
@@ -1,838 +1,837 @@
1
- <template>
2
- <a-drawer
3
- title="工单详情"
4
- placement="right"
5
- :width="isMobile ? screenWidth : screenWidth * 0.85"
6
- :visible="visible"
7
- @close="onClose"
8
- >
9
- <!-- 移交工单对话框 -->
10
- <a-modal
11
- title="移交工单"
12
- :visible="transVisible"
13
- @ok="handleTransferOk"
14
- @cancel="handleTransferCancel"
15
- :zIndex="1001"
16
- >
17
- <a-input placeholder="请输入要转移工单的员工名" v-model="transferTo" @blur="checkEmp" @change="inputChange"/>
18
- <div class="nameOptions" v-show="nameOptionsVisible">
19
- <p class="nameOptionsItem" v-for="(item,index) in nameOptionsForChoose" :key="index" @click="chooseName(item.name)">{{ item.name }}</p>
20
- </div>
21
- <span v-if="!transferCheck" style="color: red">您输入的员工不存在,请检查后再试</span>
22
- <span v-else style="color: green">您输入的员工已确认,可以进行工单转移</span>
23
- <a-form-model-item label="留言">
24
- <a-input v-model="note" type="textarea" />
25
- </a-form-model-item>
26
- <div class="clearfix">
27
- <a-upload
28
- name="avatar"
29
- list-type="picture-card"
30
- :before-upload="beforeUpload"
31
- action="/webmeteruploadapi/upload"
32
- :file-list="fileList"
33
- @preview="handlePreview"
34
- @change="handleChange"
35
- :remove="remove"
36
- >
37
- <div v-if="fileList.length < 5">
38
- <a-icon type="plus" />
39
- <div class="ant-upload-text">点击上传</div>
40
- </div>
41
- </a-upload>
42
- <a-modal
43
- :visible="previewVisible"
44
- :footer="null"
45
- @cancel="handleCancel"
46
- >
47
- <img style="width: 100%" :src="previewImage" alt="图片上传"/>
48
- </a-modal>
49
- </div>
50
- </a-modal>
51
- <!-- 关闭工单确认框 -->
52
- <a-modal
53
- title="关闭工单"
54
- :visible="closeVisible"
55
- @ok="handleCloseOk"
56
- @cancel="handleCloseCancel"
57
- :zIndex="1002"
58
- >
59
- <p>是否确认手动关闭工单?</p>
60
- <p style="color: red">(该操作不可撤销,请谨慎操作!)</p>
61
- </a-modal>
62
- <!-- 信息主体 -->
63
- <a-spin :spinning="loadTicketDetails">
64
- <a-page-header :title="'订单:' + this.details.serial_number">
65
- <div class="row">
66
- <div class="content">
67
- <a-descriptions size="small" :column="isMobile ? 1 : 2">
68
- <a-descriptions-item label="优先级">
69
- <a-alert
70
- :type="showPriorityColorControl()"
71
- :message="showPriority()"
72
- :show-icon="true"/>
73
- </a-descriptions-item>
74
- <a-descriptions-item label="发起人">{{ details.uploader }}</a-descriptions-item>
75
- <a-descriptions-item label="问题类型">{{ details.category }}</a-descriptions-item>
76
- <a-descriptions-item label="发起人联系方式">{{ details.uploader_phone }}</a-descriptions-item>
77
- </a-descriptions>
78
- </div>
79
- </div>
80
- <!-- 按钮 -->
81
- <template v-slot:extra>
82
- <a-button-group style="margin-right: 4px;">
83
- <a-popover title="开始处理" placement="bottomLeft">
84
- <template slot="content">
85
- <p>开始处理当前工单</p>
86
- </template>
87
- <a-button type="primary" @click="confirmTicketBtn()" :disabled="handlerBtnDisable()">开始处理</a-button>
88
- </a-popover>
89
- <a-popover title="移交他人" placement="bottomLeft">
90
- <template slot="content">
91
- <p>将工单转交他人处理</p>
92
- </template>
93
- <a-button type="primary" @click="transferBtn()" :disabled="transferBtnDisable()">移交他人</a-button>
94
- </a-popover>
95
- <a-popover title="关闭工单" placement="bottomLeft">
96
- <template slot="content">
97
- <p>强制关闭当前工单</p>
98
- <p style="color: red">此操作不可撤销,请谨慎使用</p>
99
- </template>
100
- <a-button type="danger" @click="closeBtn()" :disabled="closeBtnDisable()">关闭工单</a-button>
101
- </a-popover>
102
- </a-button-group>
103
- <a-button-group style="margin-right: 4px;">
104
- <a-button type="dashed" @click="initView" :loading="showSpin">刷新({{ btnCountdownText }})</a-button>
105
- </a-button-group>
106
- </template>
107
- <!-- 进度条 -->
108
- <a-card :bordered="false" style="margin-top: 40px">
109
- <a-steps :direction="'horizontal'" :current="step">
110
- <a-step>
111
- <template v-slot:title><span>待处理</span></template>
112
- <template v-slot:description>
113
- <div>工单已提交,等待处理<div>{{ format(details.created_time,'yyyy-MM-dd hh:mm:ss') }}</div></div>
114
- </template>
115
- </a-step>
116
- <a-step>
117
- <template v-slot:title><span>处理中</span></template>
118
- <template v-slot:description>
119
- <div v-if="step >= 1"><strong>{{ details.name }}</strong> 处理中...<div>{{ format(details.confirm_time,'yyyy-MM-dd hh:mm:ss') }}</div></div>
120
- </template>
121
- </a-step>
122
- <a-step>
123
- <template v-slot:title><span>{{ getStatus() }}</span></template>
124
- <template v-slot:description>
125
- <div v-if="step >= 2">{{ format(details.finished_time,'yyyy-MM-dd hh:mm:ss') }}</div>
126
- </template>
127
- </a-step>
128
- </a-steps>
129
- </a-card>
130
- <!-- 切换栏 -->
131
- <a-tabs style="margin-top: 50px;">
132
- <!-- 问题描述 -->
133
- <a-tab-pane :key="1" tab="问题详细描述">
134
- <a-card style="width: 100%" :loading="descriptionLoading">
135
- <span style="font-size: 2em;margin-right: 20px">{{ details.uploader }}</span>
136
- <span>{{ format(details.created_time,'yyyy年MM月dd日 hh:mm:ss') }}</span>
137
- <p style="text-indent: 2em;font-size: 20px;margin: 10px">{{ details.description }}</p>
138
- <img
139
- v-for="(originalPic,n) in originalImages"
140
- :src="'data:image/png;base64,' + originalPic.url"
141
- @click="changePhotoClass(originalPic.id)"
142
- :key="'os' + n"
143
- :class="changePhotoClassForSmall(originalPic.id)"
144
- style="margin-bottom: 10px"
145
- >
146
- <div style="margin-bottom: 10px;height: 1px;background: -webkit-linear-gradient(left, #fff -4%,#6b6c72 50%,#fff 100%);"></div>
147
- <div v-if="addOnDescription.length > 0" v-for="(item,index) in addOnDescription" :key="index">
148
- <span style="font-size: 2em;margin-right: 20px;margin-top: 20px">{{ details.uploader }}</span>
149
- <span>{{ format(item.time,'yyyy年MM月dd日 hh:mm:ss') }}</span>
150
- <p style="text-indent: 2em;font-size: 20px;margin: 20px">{{ item.description }}</p>
151
- <img
152
- v-for="(pic,m) in item.images"
153
- :src="'data:image/png;base64,' + pic.url"
154
- @click="changePhotoClass(pic.id)"
155
- :key="'is' + m"
156
- :class="changePhotoClassForSmall(pic.id)"
157
- >
158
- <div style="height: 1px;background: -webkit-linear-gradient(left, #fff -4%,#6b6c72 50%,#fff 100%);"></div>
159
- </div>
160
- </a-card>
161
- </a-tab-pane>
162
- <!-- 工单流转历史 -->
163
- <a-tab-pane :key="2" tab="工单流转历史">
164
- <ticket-details-flow
165
- @imageClick="flowImageClick"
166
- v-if="details.id"
167
- :ticketId="ticketId"
168
- :disableCloseBtn="disableCloseBtn"
169
- :id="details.id"/>
170
- </a-tab-pane>
171
- </a-tabs>
172
- </a-page-header>
173
- </a-spin>
174
- <audio controls="controls" hidden src="@/assets/sound/newNote.mp3" ref="audio"></audio>
175
- <!-- 放大后图片 -->
176
- <div class="imgBackground" v-if="selectedImageShow" @click="changePhotoClass(selectedImage.id)">
177
- <img
178
- :src="'data:image/png;base64,' + selectedImage.url"
179
- class="img_xl">
180
- </div>
181
- </a-drawer>
182
- </template>
183
-
184
- <script>
185
- import JsonViewer from 'vue-json-viewer'
186
- import { formatDate } from '@vue2-client/utils/util'
187
- import { TicketDetailsViewApi } from '@vue2-client/services/api/TicketDetailsViewApi'
188
- import { EmployeeDetailsViewApi } from '@vue2-client/services/api/EmployeeDetailsViewApi'
189
- import { post } from '@vue2-client/services/api/restTools'
190
- import XTable from '@vue2-client/base-client/components/common/XTable/XTable'
191
- import { mapState } from 'vuex'
192
- import TicketDetailsFlow from './part/TicketDetailsFlow'
193
- import moment from 'moment'
194
-
195
- function getBase64 (file) {
196
- return new Promise((resolve, reject) => {
197
- const reader = new FileReader()
198
- reader.readAsDataURL(file)
199
- reader.onload = () => resolve(reader.result)
200
- reader.onerror = error => reject(error)
201
- })
202
- }
203
-
204
- export default {
205
- name: 'TicketDetailsView',
206
- components: {
207
- TicketDetailsFlow,
208
- JsonViewer,
209
- XTable
210
- },
211
- data () {
212
- return {
213
- moment,
214
- // 页面宽度
215
- screenWidth: document.documentElement.clientWidth,
216
- // 控制成功页面显示
217
- successVisible: false,
218
- // 控制预览显示
219
- previewVisible: false,
220
- // 图片真实地址
221
- previewImage: '',
222
- // 图片列表
223
- fileList: [],
224
- // 工单详情
225
- details: {
226
- // 当前负责人ID
227
- id: undefined,
228
- name: '',
229
- uploader: '',
230
- status: undefined,
231
- priority: undefined,
232
- description: '',
233
- created_time: '',
234
- confirm_time: '',
235
- finished_time: '',
236
- category: '',
237
- serial_number: '',
238
- uploader_phone: ''
239
- },
240
- images: [],
241
- selectedImage: null,
242
- selectedImageShow: false,
243
- // 当前步骤
244
- step: 0,
245
- // 校验转移员工是否存在
246
- transferCheck: false,
247
- // 移交工单窗口可见性
248
- transVisible: false,
249
- // 转移工单对象
250
- transferTo: '',
251
- // 新增留言
252
- note: '',
253
- // 控制关闭订单按钮可用性
254
- disableCloseBtn: false,
255
- // 控制关闭工单确认框显示
256
- closeVisible: false,
257
- // 控制加载过程
258
- loadTicketDetails: false,
259
- // 附加描述
260
- addOnDescription: [],
261
- // 上传工单时自带照片
262
- originalImages: [],
263
- // 定时刷新定时器
264
- timer: undefined,
265
- // 所有员工姓名
266
- nameOptions: [],
267
- // 员工姓名备选
268
- nameOptionsForChoose: [],
269
- // 员工姓名备选项显示控制
270
- nameOptionsVisible: false,
271
- // 工单流转抽屉可见性
272
- workFlowVisible: false,
273
- // 控制小加载指示物显示
274
- showSpin: true,
275
- // 原始描述长度
276
- addOnDescriptionOriginal: undefined,
277
- // 描述加载控制
278
- descriptionLoading: false,
279
- // 用于刷新按钮倒计时显示
280
- btnCountdownText: 5
281
- }
282
- },
283
- mounted () {
284
- this.initView()
285
- },
286
- computed: {
287
- ...mapState('account', { currUser: 'user' }),
288
- ...mapState('setting', ['isMobile'])
289
- },
290
- props: {
291
- ticketId: {
292
- type: String,
293
- required: true
294
- },
295
- visible: {
296
- type: Boolean,
297
- default: false
298
- }
299
- },
300
- methods: {
301
- // 转移员工姓名change事件,用于展示备选
302
- inputChange () {
303
- if (this.transferTo.length === 0) {
304
- this.nameOptionsVisible = false
305
- } else {
306
- this.nameOptionsVisible = true
307
- var inputName = this.transferTo
308
- this.nameOptionsForChoose = this.nameOptions.filter(function (element) {
309
- return element.name.indexOf(inputName) !== -1
310
- })
311
- }
312
- },
313
- // 在候选框中点击了名称
314
- chooseName (name) {
315
- this.nameOptionsVisible = false
316
- this.transferTo = name
317
- this.checkEmp()
318
- },
319
- // 获取所有员工名,供输入框备选
320
- getAllEmpNames () {
321
- return post(EmployeeDetailsViewApi.getAllEmployeeName, null)
322
- .then(res => {
323
- this.nameOptions = res
324
- }, err => {
325
- console.log(err)
326
- })
327
- },
328
- // 图像修改检测
329
- handleChange ({ fileList }) {
330
- this.fileList = fileList.filter((item) => {
331
- return item.status === 'done' || item.status === 'uploading'
332
- })
333
- },
334
- // 在上传页面,点击图片上的垃圾桶,撤销上传
335
- remove (file) {
336
- return post(TicketDetailsViewApi.revocationImage, {
337
- file: file
338
- })
339
- .then(res => {
340
- if (res === 'success') {
341
- this.$message.success('删除成功')
342
- }
343
- this.fileList = this.fileList.filter((item) => {
344
- return item.response.name !== file.response.name
345
- })
346
- }, err => {
347
- console.log(err)
348
- })
349
- },
350
- // 上传头像前校验
351
- beforeUpload (file) {
352
- const isJpgOrPng =
353
- file.type === 'image/jpeg' ||
354
- file.type === 'image/jpg' ||
355
- file.type === 'image/png'
356
- const Lt2M = file.size / 1024 / 1024 < 2
357
- if (!Lt2M) {
358
- this.$message.error('图片不得大于2MB!')
359
- }
360
- if (!isJpgOrPng) {
361
- this.$message.error('只能上传jpg/png格式的图片')
362
- }
363
- return isJpgOrPng && Lt2M
364
- },
365
- handleCancel () {
366
- this.previewVisible = false
367
- },
368
- // 处理预览图像
369
- async handlePreview (file) {
370
- if (!file.url && !file.preview) {
371
- file.preview = await getBase64(file.originFileObj)
372
- }
373
- this.previewImage = file.url || file.preview
374
- this.previewVisible = true
375
- },
376
- // 开启定时器
377
- setTimer () {
378
- if (this.timer === undefined) {
379
- this.timer = setInterval(() => {
380
- if (this.btnCountdownText > 0) {
381
- this.btnCountdownText--
382
- if (this.btnCountdownText === 0) {
383
- this.initView()
384
- this.btnCountdownText = 5
385
- }
386
- }
387
- }, 1000)
388
- }
389
- },
390
- // 初始化组件
391
- initView () {
392
- this.showSpin = true
393
- this.descriptionLoading = true
394
- // 获取所有员工名
395
- this.getAllEmpNames()
396
- // 获取工单的基本详情
397
- this.getTicketDetail(this.ticketId)
398
- // 获取工单的附加信息
399
- this.handleOtherData()
400
- },
401
- // 图像点击切换放大缩小
402
- changePhotoClass (id) {
403
- for (let i = 0; i < this.images.length; i++) {
404
- if (id === this.images[i].id) {
405
- this.images[i].isLarge = !this.images[i].isLarge
406
- this.selectedImage = this.images[i]
407
- }
408
- }
409
- this.selectedImageShow = !this.selectedImageShow
410
- },
411
- // 控制未放大图像变暗
412
- changePhotoClassForSmall (id) {
413
- for (let i = 0; i < this.images.length; i++) {
414
- if (id == this.images[i].id) {
415
- if (this.images[i].isLarge === true) {
416
- return 'img_sm_dark'
417
- } else {
418
- return 'img_sm'
419
- }
420
- }
421
- }
422
- },
423
- // 获取当前相关联的照片
424
- getPhoto () {
425
- return post(TicketDetailsViewApi.getTicketImages, {
426
- ticketId: this.ticketId
427
- })
428
- .then(res => {
429
- this.images = res
430
- for (let i = 0; i < this.images.length; i++) {
431
- this.images[i].isLarge = false
432
- }
433
- this.mergeAddImage()
434
- }, err => {
435
- console.log(err)
436
- })
437
- },
438
- // 将同一次上传的图片,与描述放在一起
439
- mergeAddImage () {
440
- this.originalImages = []
441
- for (let i = 0; i < this.addOnDescription.length; i++) {
442
- this.addOnDescription[i].images = []
443
- }
444
- for (let i = 0; i < this.images.length; i++) {
445
- if (this.images[i].did === 0) {
446
- this.originalImages.push(this.images[i])
447
- continue
448
- }
449
- for (let j = 0; j < this.addOnDescription.length; j++) {
450
- if (this.images[i].did === this.addOnDescription[j].id) {
451
- this.addOnDescription[j].images.push(this.images[i])
452
- }
453
- }
454
- }
455
- this.initDone()
456
- },
457
- initDone () {
458
- // 初始化信息
459
- this.showSpin = false
460
- this.descriptionLoading = false
461
- if (this.step !== 3) {
462
- this.setTimer()
463
- }
464
- this.addOnDescriptionOriginal = 1
465
- },
466
- // 关闭工单确认后业务逻辑
467
- handleCloseOk () {
468
- return post(TicketDetailsViewApi.manualCloseTicket, {
469
- ticketId: this.ticketId,
470
- time: new Date()
471
- })
472
- .then(res => {
473
- if (res !== 0) {
474
- this.$message.success(
475
- '操作成功',
476
- 5
477
- )
478
- this.initView()
479
- this.closeVisible = false
480
- } else {
481
- this.$message.error(
482
- '操作失败',
483
- 5
484
- )
485
- }
486
- }, err => {
487
- console.error(err)
488
- })
489
- },
490
- // 关闭工单取消后业务逻辑
491
- handleCloseCancel () {
492
- this.closeVisible = false
493
- },
494
- // 确认工单按钮业务逻辑
495
- confirmTicketBtn () {
496
- const currentEmpId = this.getCurrentEmpId()
497
- return post(TicketDetailsViewApi.confirmTicket, {
498
- ticketId: this.ticketId,
499
- empId: currentEmpId,
500
- time: new Date()
501
- })
502
- .then(res => {
503
- if (res !== 0) {
504
- this.$message.success('操作成功', 5)
505
- } else {
506
- this.$message.error('工单已被他人处理或关闭,请刷新再试', 5)
507
- }
508
- this.initView()
509
- }, err => {
510
- console.error(err)
511
- this.$message.error('工单已被他人处理,请刷新再试', 5)
512
- this.initView()
513
- })
514
- },
515
- // 获取当前登陆员工ID
516
- getCurrentEmpId () {
517
- return this.currUser.id
518
- },
519
- // 转移工单按钮业务逻辑
520
- transferBtn () {
521
- this.transVisible = true
522
- },
523
- checkEmp () {
524
- return post(EmployeeDetailsViewApi.findEmpName, {
525
- empName: this.transferTo
526
- })
527
- .then(res => {
528
- const num = res
529
- this.transferCheck = num !== 0
530
- }, err => {
531
- console.error(err)
532
- })
533
- },
534
- // 获取工单状态撤销or关闭
535
- getStatus () {
536
- if (this.details.status === 2) {
537
- return '已撤销'
538
- } else {
539
- return '已关闭'
540
- }
541
- },
542
- // 关闭工单按钮业务逻辑
543
- closeBtn () {
544
- this.closeVisible = true
545
- },
546
- // 转移工单确认后逻辑
547
- handleTransferOk () {
548
- if (!this.transferCheck) {
549
- this.$message.error(
550
- '请先检查您输入的员工名',
551
- 2
552
- )
553
- } else {
554
- return post(TicketDetailsViewApi.transferTicketToOthers, {
555
- ticketId: this.ticketId,
556
- endTime: new Date(),
557
- transferTo: this.transferTo,
558
- note: this.note,
559
- images: this.fileList
560
- })
561
- .then(res => {
562
- const result = res
563
- this.note = ''
564
- this.transVisible = false
565
- if (result === 1) {
566
- this.$message.success(
567
- '操作成功',
568
- 5
569
- )
570
- this.fileList = []
571
- this.transferTo = ''
572
- this.transferCheck = false
573
- this.initView()
574
- } else {
575
- this.$message.error('工单已被他人处理或关闭,请刷新再试', 5)
576
- }
577
- this.handleCancel()
578
- this.initView()
579
- }, err => {
580
- console.error(err)
581
- this.transVisible = false
582
- })
583
- }
584
- },
585
- // 转移工单取消后逻辑
586
- handleTransferCancel () {
587
- this.transVisible = false
588
- this.transferCheck = false
589
- this.transferTo = ''
590
- this.note = ''
591
- },
592
- // 关闭抽屉时回调
593
- onClose () {
594
- clearInterval(this.timer)
595
- this.timer = undefined
596
- this.addOnDescription = []
597
- this.disableCloseBtn = false
598
- this.$emit('update:visible', false)
599
- this.originalImages = []
600
- this.images = []
601
- this.addOnDescriptionOriginal = undefined
602
- },
603
- // 对其他信息进行初始化,包括附加描述,图片
604
- handleOtherData () {
605
- const beforeLength = this.addOnDescription.length
606
- return post(TicketDetailsViewApi.getAddonDescription, {
607
- ticketId: this.ticketId
608
- })
609
- .then(res => {
610
- this.addOnDescription = res
611
- this.getPhoto()
612
- if (this.addOnDescription.length > beforeLength && this.addOnDescriptionOriginal !== undefined) {
613
- this.addOnDescriptionOriginal = 1
614
- this.$refs.audio.currentTime = 0
615
- this.$refs.audio.play()
616
- this.$notification.open({
617
- message: '最新通知',
618
- description:
619
- '客户追加了问题描述,请及时查看!',
620
- onClick: () => {
621
- }
622
- })
623
- }
624
- }, err => {
625
- console.log(err)
626
- })
627
- },
628
- // 获取工单详情信息
629
- getTicketDetail (num) {
630
- this.showSpin = true
631
- return post(TicketDetailsViewApi.getTicketDetails, {
632
- ticketId: num
633
- }).then(res => {
634
- this.details = res[0]
635
- this.step = res[0].status
636
- if (this.details.status === 3) {
637
- this.disableCloseBtn = true
638
- }
639
- const categoryValue = this.details.category
640
- this.details.category = this.$appdata.getDictionaryList('ticketCategoryMap')[categoryValue].label
641
- }, err => {
642
- console.error(err)
643
- })
644
- },
645
- // 日期格式化
646
- format (date, format) {
647
- return formatDate(date, format)
648
- },
649
- // 转换JSON
650
- toJSON (value) {
651
- try {
652
- return JSON.parse(value)
653
- } catch (e) {
654
- return value
655
- }
656
- },
657
- // 控制开始处理按钮可用状态
658
- handlerBtnDisable () {
659
- return this.step !== 0
660
- },
661
- // 控制移交他人按钮可用状态
662
- transferBtnDisable () {
663
- return this.step === 0 || this.step === 3
664
- },
665
- // 控制关闭工单按钮可用状态
666
- closeBtnDisable () {
667
- return this.step === 0 || this.disableCloseBtn || this.details.id != this.currUser.id
668
- },
669
- // 优先级文字显示
670
- showPriority () {
671
- if (this.details.priority === 2) {
672
- return '一般'
673
- } else if (this.details.priority === 1) {
674
- return '紧急'
675
- } else {
676
- return '非常紧急'
677
- }
678
- },
679
- // 优先度颜色控制
680
- showPriorityColorControl () {
681
- if (this.details.priority === 2) {
682
- return 'info'
683
- } else if (this.details.priority === 1) {
684
- return 'warning'
685
- } else {
686
- return 'error'
687
- }
688
- },
689
- // 单击工单流转历史图片
690
- flowImageClick (image) {
691
- this.selectedImage = image
692
- this.selectedImageShow = !this.selectedImageShow
693
- }
694
- },
695
- watch: {
696
- 'visible' (val) {
697
- if (val) {
698
- this.initView()
699
- }
700
- },
701
- 'step' (newVal) {
702
- if (newVal === 3) {
703
- clearInterval(this.timer)
704
- }
705
- }
706
- }
707
- }
708
- </script>
709
-
710
- <style lang="less" scoped>
711
- .high-priority{
712
- background-color: rgba(163, 30, 30, 0.66);
713
- border: red solid 1px;
714
- font-size: large;
715
- padding: 5px;
716
- color: white;
717
- border-radius: 10px;
718
- }
719
-
720
- .detail-layout {
721
- margin-left: 44px;
722
- }
723
- .text {
724
- color: rgba(0, 0, 0, .45);
725
- }
726
-
727
- .heading {
728
- color: rgba(0, 0, 0, .85);
729
- font-size: 20px;
730
- }
731
-
732
- .no-data {
733
- color: rgba(0, 0, 0, .25);
734
- text-align: center;
735
- line-height: 64px;
736
- font-size: 16px;
737
-
738
- i {
739
- font-size: 24px;
740
- margin-right: 16px;
741
- position: relative;
742
- top: 3px;
743
- }
744
- }
745
-
746
- .mobile {
747
- .detail-layout {
748
- margin-left: unset;
749
- }
750
- .text {
751
-
752
- }
753
- .status-list {
754
- text-align: left;
755
- }
756
- }
757
-
758
- .row {
759
- display: flex;
760
-
761
- .content {
762
- -webkit-box-flex: 1;
763
- flex: auto;
764
- -ms-flex: auto;
765
- }
766
-
767
- .extra {
768
- flex: 0 1 auto;
769
- -webkit-box-flex: 0;
770
- -ms-flex: 0 1 auto;
771
- min-width: 242px;
772
- margin-left: 88px;
773
- text-align: right;
774
- }
775
- }
776
-
777
- .img_sm {
778
- border: rgba(84, 84, 84, 0.2) solid 1.5px;
779
- border-radius: 5px;
780
- padding: 10px;
781
- width: 160px;
782
- height: 120px;
783
- margin-bottom: 20px;
784
- margin-left: 20px;
785
- }
786
- .img_xl {
787
- position: absolute;
788
- top:0;bottom:0;left:0;right:0;
789
- margin: auto;
790
- width: 60%;
791
- max-width: 1000px;
792
- cursor: zoom-out;
793
- z-index: 9999;
794
- animation: imgZoomIn 0.4s;
795
- -webkit-animation: imgZoomIn 0.4s;
796
- }
797
- @keyframes imgZoomIn
798
- {
799
- from {width: 160px;}
800
- to {width: 60%;}
801
- }
802
- .img_sm:hover {
803
- opacity: 0.6;
804
- cursor: zoom-in;
805
- }
806
- .img_sm_dark{
807
- filter: grayscale(100%);
808
- opacity: 0.6;
809
- border: rgba(84, 84, 84, 0.2) solid 1.5px;
810
- border-radius: 5px;
811
- padding: 10px;
812
- width: 160px;
813
- height: 120px;
814
- margin-bottom: 20px;
815
- margin-left: 20px;
816
- }
817
- .imgBackground {
818
- position: absolute;
819
- top:0;bottom:0;left:0;right:0;
820
- width: 100%;
821
- height: 100%;
822
- z-index: 9998;
823
- background-color: rgba(0,0,0,0.7);
824
- }
825
- .nameOptionsItem {
826
- padding-left: 5px;
827
- margin-bottom: 2px;
828
- }
829
- .nameOptionsItem:hover {
830
- background-color: rgb(209,233,255);
831
- }
832
- .nameOptionsItem:last-of-type {
833
- margin-bottom: 0px;
834
- }
835
- .nameOptions {
836
- border: rgba(0,0,0,0.4) solid 1px;
837
- }
838
- </style>
1
+ <template>
2
+ <a-drawer
3
+ title="工单详情"
4
+ placement="right"
5
+ :width="isMobile ? screenWidth : screenWidth * 0.85"
6
+ :visible="visible"
7
+ @close="onClose"
8
+ >
9
+ <!-- 移交工单对话框 -->
10
+ <a-modal
11
+ title="移交工单"
12
+ :visible="transVisible"
13
+ @ok="handleTransferOk"
14
+ @cancel="handleTransferCancel"
15
+ :zIndex="1001"
16
+ >
17
+ <a-input placeholder="请输入要转移工单的员工名" v-model="transferTo" @blur="checkEmp" @change="inputChange"/>
18
+ <div class="nameOptions" v-show="nameOptionsVisible">
19
+ <p class="nameOptionsItem" v-for="(item,index) in nameOptionsForChoose" :key="index" @click="chooseName(item.name)">{{ item.name }}</p>
20
+ </div>
21
+ <span v-if="!transferCheck" style="color: red">您输入的员工不存在,请检查后再试</span>
22
+ <span v-else style="color: green">您输入的员工已确认,可以进行工单转移</span>
23
+ <a-form-model-item label="留言">
24
+ <a-input v-model="note" type="textarea" />
25
+ </a-form-model-item>
26
+ <div class="clearfix">
27
+ <a-upload
28
+ name="avatar"
29
+ list-type="picture-card"
30
+ :before-upload="beforeUpload"
31
+ action="/webmeteruploadapi/upload"
32
+ :file-list="fileList"
33
+ @preview="handlePreview"
34
+ @change="handleChange"
35
+ :remove="remove"
36
+ >
37
+ <div v-if="fileList.length < 5">
38
+ <a-icon type="plus" />
39
+ <div class="ant-upload-text">点击上传</div>
40
+ </div>
41
+ </a-upload>
42
+ <a-modal
43
+ :visible="previewVisible"
44
+ :footer="null"
45
+ @cancel="handleCancel"
46
+ >
47
+ <img style="width: 100%" :src="previewImage" alt="图片上传"/>
48
+ </a-modal>
49
+ </div>
50
+ </a-modal>
51
+ <!-- 关闭工单确认框 -->
52
+ <a-modal
53
+ title="关闭工单"
54
+ :visible="closeVisible"
55
+ @ok="handleCloseOk"
56
+ @cancel="handleCloseCancel"
57
+ :zIndex="1002"
58
+ >
59
+ <p>是否确认手动关闭工单?</p>
60
+ <p style="color: red">(该操作不可撤销,请谨慎操作!)</p>
61
+ </a-modal>
62
+ <!-- 信息主体 -->
63
+ <a-spin :spinning="loadTicketDetails">
64
+ <a-page-header :title="'订单:' + this.details.serial_number">
65
+ <div class="row">
66
+ <div class="content">
67
+ <a-descriptions size="small" :column="isMobile ? 1 : 2">
68
+ <a-descriptions-item label="优先级">
69
+ <a-alert
70
+ :type="showPriorityColorControl()"
71
+ :message="showPriority()"
72
+ :show-icon="true"/>
73
+ </a-descriptions-item>
74
+ <a-descriptions-item label="发起人">{{ details.uploader }}</a-descriptions-item>
75
+ <a-descriptions-item label="问题类型">{{ details.category }}</a-descriptions-item>
76
+ <a-descriptions-item label="发起人联系方式">{{ details.uploader_phone }}</a-descriptions-item>
77
+ </a-descriptions>
78
+ </div>
79
+ </div>
80
+ <!-- 按钮 -->
81
+ <template v-slot:extra>
82
+ <a-button-group style="margin-right: 4px;">
83
+ <a-popover title="开始处理" placement="bottomLeft">
84
+ <template slot="content">
85
+ <p>开始处理当前工单</p>
86
+ </template>
87
+ <a-button type="primary" @click="confirmTicketBtn()" :disabled="handlerBtnDisable()">开始处理</a-button>
88
+ </a-popover>
89
+ <a-popover title="移交他人" placement="bottomLeft">
90
+ <template slot="content">
91
+ <p>将工单转交他人处理</p>
92
+ </template>
93
+ <a-button type="primary" @click="transferBtn()" :disabled="transferBtnDisable()">移交他人</a-button>
94
+ </a-popover>
95
+ <a-popover title="关闭工单" placement="bottomLeft">
96
+ <template slot="content">
97
+ <p>强制关闭当前工单</p>
98
+ <p style="color: red">此操作不可撤销,请谨慎使用</p>
99
+ </template>
100
+ <a-button type="danger" @click="closeBtn()" :disabled="closeBtnDisable()">关闭工单</a-button>
101
+ </a-popover>
102
+ </a-button-group>
103
+ <a-button-group style="margin-right: 4px;">
104
+ <a-button type="dashed" @click="initView" :loading="showSpin">刷新({{ btnCountdownText }})</a-button>
105
+ </a-button-group>
106
+ </template>
107
+ <!-- 进度条 -->
108
+ <a-card :bordered="false" style="margin-top: 40px">
109
+ <a-steps :direction="'horizontal'" :current="step">
110
+ <a-step>
111
+ <template v-slot:title><span>待处理</span></template>
112
+ <template v-slot:description>
113
+ <div>工单已提交,等待处理<div>{{ format(details.created_time,'yyyy-MM-dd hh:mm:ss') }}</div></div>
114
+ </template>
115
+ </a-step>
116
+ <a-step>
117
+ <template v-slot:title><span>处理中</span></template>
118
+ <template v-slot:description>
119
+ <div v-if="step >= 1"><strong>{{ details.name }}</strong> 处理中...<div>{{ format(details.confirm_time,'yyyy-MM-dd hh:mm:ss') }}</div></div>
120
+ </template>
121
+ </a-step>
122
+ <a-step>
123
+ <template v-slot:title><span>{{ getStatus() }}</span></template>
124
+ <template v-slot:description>
125
+ <div v-if="step >= 2">{{ format(details.finished_time,'yyyy-MM-dd hh:mm:ss') }}</div>
126
+ </template>
127
+ </a-step>
128
+ </a-steps>
129
+ </a-card>
130
+ <!-- 切换栏 -->
131
+ <a-tabs style="margin-top: 50px;">
132
+ <!-- 问题描述 -->
133
+ <a-tab-pane :key="1" tab="问题详细描述">
134
+ <a-card style="width: 100%" :loading="descriptionLoading">
135
+ <div v-if="addOnDescription.length > 0" v-for="(item,index) in addOnDescription" :key="index">
136
+ <span style="font-size: 2em;margin-right: 20px;margin-top: 20px">{{ details.uploader }}</span>
137
+ <span>{{ format(item.time,'yyyy年MM月dd日 hh:mm:ss') }}</span>
138
+ <p style="text-indent: 2em;font-size: 20px;margin: 20px">{{ item.description }}</p>
139
+ <img
140
+ v-for="(pic,m) in item.images"
141
+ :src="'data:image/png;base64,' + pic.url"
142
+ @click="changePhotoClass(pic.id)"
143
+ :key="'is' + m"
144
+ :class="changePhotoClassForSmall(pic.id)"
145
+ >
146
+ <div style="height: 1px;background: -webkit-linear-gradient(left, #fff -4%,#6b6c72 50%,#fff 100%);"></div>
147
+ </div>
148
+ <span style="font-size: 2em;margin-right: 20px">{{ details.uploader }}</span>
149
+ <span>{{ format(details.created_time,'yyyy年MM月dd日 hh:mm:ss') }}</span>
150
+ <p style="text-indent: 2em;font-size: 20px;margin: 10px">{{ details.description }}</p>
151
+ <img
152
+ v-for="(originalPic,n) in originalImages"
153
+ :src="'data:image/png;base64,' + originalPic.url"
154
+ @click="changePhotoClass(originalPic.id)"
155
+ :key="'os' + n"
156
+ :class="changePhotoClassForSmall(originalPic.id)"
157
+ style="margin-bottom: 10px"
158
+ >
159
+ </a-card>
160
+ </a-tab-pane>
161
+ <!-- 工单流转历史 -->
162
+ <a-tab-pane :key="2" tab="工单流转历史">
163
+ <ticket-details-flow
164
+ @imageClick="flowImageClick"
165
+ v-if="details.id"
166
+ :ticketId="ticketId"
167
+ :disableCloseBtn="disableCloseBtn"
168
+ :id="details.id"/>
169
+ </a-tab-pane>
170
+ </a-tabs>
171
+ </a-page-header>
172
+ </a-spin>
173
+ <audio controls="controls" hidden src="@/assets/sound/newNote.mp3" ref="audio"></audio>
174
+ <!-- 放大后图片 -->
175
+ <div class="imgBackground" v-if="selectedImageShow" @click="changePhotoClass(selectedImage.id)">
176
+ <img
177
+ :src="'data:image/png;base64,' + selectedImage.url"
178
+ class="img_xl">
179
+ </div>
180
+ </a-drawer>
181
+ </template>
182
+
183
+ <script>
184
+ import JsonViewer from 'vue-json-viewer'
185
+ import { formatDate } from '@vue2-client/utils/util'
186
+ import { TicketDetailsViewApi } from '@vue2-client/services/api/TicketDetailsViewApi'
187
+ import { EmployeeDetailsViewApi } from '@vue2-client/services/api/EmployeeDetailsViewApi'
188
+ import { post } from '@vue2-client/services/api/restTools'
189
+ import XTable from '@vue2-client/base-client/components/common/XTable/XTable'
190
+ import { mapState } from 'vuex'
191
+ import TicketDetailsFlow from './part/TicketDetailsFlow'
192
+ import moment from 'moment'
193
+
194
+ function getBase64 (file) {
195
+ return new Promise((resolve, reject) => {
196
+ const reader = new FileReader()
197
+ reader.readAsDataURL(file)
198
+ reader.onload = () => resolve(reader.result)
199
+ reader.onerror = error => reject(error)
200
+ })
201
+ }
202
+
203
+ export default {
204
+ name: 'TicketDetailsView',
205
+ components: {
206
+ TicketDetailsFlow,
207
+ JsonViewer,
208
+ XTable
209
+ },
210
+ data () {
211
+ return {
212
+ moment,
213
+ // 页面宽度
214
+ screenWidth: document.documentElement.clientWidth,
215
+ // 控制成功页面显示
216
+ successVisible: false,
217
+ // 控制预览显示
218
+ previewVisible: false,
219
+ // 图片真实地址
220
+ previewImage: '',
221
+ // 图片列表
222
+ fileList: [],
223
+ // 工单详情
224
+ details: {
225
+ // 当前负责人ID
226
+ id: undefined,
227
+ name: '',
228
+ uploader: '',
229
+ status: undefined,
230
+ priority: undefined,
231
+ description: '',
232
+ created_time: '',
233
+ confirm_time: '',
234
+ finished_time: '',
235
+ category: '',
236
+ serial_number: '',
237
+ uploader_phone: ''
238
+ },
239
+ images: [],
240
+ selectedImage: null,
241
+ selectedImageShow: false,
242
+ // 当前步骤
243
+ step: 0,
244
+ // 校验转移员工是否存在
245
+ transferCheck: false,
246
+ // 移交工单窗口可见性
247
+ transVisible: false,
248
+ // 转移工单对象
249
+ transferTo: '',
250
+ // 新增留言
251
+ note: '',
252
+ // 控制关闭订单按钮可用性
253
+ disableCloseBtn: false,
254
+ // 控制关闭工单确认框显示
255
+ closeVisible: false,
256
+ // 控制加载过程
257
+ loadTicketDetails: false,
258
+ // 附加描述
259
+ addOnDescription: [],
260
+ // 上传工单时自带照片
261
+ originalImages: [],
262
+ // 定时刷新定时器
263
+ timer: undefined,
264
+ // 所有员工姓名
265
+ nameOptions: [],
266
+ // 员工姓名备选
267
+ nameOptionsForChoose: [],
268
+ // 员工姓名备选项显示控制
269
+ nameOptionsVisible: false,
270
+ // 工单流转抽屉可见性
271
+ workFlowVisible: false,
272
+ // 控制小加载指示物显示
273
+ showSpin: true,
274
+ // 原始描述长度
275
+ addOnDescriptionOriginal: undefined,
276
+ // 描述加载控制
277
+ descriptionLoading: false,
278
+ // 用于刷新按钮倒计时显示
279
+ btnCountdownText: 5
280
+ }
281
+ },
282
+ mounted () {
283
+ this.initView()
284
+ },
285
+ computed: {
286
+ ...mapState('account', { currUser: 'user' }),
287
+ ...mapState('setting', ['isMobile'])
288
+ },
289
+ props: {
290
+ ticketId: {
291
+ type: String,
292
+ required: true
293
+ },
294
+ visible: {
295
+ type: Boolean,
296
+ default: false
297
+ }
298
+ },
299
+ methods: {
300
+ // 转移员工姓名change事件,用于展示备选
301
+ inputChange () {
302
+ if (this.transferTo.length === 0) {
303
+ this.nameOptionsVisible = false
304
+ } else {
305
+ this.nameOptionsVisible = true
306
+ var inputName = this.transferTo
307
+ this.nameOptionsForChoose = this.nameOptions.filter(function (element) {
308
+ return element.name.indexOf(inputName) !== -1
309
+ })
310
+ }
311
+ },
312
+ // 在候选框中点击了名称
313
+ chooseName (name) {
314
+ this.nameOptionsVisible = false
315
+ this.transferTo = name
316
+ this.checkEmp()
317
+ },
318
+ // 获取所有员工名,供输入框备选
319
+ getAllEmpNames () {
320
+ return post(EmployeeDetailsViewApi.getAllEmployeeName, null)
321
+ .then(res => {
322
+ this.nameOptions = res
323
+ }, err => {
324
+ console.log(err)
325
+ })
326
+ },
327
+ // 图像修改检测
328
+ handleChange ({ fileList }) {
329
+ this.fileList = fileList.filter((item) => {
330
+ return item.status === 'done' || item.status === 'uploading'
331
+ })
332
+ },
333
+ // 在上传页面,点击图片上的垃圾桶,撤销上传
334
+ remove (file) {
335
+ return post(TicketDetailsViewApi.revocationImage, {
336
+ file: file
337
+ })
338
+ .then(res => {
339
+ if (res === 'success') {
340
+ this.$message.success('删除成功')
341
+ }
342
+ this.fileList = this.fileList.filter((item) => {
343
+ return item.response.name !== file.response.name
344
+ })
345
+ }, err => {
346
+ console.log(err)
347
+ })
348
+ },
349
+ // 上传头像前校验
350
+ beforeUpload (file) {
351
+ const isJpgOrPng =
352
+ file.type === 'image/jpeg' ||
353
+ file.type === 'image/jpg' ||
354
+ file.type === 'image/png'
355
+ const Lt2M = file.size / 1024 / 1024 < 2
356
+ if (!Lt2M) {
357
+ this.$message.error('图片不得大于2MB!')
358
+ }
359
+ if (!isJpgOrPng) {
360
+ this.$message.error('只能上传jpg/png格式的图片')
361
+ }
362
+ return isJpgOrPng && Lt2M
363
+ },
364
+ handleCancel () {
365
+ this.previewVisible = false
366
+ },
367
+ // 处理预览图像
368
+ async handlePreview (file) {
369
+ if (!file.url && !file.preview) {
370
+ file.preview = await getBase64(file.originFileObj)
371
+ }
372
+ this.previewImage = file.url || file.preview
373
+ this.previewVisible = true
374
+ },
375
+ // 开启定时器
376
+ setTimer () {
377
+ if (this.timer === undefined) {
378
+ this.timer = setInterval(() => {
379
+ if (this.btnCountdownText > 0) {
380
+ this.btnCountdownText--
381
+ if (this.btnCountdownText === 0) {
382
+ this.initView()
383
+ this.btnCountdownText = 5
384
+ }
385
+ }
386
+ }, 1000)
387
+ }
388
+ },
389
+ // 初始化组件
390
+ initView () {
391
+ this.showSpin = true
392
+ this.descriptionLoading = true
393
+ // 获取所有员工名
394
+ this.getAllEmpNames()
395
+ // 获取工单的基本详情
396
+ this.getTicketDetail(this.ticketId)
397
+ // 获取工单的附加信息
398
+ this.handleOtherData()
399
+ },
400
+ // 图像点击切换放大缩小
401
+ changePhotoClass (id) {
402
+ for (let i = 0; i < this.images.length; i++) {
403
+ if (id === this.images[i].id) {
404
+ this.images[i].isLarge = !this.images[i].isLarge
405
+ this.selectedImage = this.images[i]
406
+ }
407
+ }
408
+ this.selectedImageShow = !this.selectedImageShow
409
+ },
410
+ // 控制未放大图像变暗
411
+ changePhotoClassForSmall (id) {
412
+ for (let i = 0; i < this.images.length; i++) {
413
+ if (id == this.images[i].id) {
414
+ if (this.images[i].isLarge === true) {
415
+ return 'img_sm_dark'
416
+ } else {
417
+ return 'img_sm'
418
+ }
419
+ }
420
+ }
421
+ },
422
+ // 获取当前相关联的照片
423
+ getPhoto () {
424
+ return post(TicketDetailsViewApi.getTicketImages, {
425
+ ticketId: this.ticketId
426
+ })
427
+ .then(res => {
428
+ this.images = res
429
+ for (let i = 0; i < this.images.length; i++) {
430
+ this.images[i].isLarge = false
431
+ }
432
+ this.mergeAddImage()
433
+ }, err => {
434
+ console.log(err)
435
+ })
436
+ },
437
+ // 将同一次上传的图片,与描述放在一起
438
+ mergeAddImage () {
439
+ this.originalImages = []
440
+ for (let i = 0; i < this.addOnDescription.length; i++) {
441
+ this.addOnDescription[i].images = []
442
+ }
443
+ for (let i = 0; i < this.images.length; i++) {
444
+ if (this.images[i].did === 0) {
445
+ this.originalImages.push(this.images[i])
446
+ continue
447
+ }
448
+ for (let j = 0; j < this.addOnDescription.length; j++) {
449
+ if (this.images[i].did === this.addOnDescription[j].id) {
450
+ this.addOnDescription[j].images.push(this.images[i])
451
+ }
452
+ }
453
+ }
454
+ this.initDone()
455
+ },
456
+ initDone () {
457
+ // 初始化信息
458
+ this.showSpin = false
459
+ this.descriptionLoading = false
460
+ if (this.step !== 3) {
461
+ this.setTimer()
462
+ }
463
+ this.addOnDescriptionOriginal = 1
464
+ },
465
+ // 关闭工单确认后业务逻辑
466
+ handleCloseOk () {
467
+ return post(TicketDetailsViewApi.manualCloseTicket, {
468
+ ticketId: this.ticketId,
469
+ time: new Date()
470
+ })
471
+ .then(res => {
472
+ if (res !== 0) {
473
+ this.$message.success(
474
+ '操作成功',
475
+ 5
476
+ )
477
+ this.initView()
478
+ this.closeVisible = false
479
+ } else {
480
+ this.$message.error(
481
+ '操作失败',
482
+ 5
483
+ )
484
+ }
485
+ }, err => {
486
+ console.error(err)
487
+ })
488
+ },
489
+ // 关闭工单取消后业务逻辑
490
+ handleCloseCancel () {
491
+ this.closeVisible = false
492
+ },
493
+ // 确认工单按钮业务逻辑
494
+ confirmTicketBtn () {
495
+ const currentEmpId = this.getCurrentEmpId()
496
+ return post(TicketDetailsViewApi.confirmTicket, {
497
+ ticketId: this.ticketId,
498
+ empId: currentEmpId,
499
+ time: new Date()
500
+ })
501
+ .then(res => {
502
+ if (res !== 0) {
503
+ this.$message.success('操作成功', 5)
504
+ } else {
505
+ this.$message.error('工单已被他人处理或关闭,请刷新再试', 5)
506
+ }
507
+ this.initView()
508
+ }, err => {
509
+ console.error(err)
510
+ this.$message.error('工单已被他人处理,请刷新再试', 5)
511
+ this.initView()
512
+ })
513
+ },
514
+ // 获取当前登陆员工ID
515
+ getCurrentEmpId () {
516
+ return this.currUser.id
517
+ },
518
+ // 转移工单按钮业务逻辑
519
+ transferBtn () {
520
+ this.transVisible = true
521
+ },
522
+ checkEmp () {
523
+ return post(EmployeeDetailsViewApi.findEmpName, {
524
+ empName: this.transferTo
525
+ })
526
+ .then(res => {
527
+ const num = res
528
+ this.transferCheck = num !== 0
529
+ }, err => {
530
+ console.error(err)
531
+ })
532
+ },
533
+ // 获取工单状态撤销or关闭
534
+ getStatus () {
535
+ if (this.details.status === 2) {
536
+ return '已撤销'
537
+ } else {
538
+ return '已关闭'
539
+ }
540
+ },
541
+ // 关闭工单按钮业务逻辑
542
+ closeBtn () {
543
+ this.closeVisible = true
544
+ },
545
+ // 转移工单确认后逻辑
546
+ handleTransferOk () {
547
+ if (!this.transferCheck) {
548
+ this.$message.error(
549
+ '请先检查您输入的员工名',
550
+ 2
551
+ )
552
+ } else {
553
+ return post(TicketDetailsViewApi.transferTicketToOthers, {
554
+ ticketId: this.ticketId,
555
+ endTime: new Date(),
556
+ transferTo: this.transferTo,
557
+ note: this.note,
558
+ images: this.fileList
559
+ })
560
+ .then(res => {
561
+ const result = res
562
+ this.note = ''
563
+ this.transVisible = false
564
+ if (result === 1) {
565
+ this.$message.success(
566
+ '操作成功',
567
+ 5
568
+ )
569
+ this.fileList = []
570
+ this.transferTo = ''
571
+ this.transferCheck = false
572
+ this.initView()
573
+ } else {
574
+ this.$message.error('工单已被他人处理或关闭,请刷新再试', 5)
575
+ }
576
+ this.handleCancel()
577
+ this.initView()
578
+ }, err => {
579
+ console.error(err)
580
+ this.transVisible = false
581
+ })
582
+ }
583
+ },
584
+ // 转移工单取消后逻辑
585
+ handleTransferCancel () {
586
+ this.transVisible = false
587
+ this.transferCheck = false
588
+ this.transferTo = ''
589
+ this.note = ''
590
+ },
591
+ // 关闭抽屉时回调
592
+ onClose () {
593
+ clearInterval(this.timer)
594
+ this.timer = undefined
595
+ this.addOnDescription = []
596
+ this.disableCloseBtn = false
597
+ this.$emit('update:visible', false)
598
+ this.originalImages = []
599
+ this.images = []
600
+ this.addOnDescriptionOriginal = undefined
601
+ },
602
+ // 对其他信息进行初始化,包括附加描述,图片
603
+ handleOtherData () {
604
+ const beforeLength = this.addOnDescription.length
605
+ return post(TicketDetailsViewApi.getAddonDescription, {
606
+ ticketId: this.ticketId
607
+ })
608
+ .then(res => {
609
+ this.addOnDescription = res
610
+ this.getPhoto()
611
+ if (this.addOnDescription.length > beforeLength && this.addOnDescriptionOriginal !== undefined) {
612
+ this.addOnDescriptionOriginal = 1
613
+ this.$refs.audio.currentTime = 0
614
+ this.$refs.audio.play()
615
+ this.$notification.open({
616
+ message: '最新通知',
617
+ description:
618
+ '客户追加了问题描述,请及时查看!',
619
+ onClick: () => {
620
+ }
621
+ })
622
+ }
623
+ }, err => {
624
+ console.log(err)
625
+ })
626
+ },
627
+ // 获取工单详情信息
628
+ getTicketDetail (num) {
629
+ this.showSpin = true
630
+ return post(TicketDetailsViewApi.getTicketDetails, {
631
+ ticketId: num
632
+ }).then(res => {
633
+ this.details = res[0]
634
+ this.step = res[0].status
635
+ if (this.details.status === 3) {
636
+ this.disableCloseBtn = true
637
+ }
638
+ const categoryValue = this.details.category
639
+ this.details.category = this.$appdata.getDictionaryList('ticketCategoryMap')[categoryValue].label
640
+ }, err => {
641
+ console.error(err)
642
+ })
643
+ },
644
+ // 日期格式化
645
+ format (date, format) {
646
+ return formatDate(date, format)
647
+ },
648
+ // 转换JSON
649
+ toJSON (value) {
650
+ try {
651
+ return JSON.parse(value)
652
+ } catch (e) {
653
+ return value
654
+ }
655
+ },
656
+ // 控制开始处理按钮可用状态
657
+ handlerBtnDisable () {
658
+ return this.step !== 0
659
+ },
660
+ // 控制移交他人按钮可用状态
661
+ transferBtnDisable () {
662
+ return this.step === 0 || this.step === 3
663
+ },
664
+ // 控制关闭工单按钮可用状态
665
+ closeBtnDisable () {
666
+ return this.step === 0 || this.disableCloseBtn || this.details.id != this.currUser.id
667
+ },
668
+ // 优先级文字显示
669
+ showPriority () {
670
+ if (this.details.priority === 2) {
671
+ return '一般'
672
+ } else if (this.details.priority === 1) {
673
+ return '紧急'
674
+ } else {
675
+ return '非常紧急'
676
+ }
677
+ },
678
+ // 优先度颜色控制
679
+ showPriorityColorControl () {
680
+ if (this.details.priority === 2) {
681
+ return 'info'
682
+ } else if (this.details.priority === 1) {
683
+ return 'warning'
684
+ } else {
685
+ return 'error'
686
+ }
687
+ },
688
+ // 单击工单流转历史图片
689
+ flowImageClick (image) {
690
+ this.selectedImage = image
691
+ this.selectedImageShow = !this.selectedImageShow
692
+ }
693
+ },
694
+ watch: {
695
+ 'visible' (val) {
696
+ if (val) {
697
+ this.initView()
698
+ }
699
+ },
700
+ 'step' (newVal) {
701
+ if (newVal === 3) {
702
+ clearInterval(this.timer)
703
+ }
704
+ }
705
+ }
706
+ }
707
+ </script>
708
+
709
+ <style lang="less" scoped>
710
+ .high-priority{
711
+ background-color: rgba(163, 30, 30, 0.66);
712
+ border: red solid 1px;
713
+ font-size: large;
714
+ padding: 5px;
715
+ color: white;
716
+ border-radius: 10px;
717
+ }
718
+
719
+ .detail-layout {
720
+ margin-left: 44px;
721
+ }
722
+ .text {
723
+ color: rgba(0, 0, 0, .45);
724
+ }
725
+
726
+ .heading {
727
+ color: rgba(0, 0, 0, .85);
728
+ font-size: 20px;
729
+ }
730
+
731
+ .no-data {
732
+ color: rgba(0, 0, 0, .25);
733
+ text-align: center;
734
+ line-height: 64px;
735
+ font-size: 16px;
736
+
737
+ i {
738
+ font-size: 24px;
739
+ margin-right: 16px;
740
+ position: relative;
741
+ top: 3px;
742
+ }
743
+ }
744
+
745
+ .mobile {
746
+ .detail-layout {
747
+ margin-left: unset;
748
+ }
749
+ .text {
750
+
751
+ }
752
+ .status-list {
753
+ text-align: left;
754
+ }
755
+ }
756
+
757
+ .row {
758
+ display: flex;
759
+
760
+ .content {
761
+ -webkit-box-flex: 1;
762
+ flex: auto;
763
+ -ms-flex: auto;
764
+ }
765
+
766
+ .extra {
767
+ flex: 0 1 auto;
768
+ -webkit-box-flex: 0;
769
+ -ms-flex: 0 1 auto;
770
+ min-width: 242px;
771
+ margin-left: 88px;
772
+ text-align: right;
773
+ }
774
+ }
775
+
776
+ .img_sm {
777
+ border: rgba(84, 84, 84, 0.2) solid 1.5px;
778
+ border-radius: 5px;
779
+ padding: 10px;
780
+ width: 160px;
781
+ height: 120px;
782
+ margin-bottom: 20px;
783
+ margin-left: 20px;
784
+ }
785
+ .img_xl {
786
+ position: absolute;
787
+ top:0;bottom:0;left:0;right:0;
788
+ margin: auto;
789
+ width: 60%;
790
+ max-width: 1000px;
791
+ cursor: zoom-out;
792
+ z-index: 9999;
793
+ animation: imgZoomIn 0.4s;
794
+ -webkit-animation: imgZoomIn 0.4s;
795
+ }
796
+ @keyframes imgZoomIn
797
+ {
798
+ from {width: 160px;}
799
+ to {width: 60%;}
800
+ }
801
+ .img_sm:hover {
802
+ opacity: 0.6;
803
+ cursor: zoom-in;
804
+ }
805
+ .img_sm_dark{
806
+ filter: grayscale(100%);
807
+ opacity: 0.6;
808
+ border: rgba(84, 84, 84, 0.2) solid 1.5px;
809
+ border-radius: 5px;
810
+ padding: 10px;
811
+ width: 160px;
812
+ height: 120px;
813
+ margin-bottom: 20px;
814
+ margin-left: 20px;
815
+ }
816
+ .imgBackground {
817
+ position: absolute;
818
+ top:0;bottom:0;left:0;right:0;
819
+ width: 100%;
820
+ height: 100%;
821
+ z-index: 9998;
822
+ background-color: rgba(0,0,0,0.7);
823
+ }
824
+ .nameOptionsItem {
825
+ padding-left: 5px;
826
+ margin-bottom: 2px;
827
+ }
828
+ .nameOptionsItem:hover {
829
+ background-color: rgb(209,233,255);
830
+ }
831
+ .nameOptionsItem:last-of-type {
832
+ margin-bottom: 0px;
833
+ }
834
+ .nameOptions {
835
+ border: rgba(0,0,0,0.4) solid 1px;
836
+ }
837
+ </style>