vue-intergrall-plugins 1.1.51 → 1.1.53

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,1340 +1,741 @@
1
- <template>
2
- <div
3
- :class="['email-item box-shadow-active', isOpen ? isOpenClass : `${isClosedClass} cursor-pointer`, showInfos ? 'info-open' : '', origem, customClass]"
4
- @click="openByItem($event)">
5
- <div v-if="showInfos" class="email-overlay"></div>
6
- <div class="email-author" v-if="autor" :class="[origem, isMainEmail ? 'main' : '']" @click.stop="toggleIsOpen"
7
- :key="autor">
8
- <span :title="statusTitle"><fa-icon :icon="['fas', status !== 'C' ? 'reply' : 'times']" :class="[origem]" /></span>
9
- <p class="email-author-name" v-text="returnAuthorName" :title="returnAuthorName"></p>
10
- <span :title="`E-mail ${origem === 'outros' ? 'recebido' : 'enviado'}`">
11
- <fa-icon :icon="['fas', origem === 'outros' ? 'user' : 'headset']" class="email-to-svg" />
12
- </span>
13
- </div>
14
- <div class="email-custom-buttons" v-if="customButtons && customButtons.length" @click.stop>
15
- <span v-for="(button, index) in customButtons" :key="button.id || index" v-show="button.use"
16
- @click="button.callback ? button.callback(returnParams(button.params)) : $emit(button.emitName, returnParams(button.params))" :class="`${button.customClass || 'menu-mensagem'}`"
17
- v-tippy :content="button.tippyContent">
18
- <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
19
- <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
20
- </span>
21
- </div>
22
- <div
23
- v-if="customActionButtons && customActionButtons.length && customActionButtons[0].type === 'ja-spam'"
24
- :key="customActionButtons[0].id"
25
- class="ja-marcado-spam"
26
- >
27
- <span class="icon-tittle-ja-spam">
28
- <fa-icon :icon="['fas', 'exclamation-triangle']" style="color:#FF0000; margin-right:8px; font-size:16px;" />
29
- {{ customActionButtons[0].label }}
30
- </span>
31
- <div @click.stop class="ja-marcado-spam-buttons">
32
- <button
33
- :disabled="customActionButtons[0].btn1.disabled"
34
- class="btn-nao-spam"
35
- @click="customActionButtons[0].btn1.callback"
36
- style="position: relative;"
37
- >
38
- <VueLoader
39
- v-if="customActionButtons[0].btn1.loading"
40
- :hasBg="false"
41
- class="btn-loader"
42
- />
43
- <span :style="{ opacity: customActionButtons[0].btn1.loading ? 0 : 1 }">
44
- {{ customActionButtons[0].btn1.label }}
45
- </span>
46
- </button>
47
- <button
48
- :disabled="customActionButtons[0].btn2.disabled"
49
- class="btn-e-spam"
50
- @click="customActionButtons[0].btn2.callback"
51
- style="position: relative;"
52
- >
53
- <VueLoader
54
- v-if="customActionButtons[0].btn2.loading"
55
- :hasBg="false"
56
- class="btn-loader"
57
- />
58
- <span :style="{ opacity: customActionButtons[0].btn2.loading ? 0 : 1 }">
59
- <fa-icon v-if="customActionButtons[0].btn2.icon"
60
- class="icon-btn-encerrar-spam"
61
- :icon="['fas', customActionButtons[0].btn2.icon === 'exit' ? 'sign-out-alt' : customActionButtons[0].btn2.icon]"
62
- style="margin-right: 6px;"
63
- />
64
- {{ customActionButtons[0].btn2.label }}
65
- </span>
66
- </button>
67
- </div>
68
- </div>
69
- <div class="email-custom-action-buttons" v-if="customActionButtons && customActionButtons.length" @click.stop>
70
- <template v-for="(button, index) in customActionButtons">
71
- <button
72
- v-if="button.type !== 'ja-spam'"
73
- :key="button.id || index"
74
- v-show="button.use"
75
- @click="button.callback(returnParams(button.params))"
76
- :class="`${button.customClass || 'email-custom-action-button'}`"
77
- v-tippy
78
- :content="button.tippyContent"
79
- >
80
- <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
81
- <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
82
- <span v-if="button.label" class="email-custom-action-label" v-text="button.label"></span>
83
- </button>
84
- </template>
85
- </div>
86
- <div class="email-header" @click.stop="toggleIsOpen">
87
- <p class="email-subject" :title="returnMainValue()">
88
- {{ returnMainValue() }}
89
- </p>
90
- <div
91
- class="divBtnReplyEmail" :class="[isOpen ? 'reply-email-open' : '']" v-if="status === 'C'">
92
- <strong class="strongMsg">{{ status_msg }} </strong>
93
- <button
94
- v-if="hasReplyEmail"
95
- class="btnReplyEmail"
96
- @click.stop="emitReplyEmail"
97
- ><strong>Reenviar</strong>
98
- </button>
99
- </div>
100
- <div class="header-container">
101
- <div :class="`email-header-content${isOpen ? ' open' : ''}`">
102
- <div class="email-header-infos">
103
- <template>
104
- <div v-if="para && para.length" class="email-to-from-container" ref="emailToContainer">
105
- <EmailTo v-for="(recipient, index) in para" :key="`to-${recipient.email}`"
106
- :currentName="formattedToName(recipient.name, index, para.length)" :email="recipient.email"
107
- :showMail="isOpen" />
108
- </div>
109
- <div v-if="copia && copia.length" class="email-cc-container">
110
- <EmailTo v-for="(recipient, index) in copia" :key="`cc-${recipient.email}`"
111
- :currentName="formattedCcName(recipient.name, index, copia.length)" :email="recipient.email"
112
- :showMail="isOpen" />
113
- </div>
114
- <div class="email-to-btn" v-show="isOpen" @click.stop="toggleShowInfos()">
115
- <fa-icon :icon="['fas', 'caret-down']" />
116
- </div>
117
- </template>
118
- <div v-if="!isMainEmail && isOpen" class="email-subject-secondary">
119
- <span class="email-subject-span"
120
- v-text="`Assunto: ${htmlEntityToEmoji(replaceUnicodeWithEmoji(assunto)) || '(Sem assunto)'}`"></span>
121
- </div>
122
- </div>
123
- </div>
124
- <span :class="`email-date ${isOpen ? isOpenClass : isClosedClass}`" :title="formattedDate" ref="emailDate"
125
- v-show="formattedDate">
126
- <fa-icon :icon="['fas', 'calendar']" />
127
- {{ formattedDate }}
128
- </span>
129
- </div>
130
- <ul v-if="showInfos" ref="emailToInfos" class="email-to-infos box-shadow" v-clickaway="() => showInfos = false"
131
- @click.stop>
132
- <li v-for="(info, index) in mailInfos" :key="`info-${index}`" class="email-info">
133
- <span v-text="info.label"></span>
134
- {{ info.value }}
135
- </li>
136
- </ul>
137
- <span v-if="isOpen" :class="['email-actions box-shadow', { active: actionsOpen }, { main: isMainEmail }]"
138
- @click.stop="toggleActions">
139
- <span></span>
140
- <span></span>
141
- <span></span>
142
- </span>
143
- <ul class="email-actions-list box-shadow" v-if="actionsOpen && isOpen" v-clickaway="closeActions" @click.stop>
144
- <li class="email-action" @click.stop="toggleOpenMessage">
145
- {{ !openMessage ? 'Visualizar' : 'Esconder' }} texto do e-mail (html)
146
- </li>
147
- </ul>
148
- </div>
149
- <div class="email-content" v-show="isOpen" ref="emailIframeParent">
150
- <VueLoader v-if="isIframeLoading" />
151
- <div v-if="hasError" class="email-error-content">
152
- <p>Erro ao carregar o e-mail</p>
153
- <button class="box-shadow" @click="handleTryAgain()">Tentar novamente</button>
154
- </div>
155
- <iframe v-show="!hasError" ref="emailIframe"
156
- :class="`email-html ${isIframeLoading ? 'visibility-hidden' : ''}`"></iframe>
157
- <span class="email-raw" v-if="openMessage">{{ mensagem }}</span>
158
- </div>
159
- <div v-if="filteredFiles && filteredFiles.length" class="email-files" v-show="isOpen">
160
- <EmailFile v-for="(anexo, index) in filteredFiles" :key="index" :anexo="anexo" :dominio="dominio" />
161
- </div>
162
- <div
163
- v-if="filteredFiles && filteredFiles.length && !isOpen"
164
- class="email-attachments-clip cursor-pointer"
165
- @click.stop="openAndScrollToAttachments"
166
- >
167
- <span class="clip-icon">
168
- <fa-icon :icon="['fas', 'paperclip']" />
169
- <span class="clip-badge">{{ filteredFiles.length }}</span>
170
- </span>
171
- </div>
172
- <!-- Status da mensagem -->
173
- <transition name="fade" mode="out-in">
174
- <span class="check" v-if="status == 'D'" :content="contentTooltip" v-tippy key="check-padrao">
175
- <fa-icon :icon="['fas', 'check']" />
176
- </span>
177
- <span class="check cinza" v-else-if="status == 'Q'" :content="contentTooltip" v-tippy key="check-cinza">
178
- <fa-icon :icon="['fas', 'check']" />
179
- </span>
180
- <span class="check preto" v-else-if="status == 'G'" :content="contentTooltip" v-tippy key="check-preto">
181
- <fa-icon :icon="['fas', 'check']" />
182
- </span>
183
- <span class="check preto" v-else-if="status == 'E'" :content="contentTooltip" v-tippy key="double-check-preto">
184
- <fa-icon :icon="['fas', 'check-double']" />
185
- </span>
186
- <span class="check visualizado" v-else-if="status == 'L'" :content="contentTooltip" v-tippy
187
- key="double-check-visualizado">
188
- <fa-icon :icon="['fas', 'check-double']" />
189
- </span>
190
- <!-- Status finalizador -->
191
- <span class="check vermelho" v-else-if="status == 'C' || status == 'ERRO'" :content="contentTooltip" v-tippy
192
- key="times-circle">
193
- <fa-icon :icon="['fas', 'times-circle']" />
194
- </span>
195
- <!-- Status finalizador -->
196
- <span class="check vermelho" v-else-if="status == 'T'" :content="contentTooltip" v-tippy key="hourglass">
197
- <fa-icon :icon="['fas', 'hourglass']" />
198
- </span>
199
- <!-- Status finalizador -->
200
- <span class="check vermelho" v-else-if="status == 'O'" :content="contentTooltip" v-tippy key="deleted">
201
- <fa-icon :icon="['fas', 'times']" />
202
- </span>
203
- <!-- Status de mensagem deletada -->
204
- </transition>
205
- </div>
206
- </template>
207
-
208
- <script>
209
- import EmailFile from "./EmailFile.vue";
210
- import EmailTo from "./EmailTo.vue";
211
- import { textoLongo } from "@/mixins/formatarTexto";
212
- import Clickaway from '@/directives/clickaway';
213
-
214
- export default {
215
- mixins: [textoLongo],
216
- directives: {
217
- clickaway: Clickaway
218
- },
219
- components: { EmailFile, EmailTo },
220
- props: {
221
- dominio: {
222
- type: String,
223
- required: true
224
- },
225
- dicionario: {
226
- type: Object,
227
- required: true
228
- },
229
- customClass: {
230
- type: String,
231
- default: ''
232
- },
233
- from: {
234
- type: Array,
235
- default: () => []
236
- },
237
- para: {
238
- type: Array,
239
- default: () => []
240
- },
241
- copia: {
242
- type: Array,
243
- default: () => []
244
- },
245
- html: {
246
- type: String,
247
- default: ""
248
- },
249
- assunto: {
250
- type: String,
251
- default: ""
252
- },
253
- dataHora: {
254
- type: String,
255
- default: ""
256
- },
257
- mensagem: {
258
- type: String,
259
- default: ""
260
- },
261
- anexos: {
262
- type: [Array, String],
263
- default: () => []
264
- },
265
- iniciarAberto: {
266
- type: Boolean,
267
- default: false
268
- },
269
- dataServer: {
270
- type: String,
271
- default: ""
272
- },
273
- isOpenClass: {
274
- type: String,
275
- default: 'bg-dark-white-2'
276
- },
277
- isClosedClass: {
278
- type: String,
279
- default: 'bg-white'
280
- },
281
- refKey: {
282
- type: String,
283
- },
284
- showRawMessageInsideEmail: {
285
- type: Boolean,
286
- default: false
287
- },
288
- origem: {
289
- type: String,
290
- default: 'outros'
291
- },
292
- autor: {
293
- type: String
294
- },
295
- isMainEmail: {
296
- type: Boolean,
297
- default: true
298
- },
299
- customButtons: {
300
- type: Array
301
- },
302
- customActionButtons: {
303
- type: Array
304
- },
305
- status: {
306
- type: String,
307
- default: ''
308
- },
309
- status_msg: {
310
- type: String,
311
- default: ''
312
- },
313
- hasReplyEmail: {
314
- type: Boolean,
315
- default: false
316
- },
317
- id_lig: {
318
- type: String,
319
- },
320
- token_cliente: {
321
- type: String,
322
- },
323
- infos: {
324
- type: Object,
325
- default: () => ({}),
326
- },
327
- jaMarcadoSpam: {
328
- type: Boolean,
329
- default: false
330
- },
331
- msgTooltip: {
332
- type: String,
333
- default: ''
334
- }
335
- },
336
- data() {
337
- return {
338
- isOpen: this.iniciarAberto,
339
- openMessage: false,
340
- actionsOpen: false,
341
- showInfos: false,
342
- isIframeLoading: true,
343
- hasError: false,
344
- errorCount: 0,
345
- scrollToFile: false,
346
- };
347
- },
348
- computed: {
349
- statusTitle() {
350
- if(this.status !== 'C') {
351
- return `Enviado por: ${this.autor}`
352
- }
353
-
354
- if(!this.status_msg) {
355
- return `Enviado com erro por: ${this.autor}`
356
- }
357
-
358
- return `Enviado com erro por: ${this.autor} - ${this.status_msg}`
359
- },
360
- paraCopia() {
361
- if (!this.copia || !this.copia.length) return this.para && this.para.length ? this.para : []
362
- return this.para && this.para.length ? this.para.concat(this.copia) : this.copia
363
- },
364
- formattedDate() {
365
- return this.formataDateHoraDateFns(this.dataHora, this.dataServer, this.dicionario);
366
- },
367
- contentTooltip: {
368
- get() {
369
- if(!this.status || !this.msgTooltip) return ''
370
- if (this.status && !this.msgTooltip) {
371
- const msgStatus = "msg_status_" + this.status;
372
- return (this.strTooltipAux = this.dicionario[msgStatus]);
373
- } else if (this.status && this.msgTooltip) {
374
- return (this.strTooltipAux = this.msgTooltip);
375
- }
376
- },
377
- set(msg) {
378
- return (this.contentTooltip = msg);
379
- },
380
- },
381
- mailInfos() {
382
- const formatAsString = (arr) => {
383
- let str = ''
384
- arr.forEach(({ name, email }, index) => {
385
- if (!name && !email) str += ''
386
- else str += `${name || ''} ${email ? `<${email}>` : ''}${((name || email) && index !== arr.length - 1) ? ', ' : ''}`
387
- })
388
- return str
389
- }
390
-
391
- const infos = [
392
- {
393
- label: 'De:',
394
- value: this.from && this.from.length ? formatAsString(this.from) : '--'
395
- },
396
- {
397
- label: 'Para:',
398
- value: this.para && this.para.length ? formatAsString(this.para) : '--'
399
- },
400
- {
401
- label: 'Assunto:',
402
- value: this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
403
- },
404
- {
405
- label: 'Data:',
406
- value: this.formataDataHora(this.dataHora) || '--'
407
- },
408
- ]
409
-
410
- if (this.copia && this.copia.length) {
411
- infos.splice(2, 0, {
412
- label: `${this.dicionario.tit_copia}:` || 'Copia:',
413
- value: formatAsString(this.copia)
414
- })
415
- }
416
-
417
- return infos
418
- },
419
- filteredFiles() {
420
- if (!this.anexos || !this.anexos.length) return
421
-
422
- return this.anexos.filter(anexo => {
423
- return !this.html.includes(anexo.name);
424
- })
425
- },
426
- returnAuthorName() {
427
- if (!this.from || !this.from.length) return this.autor || ''
428
- const { email, name } = this.from[0]
429
- if (!name) return email
430
- if (!email) return name
431
- if (this.isOpen) return `${name} (${email})`
432
- return name
433
- },
434
- formattedToName() {
435
- return (name, index, length) => {
436
- let addVirgulaDps = index < length - 1
437
- const text = index === 0 ? `Para: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
438
- return text
439
- }
440
- },
441
- formattedCcName() {
442
- return (name, index, length) => {
443
- let addVirgulaDps = index < length - 1
444
- const text = index === 0 ? `${this.dicionario.tit_copia || 'Cópia'}: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
445
- return text
446
- }
447
- }
448
- },
449
- watch: {
450
- isOpen: 'updateIframeContent'
451
- },
452
- mounted() {
453
- this.updateIframeContent();
454
- this.adjustMaxWidth()
455
-
456
- if (this.refKey) this.$root.$refs[`${refKey}`] = this
457
-
458
- setTimeout(() => {
459
- if (this.isIframeLoading) this.adjustIframeHeight()
460
- }, 15000);
461
- },
462
- methods: {
463
- openAndScrollToAttachments() {
464
- if (!this.isOpen) {
465
- this.scrollToFile = true;
466
- this.isIframeLoading = true;
467
- this.isOpen = true;
468
- } else if (!this.isIframeLoading) {
469
- this.scrollToAttachments();
470
- } else {
471
- this.scrollToFile = true;
472
- }
473
- },
474
- scrollToAttachments() {
475
- this.$nextTick(() => {
476
- const files = this.$el.querySelector('.email-files');
477
- if (files) {
478
- files.scrollIntoView({ behavior: 'smooth', block: 'center' });
479
- }
480
- });
481
- },
482
- handleTryAgain() {
483
- this.isOpen = true
484
- this.isIframeLoading = true
485
- this.hasError = false
486
-
487
- this.$nextTick(this.updateIframeContent())
488
- },
489
-
490
- emitReplyEmail() {
491
- if(!this.hasReplyEmail) return
492
-
493
- this.$emit('reply-email', {
494
- html: this.html,
495
- mensagem: this.mensagem,
496
- assunto: this.assunto,
497
- from: this.from,
498
- para: this.para,
499
- dataHora: this.dataHora,
500
- anexos: this.anexos,
501
- status: this.status,
502
- status_msg: this.status_msg,
503
- copia: this.copia,
504
- origem: this.origem,
505
- autor: this.autor,
506
- id_lig: this.id_lig,
507
- token_cliente: this.token_cliente,
508
- infos: this.infos,
509
- });
510
- },
511
-
512
- gerarMensagemEstilizada(msg) {
513
- try {
514
- const currentStyles = [
515
- { tagAbertura: "<i>", tagFechamento: "</i>", find: /_(.*?)_/g },
516
- { tagAbertura: "<b>", tagFechamento: "</b>", find: /\*(.*?)\*/g },
517
- { tagAbertura: "<del>", tagFechamento: "</del>", find: /~(.*?)~/g }
518
- ]
519
-
520
- const isLetterOrUnderscore = (char) => {
521
- return /[a-zA-Z_]/.test(char)
522
- }
523
-
524
- const isValidMatch = (message, fullMatch, startIndex) => {
525
- const beforeChar = message[startIndex - 1]
526
- const afterChar = message[startIndex + fullMatch.length]
527
- return (
528
- (beforeChar === undefined || !isLetterOrUnderscore(beforeChar)) &&
529
- (afterChar === undefined || !isLetterOrUnderscore(afterChar))
530
- )
531
- }
532
-
533
- let message = msg
534
-
535
- for (const { tagAbertura, tagFechamento, find } of currentStyles) {
536
- let match
537
- while ((match = find.exec(message)) !== null) {
538
- const fullMatch = match[0]
539
- const content = match[1]
540
- const startIndex = match.index
541
-
542
- if (isValidMatch(message, fullMatch, startIndex)) {
543
- const endIndex = startIndex + fullMatch.length
544
- const replacedContent = `${tagAbertura}${content}${tagFechamento}`
545
- message = message.slice(0, startIndex) + replacedContent + message.slice(endIndex)
546
- }
547
- }
548
- }
549
-
550
- return message
551
- } catch (err) {
552
- console.error('Erro ao gerar mensagem estilizada: ', err)
553
- return msg
554
- }
555
- },
556
- updateIframeContent() {
557
- this.$nextTick(() => {
558
- if (this.isOpen && this.isIframeLoading) {
559
- const iframe = this.$refs.emailIframe;
560
- if (!iframe) {
561
- console.warn('Iframe not found');
562
- this.isIframeLoading = false
563
- return
564
- }
565
- const doc = iframe.contentDocument || iframe.contentWindow.document;
566
- if (!doc) {
567
- console.warn('Document not found in iframe');
568
- this.isIframeLoading = false
569
- return
570
- }
571
- let content = this.html || ''
572
- if(!content || !content.length) {
573
- console.warn('No content to display in iframe');
574
- this.isIframeLoading = false
575
- return
576
- }
577
- if (!/<[a-z][\s\S]*>/i.test(content)) {
578
- content = content.replace(/\n/g, '<br>');
579
- content = this.gerarMensagemEstilizada(content)
580
- content = `<p>${content}</p>`;
581
- }
582
-
583
- doc.open();
584
- doc.write(content);
585
- doc.close();
586
-
587
- const images = doc.getElementsByTagName('img');
588
- let imagesLoaded = 0;
589
-
590
- const imageLoadHandler = () => {
591
- imagesLoaded++;
592
- if (imagesLoaded === images.length) {
593
- this.adjustIframeHeight();
594
- }
595
- };
596
-
597
- if (images.length === 0) {
598
- this.adjustIframeHeight();
599
- } else {
600
- for (let img of images) {
601
- img.addEventListener('load', imageLoadHandler);
602
- img.addEventListener('error', imageLoadHandler);
603
- }
604
- }
605
- }
606
- });
607
- },
608
- adjustIframeHeight() {
609
- this.$nextTick(() => {
610
- const iframe = this.$refs.emailIframe;
611
- const emailParent = this.$refs.emailIframeParent
612
- if (iframe && emailParent) {
613
- setTimeout(() => {
614
- const doc = iframe.contentDocument || iframe.contentWindow.document;
615
- const margin = 20
616
- const value = doc.documentElement.offsetHeight + margin
617
- if (value === 0 || doc.documentElement.querySelector('body').innerHTML === '') {
618
- this.errorCount++
619
- if (this.errorCount > 3) {
620
- this.hasError = true
621
- if (this.isIframeLoading) this.isIframeLoading = false
622
- return
623
- }
624
- this.isIframeLoading = true
625
- this.updateIframeContent()
626
- return
627
- }
628
- if (this.hasError || this.errorCount > 0) {
629
- this.hasError = false
630
- this.errorCount = 0
631
- }
632
- iframe.style.height = `${value}px`;
633
- emailParent.style.minHeight = `${value}px`
634
- if (this.scrollToFile) {
635
- this.scrollToFile = false;
636
- this.scrollToAttachments();
637
- }
638
- }, 100)
639
- }
640
-
641
- if (this.isIframeLoading) this.isIframeLoading = false
642
- });
643
- },
644
- toggleShowInfos() {
645
- this.showInfos = !this.showInfos;
646
- if (this.showInfos) {
647
- this.$nextTick(() => {
648
- this.adjustTopPosition();
649
- });
650
- }
651
- },
652
- adjustTopPosition() {
653
- const ulElement = this.$refs.emailToInfos;
654
- if (!ulElement) return
655
- const ulHeight = ulElement.offsetHeight;
656
- const maxHeight = 300
657
- const finalHeight = ulHeight < maxHeight ? ulHeight : maxHeight
658
- ulElement.style.bottom = `-${finalHeight}px`;
659
- },
660
- toggleIsOpen() {
661
- this.isOpen = !this.isOpen;
662
- if (this.isOpen) {
663
- this.isIframeLoading = true;
664
- } else {
665
- this.actionsOpen = false;
666
- this.openMessage = false;
667
- this.showInfos = false;
668
- this.scrollToFile = false;
669
- }
670
- },
671
- adjustMaxWidth() {
672
- this.$nextTick(() => {
673
- const toContainer = this.$refs.emailToContainer
674
- const dateContainer = this.$refs.emailDate
675
- if (!toContainer || !dateContainer) return
676
- toContainer.style.maxWidth = `calc(100% - ${dateContainer.offsetWidth}px)`
677
- })
678
- },
679
- toggleActions() {
680
- this.actionsOpen = !this.actionsOpen;
681
- },
682
- toggleOpenMessage() {
683
- if (this.showRawMessageInsideEmail) {
684
- this.openMessage = !this.openMessage;
685
- }
686
-
687
- this.$emit('open-message', {
688
- dicionario: this.dicionario,
689
- from: this.from,
690
- para: this.para,
691
- html: this.html,
692
- assunto: this.assunto,
693
- dataHora: this.dataHora,
694
- mensagem: this.mensagem,
695
- anexos: this.filteredFiles,
696
- dataServer: this.dataServer,
697
- dominio: this.dominio
698
- })
699
- },
700
- closeActions() {
701
- this.actionsOpen = false;
702
- },
703
- returnMainValue() {
704
- if (this.isMainEmail) return this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
705
- return ''
706
- },
707
- openByItem(event) {
708
- if (this.isOpen) return;
709
-
710
- event.preventDefault();
711
- event.stopPropagation();
712
-
713
- this.toggleIsOpen();
714
- },
715
- returnParams(params) {
716
- const defaultParams = {
717
- message: this.mensagem,
718
- };
719
-
720
- if (!params) return defaultParams;
721
-
722
- const keys = params.instanceKeys.split("|");
723
- if (!keys || !keys.length)
724
- return {
725
- defaultParams,
726
- ...params.values,
727
- };
728
-
729
- const customParams = { ...params.values };
730
- keys.forEach((key) => {
731
- if (this[key]) customParams[key] = this[key];
732
- else console.warn(`Cant find ${key} on 'this' instance`);
733
- });
734
-
735
- return Object.keys(customParams).length ? customParams : defaultParams;
736
- }
737
- }
738
- };
739
- </script>
740
-
741
- <style scoped>
742
- .show-y-top-enter-active,
743
- .show-y-top-leave-enter {
744
- opacity: 1;
745
- transform: translateY(0);
746
- transition: all 200ms linear;
747
- }
748
-
749
- .show-y-top-enter,
750
- .show-y-top-leave-to {
751
- opacity: 0;
752
- transform: translateY(-2%);
753
- }
754
- </style>
755
-
756
- <style>
757
- .visibility-hidden {
758
- visibility: hidden;
759
- }
760
-
761
- .box-shadow-active {
762
- box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.25);
763
- }
764
-
765
- .bg-dark-white-2 {
766
- background-color: #f7f7f7;
767
- }
768
-
769
- .bg-white {
770
- background-color: #FFF;
771
- }
772
-
773
- .cursor-pointer {
774
- cursor: pointer;
775
- }
776
-
777
- .email-overlay {
778
- width: 100%;
779
- height: 100%;
780
- background-color: transparent;
781
- z-index: 1;
782
- position: absolute;
783
- top: 0;
784
- left: 0;
785
- }
786
-
787
- .email-item {
788
- --konecta-gray-3: #515050;
789
- --konecta-light: #f8f9fa;
790
- --blue-silver-4: #dae0e5;
791
- --email-principal: #faa732;
792
- --email-outros: #86b7fe;
793
- font-family: "Roboto", sans-serif;
794
- flex: 1;
795
- margin: 0 0 10px 0;
796
- color: #222;
797
- min-height: 60px;
798
- display: flex;
799
- flex-wrap: wrap;
800
- padding: 10px;
801
- border-radius: 5px;
802
- transition: all 150ms ease-in-out;
803
- max-width: 100%;
804
- width: 100%;
805
- overflow: hidden;
806
- position: relative;
807
- }
808
-
809
- .divBtnReplyEmail {
810
- display: flex;
811
- align-items: center;
812
- background-color: #f0adad;
813
- border-radius: 6px;
814
- padding: 7px 9px;
815
- margin: 5px 0;
816
- gap: 8px;
817
- }
818
-
819
- .reply-email-open {
820
- width: calc(100% - 10px - 45px);
821
- }
822
-
823
- .btnReplyEmail {
824
- display: block;
825
- background-color: #faa732;
826
- border: 1px solid #da8205;
827
- margin: 8px 0 8px 5px;
828
- padding: 5px 10px 5px 10px;
829
- font-size: 14.4px;
830
- font-weight: bold;
831
- border-radius: 3px;
832
- color: #000000;
833
- cursor: pointer;
834
- }
835
-
836
- .ja-marcado-spam {
837
- width: 100%;
838
- background: #fffbe6;
839
- border: 1px solid #ffe58f;
840
- border-radius: 6px;
841
- box-shadow: 0 2px 8px rgba(0,0,0,0.08);
842
- padding: 5px 30px;
843
- margin: 9px 0px 5px 0px;
844
- display: flex;
845
- justify-content: space-between;
846
- align-items: center;
847
- gap: 16px;
848
- }
849
-
850
- .ja-marcado-spam > span {
851
- color: #614500;
852
- font-weight: 500;
853
- font-size: 14px;
854
- margin-bottom: 0;
855
- align-self: center;
856
- align-items: center;
857
- }
858
-
859
- .ja-marcado-spam-buttons {
860
- display: flex;
861
- flex-direction: column;
862
- gap: 6px;
863
- align-items: flex-end;
864
- }
865
-
866
- .ja-marcado-spam button {
867
- min-width: 110px;
868
- padding: 4px 10px;
869
- border: none;
870
- border-radius: 5px;
871
- background: #ffe58f;
872
- color: #333;
873
- cursor: pointer;
874
- font-size: 13.4px;
875
- }
876
-
877
- .ja-marcado-spam-buttons .btn-nao-spam {
878
- background: #36b87b;
879
- color: var(--white);
880
- border: 1px solid var(--konecta-success-hover, #309264);
881
- font-weight: bold;
882
- }
883
-
884
- .ja-marcado-spam-buttons .btn-nao-spam:hover {
885
- background: #309264;
886
- }
887
-
888
- .ja-marcado-spam-buttons .btn-e-spam {
889
- background: #e74c3c;
890
- color: var(--white);
891
- border: 1px solid var(--konecta-danger-hover, #c92e1e);
892
- font-weight: bold;
893
- }
894
-
895
- .ja-marcado-spam-buttons .btn-e-spam:hover {
896
- background: #c92e1e;
897
- }
898
-
899
- .icon-btn-encerrar-spam {
900
- margin-right: 2px;
901
- }
902
-
903
- .btn-loader {
904
- position: absolute;
905
- left: 50%;
906
- top: 50%;
907
- transform: translate(-50%, -50%);
908
- z-index: 2;
909
- pointer-events: none;
910
- }
911
-
912
- .strongMsg {
913
- flex: 1;
914
- font-size: 13px;
915
- }
916
-
917
- .email-custom-action-buttons {
918
- display: flex;
919
- gap: 7px;
920
- align-items: center;
921
- flex-wrap: wrap;
922
- max-width: 100%;
923
- cursor: default;
924
- }
925
-
926
- .email-custom-action-button {
927
- margin-top: 10px;
928
- background-color: var(--konecta-light) !important;
929
- color: var(--konecta-dark) !important;
930
- border: 1px solid var(--blue-silver-4) !important;
931
- flex: 1;
932
- min-width: 100px;
933
- display: flex;
934
- align-items: center;
935
- justify-content: center;
936
- gap: 5px;
937
- padding: 5px;
938
- overflow: hidden;
939
- border-radius: 5px;
940
- text-overflow: ellipsis;
941
- white-space: nowrap;
942
- transition: all 100ms ease-in-out;
943
- max-width: 100%;
944
- cursor: pointer
945
- }
946
-
947
- .email-custom-action-button:hover {
948
- background-color: #e9ecef !important;
949
- }
950
-
951
- .email-custom-action-button:disabled {
952
- background-color: var(--konecta-gray-3) !important;
953
- border: 1px solid #25282b !important;
954
- cursor: not-allowed !important;
955
- }
956
-
957
- .email-item.outros {
958
- border-left: 3px solid var(--email-outros);
959
- }
960
-
961
- .email-author-name {
962
- margin: 0 5px;
963
- max-width: 100%;
964
- overflow: hidden;
965
- text-overflow: ellipsis;
966
- white-space: nowrap;
967
- }
968
-
969
- .email-author.outros {
970
- color: var(--email-outros);
971
- }
972
-
973
- .email-author.outros>svg:nth-child(1) {
974
- transform: rotate(180deg);
975
- }
976
-
977
- .email-author.principal {
978
- color: var(--email-principal);
979
- }
980
-
981
- .email-author.main {
982
- font-size: 16.4px;
983
- }
984
-
985
- .email-item.principal {
986
- border-left: 3px solid var(--email-principal);
987
- }
988
-
989
- .email-item.info-open {
990
- overflow: visible
991
- }
992
-
993
- .email-header {
994
- width: 100%;
995
- display: flex;
996
- flex-direction: column;
997
- cursor: pointer;
998
- border-top-right-radius: 5px;
999
- border-top-left-radius: 5px;
1000
- position: relative;
1001
- overflow: visible;
1002
- }
1003
-
1004
- .header-container {
1005
- display: flex;
1006
- overflow: hidden;
1007
- position: relative;
1008
- }
1009
-
1010
- .email-header-content {
1011
- display: flex;
1012
- align-items: center;
1013
- flex: 1;
1014
- min-width: 250px;
1015
- }
1016
-
1017
- .email-header-infos {
1018
- display: flex;
1019
- flex-direction: column;
1020
- flex: 1;
1021
- }
1022
-
1023
- .email-subject {
1024
- margin: 5px 0 0 0;
1025
- font-size: 16.4px;
1026
- cursor: pointer;
1027
- }
1028
-
1029
- .email-date {
1030
- --width: 245px;
1031
- font-size: 12.8px;
1032
- text-overflow: ellipsis;
1033
- white-space: nowrap;
1034
- overflow: hidden;
1035
- position: absolute;
1036
- right: 0;
1037
- top: 0;
1038
- min-width: var(--width);
1039
- width: var(--width);
1040
- max-width: var(--width);
1041
- display: flex;
1042
- justify-content: flex-end;
1043
- gap: 3px;
1044
- align-items: center;
1045
- }
1046
-
1047
- .email-content {
1048
- display: flex;
1049
- flex-direction: column;
1050
- align-items: center;
1051
- justify-content: flex-start;
1052
- width: 100%;
1053
- background-color: #FFF;
1054
- position: relative;
1055
- max-width: 100%;
1056
- }
1057
-
1058
- .email-actions {
1059
- align-self: flex-end;
1060
- display: flex;
1061
- border-radius: 10px;
1062
- cursor: pointer;
1063
- align-items: center;
1064
- justify-content: center;
1065
- gap: 3px;
1066
- padding: 5px 7px;
1067
- background-color: #dddddd;
1068
- position: absolute;
1069
- right: 0;
1070
- top: 30px;
1071
- z-index: 1;
1072
- }
1073
-
1074
- .email-actions.main {
1075
- top: 10px
1076
- }
1077
-
1078
- .email-actions.active {
1079
- background-color: #dfdfdf;
1080
- }
1081
-
1082
- .email-actions>span {
1083
- width: 4px;
1084
- height: 4px;
1085
- min-width: 4px;
1086
- min-height: 4px;
1087
- max-width: 4px;
1088
- max-height: 4px;
1089
- background-color: #222;
1090
- border-radius: 50%;
1091
- }
1092
-
1093
- .email-actions-list {
1094
- position: absolute;
1095
- right: 45px;
1096
- width: 250px;
1097
- top: 5px;
1098
- margin: 0;
1099
- list-style-type: none;
1100
- padding: 0;
1101
- border-radius: 5px;
1102
- z-index: 1;
1103
- }
1104
-
1105
- .email-action {
1106
- background-color: #dfdfdf;
1107
- padding: 5px 10px;
1108
- cursor: pointer;
1109
- transition: background-color 150ms ease-in-out;
1110
- font-size: 14.4px;
1111
- user-select: none;
1112
- }
1113
-
1114
- .email-action:nth-child(1) {
1115
- border-top-left-radius: 5px;
1116
- border-top-right-radius: 5px;
1117
- }
1118
-
1119
- .email-action:last-child {
1120
- border-bottom-left-radius: 5px;
1121
- border-bottom-right-radius: 5px;
1122
- }
1123
-
1124
- .email-action:hover {
1125
- background-color: #CCC;
1126
- }
1127
-
1128
- .email-html {
1129
- width: 100%;
1130
- min-width: 300px;
1131
- max-width: 100%;
1132
- border: none;
1133
- overflow: auto;
1134
- }
1135
-
1136
- .email-raw {
1137
- width: 100%;
1138
- max-width: 100%;
1139
- padding: 15px;
1140
- font-size: 14.4px;
1141
- color: #222;
1142
- }
1143
-
1144
- .email-files {
1145
- display: flex;
1146
- gap: 10px;
1147
- flex-wrap: wrap;
1148
- width: 100%;
1149
- margin-top: 5px;
1150
- }
1151
-
1152
- .email-header-content,
1153
- .email-header-infos {
1154
- max-width: 100%;
1155
- overflow: hidden;
1156
- }
1157
-
1158
- .email-to-from-container {
1159
- margin-bottom: 5px;
1160
- max-width: 100%;
1161
- min-width: 250px;
1162
- overflow: hidden;
1163
- display: flex;
1164
- align-items: center;
1165
- flex-wrap: wrap;
1166
- flex: 1;
1167
- gap: 5px;
1168
- }
1169
-
1170
- .email-cc-container {
1171
- margin-bottom: 5px;
1172
- max-width: 100%;
1173
- min-width: 250px;
1174
- overflow: hidden;
1175
- display: flex;
1176
- align-items: center;
1177
- flex-wrap: wrap;
1178
- flex: 1;
1179
- gap: 5px;
1180
- }
1181
-
1182
- .email-to-btn {
1183
- padding: 0 5px;
1184
- font-size: 14.4px;
1185
- cursor: pointer;
1186
- color: #666;
1187
- }
1188
-
1189
- .email-to-infos {
1190
- position: absolute;
1191
- bottom: -325px;
1192
- border: 1px solid #CCC;
1193
- z-index: 2;
1194
- padding: 10px;
1195
- background-color: #FFF;
1196
- max-height: 300px;
1197
- overflow-y: auto;
1198
- overflow-x: hidden;
1199
- width: 300px;
1200
- display: flex;
1201
- flex-direction: column;
1202
- gap: 5px;
1203
- margin: 0;
1204
- cursor: default;
1205
- }
1206
-
1207
- .email-info {
1208
- width: 100%;
1209
- font-size: 12.8px;
1210
- }
1211
-
1212
- .email-info>span {
1213
- font-size: 12px;
1214
- color: gray;
1215
- margin-right: 3px;
1216
- }
1217
-
1218
- .email-author {
1219
- display: flex;
1220
- align-items: center;
1221
- height: 5px;
1222
- font-size: 12px;
1223
- font-weight: bold;
1224
- transform: translateY(-2px);
1225
- width: 100%;
1226
- cursor: pointer;
1227
- }
1228
-
1229
- .email-subject-secondary {
1230
- margin-top: -5px;
1231
- }
1232
-
1233
- .email-subject-span {
1234
- font-size: 11.2px;
1235
- color: gray;
1236
- }
1237
-
1238
- .email-to-svg {
1239
- font-size: 13.6px;
1240
- }
1241
-
1242
- .email-custom-buttons {
1243
- display: flex;
1244
- gap: 7px;
1245
- position: absolute;
1246
- top: 5px;
1247
- right: 5px;
1248
- z-index: 1;
1249
- font-size: 12.8px;
1250
- }
1251
-
1252
- .menu-mensagem {
1253
- cursor: pointer;
1254
- padding: 1px;
1255
- opacity: .7;
1256
- transition: opacity 100ms ease-in-out;
1257
- }
1258
-
1259
- .menu-mensagem:hover,
1260
- .menu-mensagem:focus,
1261
- .menu-mensagem:active {
1262
- opacity: 1;
1263
- }
1264
-
1265
- .email-error-content {
1266
- display: flex;
1267
- justify-content: center;
1268
- align-items: center;
1269
- flex-direction: column;
1270
- gap: 5px;
1271
- padding: 10px;
1272
- }
1273
-
1274
- .email-error-content p {
1275
- margin: 0;
1276
- color: #E74C3C;
1277
- }
1278
-
1279
- .email-error-content button {
1280
- border: 1px solid #CCC;
1281
- border-radius: 3px;
1282
- padding: 5px 10px;
1283
- background-color: #FFF;
1284
- cursor: pointer;
1285
- transition: background-color 150ms ease-in-out;
1286
- }
1287
-
1288
- .email-error-content button:hover {
1289
- background-color: #EEE;
1290
- }
1291
-
1292
- .btnReplyEmail:hover, .btnReplyEmail:active {
1293
- background-color: #da8205;
1294
- color: #000000;
1295
- }
1296
-
1297
- .email-attachments-clip {
1298
- display: flex;
1299
- cursor: pointer;
1300
- margin-top: 5px;
1301
- }
1302
-
1303
- .clip-icon {
1304
- position: relative;
1305
- font-size: 22px;
1306
- color: #999;
1307
- transform: rotate(-15deg);
1308
- }
1309
-
1310
- .clip-badge {
1311
- position: absolute;
1312
- transform: rotate(15deg);
1313
- top: 0px;
1314
- right: -15px;
1315
- display: flex;
1316
- align-items: center;
1317
- justify-content: center;
1318
- background: linear-gradient(135deg, #999 40%, #515050 100%);
1319
- color: #fff;
1320
- border-radius: 50%;
1321
- min-width: 22px;
1322
- height: 22px;
1323
- font-size: 12.4px;
1324
- border: 1px solid #fff;
1325
- filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .18));
1326
- text-align: center;
1327
- padding: 0 4px;
1328
- box-sizing: border-box;
1329
- }
1330
-
1331
- .clip-icon:hover {
1332
- color: #777;
1333
- }
1334
-
1335
- .clip-icon:hover .clip-badge {
1336
- background: linear-gradient(135deg, #999 20%, #515050 70%);
1337
- filter: drop-shadow(0 2px 4px rgba(0,0,0,0.28));
1338
- }
1339
-
1340
- </style>
1
+ <template>
2
+ <div
3
+ :class="['email-item box-shadow-active', isOpen ? isOpenClass : `${isClosedClass} cursor-pointer`, showInfos ? 'info-open' : '', origem, customClass]"
4
+ @click="openByItem($event)">
5
+ <div v-if="showInfos" class="email-overlay"></div>
6
+ <div class="email-author" v-if="autor" :class="[origem, isMainEmail ? 'main' : '']" @click.stop="toggleIsOpen"
7
+ :key="autor">
8
+ <span :title="statusTitle"><fa-icon :icon="['fas', status !== 'C' ? 'reply' : 'times']" :class="[origem]" /></span>
9
+ <p class="email-author-name" v-text="returnAuthorName" :title="returnAuthorName"></p>
10
+ <span :title="`E-mail ${origem === 'outros' ? 'recebido' : 'enviado'}`">
11
+ <fa-icon :icon="['fas', origem === 'outros' ? 'user' : 'headset']" class="email-to-svg" />
12
+ </span>
13
+ </div>
14
+ <div class="email-custom-buttons" v-if="customButtons && customButtons.length" @click.stop>
15
+ <span v-for="(button, index) in customButtons" :key="button.id || index" v-show="button.use"
16
+ @click="button.callback ? button.callback(returnParams(button.params)) : $emit(button.emitName, returnParams(button.params))" :class="`${button.customClass || 'menu-mensagem'}`"
17
+ v-tippy :content="button.tippyContent">
18
+ <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
19
+ <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
20
+ </span>
21
+ </div>
22
+ <div
23
+ v-if="customActionButtons && customActionButtons.length && customActionButtons[0].type === 'ja-spam'"
24
+ :key="customActionButtons[0].id"
25
+ class="ja-marcado-spam"
26
+ >
27
+ <span class="icon-tittle-ja-spam">
28
+ <fa-icon :icon="['fas', 'exclamation-triangle']" style="color:#FF0000; margin-right:8px; font-size:16px;" />
29
+ {{ customActionButtons[0].label }}
30
+ </span>
31
+ <div @click.stop class="ja-marcado-spam-buttons">
32
+ <button
33
+ :disabled="customActionButtons[0].btn1.disabled"
34
+ class="btn-nao-spam"
35
+ @click="customActionButtons[0].btn1.callback"
36
+ style="position: relative;"
37
+ >
38
+ <VueLoader
39
+ v-if="customActionButtons[0].btn1.loading"
40
+ :hasBg="false"
41
+ class="btn-loader"
42
+ />
43
+ <span :style="{ opacity: customActionButtons[0].btn1.loading ? 0 : 1 }">
44
+ {{ customActionButtons[0].btn1.label }}
45
+ </span>
46
+ </button>
47
+ <button
48
+ :disabled="customActionButtons[0].btn2.disabled"
49
+ class="btn-e-spam"
50
+ @click="customActionButtons[0].btn2.callback"
51
+ style="position: relative;"
52
+ >
53
+ <VueLoader
54
+ v-if="customActionButtons[0].btn2.loading"
55
+ :hasBg="false"
56
+ class="btn-loader"
57
+ />
58
+ <span :style="{ opacity: customActionButtons[0].btn2.loading ? 0 : 1 }">
59
+ <fa-icon v-if="customActionButtons[0].btn2.icon"
60
+ class="icon-btn-encerrar-spam"
61
+ :icon="['fas', customActionButtons[0].btn2.icon === 'exit' ? 'sign-out-alt' : customActionButtons[0].btn2.icon]"
62
+ style="margin-right: 6px;"
63
+ />
64
+ {{ customActionButtons[0].btn2.label }}
65
+ </span>
66
+ </button>
67
+ </div>
68
+ </div>
69
+ <div class="email-custom-action-buttons" v-if="customActionButtons && customActionButtons.length" @click.stop>
70
+ <template v-for="(button, index) in customActionButtons">
71
+ <button
72
+ v-if="button.type !== 'ja-spam'"
73
+ :key="button.id || index"
74
+ v-show="button.use"
75
+ @click="button.callback(returnParams(button.params))"
76
+ :class="`${button.customClass || 'email-custom-action-button'}`"
77
+ v-tippy
78
+ :content="button.tippyContent"
79
+ >
80
+ <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
81
+ <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
82
+ <span v-if="button.label" class="email-custom-action-label" v-text="button.label"></span>
83
+ </button>
84
+ </template>
85
+ </div>
86
+ <div class="email-header" @click.stop="toggleIsOpen">
87
+ <p class="email-subject" :title="returnMainValue()">
88
+ {{ returnMainValue() }}
89
+ </p>
90
+ <div
91
+ class="divBtnReplyEmail" :class="[isOpen ? 'reply-email-open' : '']" v-if="status === 'C'">
92
+ <strong class="strongMsg">{{ status_msg }} </strong>
93
+ <button
94
+ v-if="hasReplyEmail"
95
+ class="btnReplyEmail"
96
+ @click.stop="emitReplyEmail"
97
+ ><strong>Reenviar</strong>
98
+ </button>
99
+ </div>
100
+ <div class="header-container">
101
+ <div :class="`email-header-content${isOpen ? ' open' : ''}`">
102
+ <div class="email-header-infos">
103
+ <template>
104
+ <div v-if="para && para.length" class="email-to-from-container" ref="emailToContainer">
105
+ <EmailTo v-for="(recipient, index) in para" :key="`to-${recipient.email}`"
106
+ :currentName="formattedToName(recipient.name, index, para.length)" :email="recipient.email"
107
+ :showMail="isOpen" />
108
+ </div>
109
+
110
+ <div v-if="copia && copia.length" class="email-cc-container">
111
+ <EmailTo v-for="(recipient, index) in copia" :key="`cc-${recipient.email}`"
112
+ :currentName="formattedCcName(recipient.name, index, copia.length)" :email="recipient.email"
113
+ :showMail="isOpen" />
114
+ </div>
115
+ <div class="email-to-btn" v-show="isOpen" @click.stop="toggleShowInfos()">
116
+ <fa-icon :icon="['fas', 'caret-down']" />
117
+ </div>
118
+ </template>
119
+ <div v-if="!isMainEmail && isOpen" class="email-subject-secondary">
120
+ <span class="email-subject-span"
121
+ v-text="`Assunto: ${htmlEntityToEmoji(replaceUnicodeWithEmoji(assunto)) || '(Sem assunto)'}`"></span>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ <span :class="`email-date ${isOpen ? isOpenClass : isClosedClass}`" :title="formattedDate" ref="emailDate"
126
+ v-show="formattedDate">
127
+ <fa-icon :icon="['fas', 'calendar']" />
128
+ {{ formattedDate }}
129
+ </span>
130
+ </div>
131
+ <ul v-if="showInfos" ref="emailToInfos" class="email-to-infos box-shadow" v-clickaway="() => showInfos = false"
132
+ @click.stop>
133
+ <li v-for="(info, index) in mailInfos" :key="`info-${index}`" class="email-info">
134
+ <span v-text="info.label"></span>
135
+ {{ info.value }}
136
+ </li>
137
+ </ul>
138
+ <span v-if="isOpen" :class="['email-actions box-shadow', { active: actionsOpen }, { main: isMainEmail }]"
139
+ @click.stop="toggleActions">
140
+ <span></span>
141
+ <span></span>
142
+ <span></span>
143
+ </span>
144
+ <ul class="email-actions-list box-shadow" v-if="actionsOpen && isOpen" v-clickaway="closeActions" @click.stop>
145
+ <li class="email-action" @click.stop="toggleOpenMessage">
146
+ {{ !openMessage ? 'Visualizar' : 'Esconder' }} texto do e-mail (html)
147
+ </li>
148
+ </ul>
149
+ </div>
150
+ <div class="email-content" v-show="isOpen" ref="emailIframeParent">
151
+ <VueLoader v-if="isIframeLoading" />
152
+ <div v-if="hasError" class="email-error-content">
153
+ <p>Erro ao carregar o e-mail</p>
154
+ <button class="box-shadow" @click="handleTryAgain()">Tentar novamente</button>
155
+ </div>
156
+ <iframe v-show="!hasError" ref="emailIframe"
157
+ :class="`email-html ${isIframeLoading ? 'visibility-hidden' : ''}`"></iframe>
158
+ <span class="email-raw" v-if="openMessage">{{ mensagem }}</span>
159
+ </div>
160
+ <div v-if="filteredFiles && filteredFiles.length" class="email-files" v-show="isOpen">
161
+ <EmailFile v-for="(anexo, index) in filteredFiles" :key="index" :anexo="anexo" :dominio="dominio" />
162
+ </div>
163
+ <div
164
+ v-if="filteredFiles && filteredFiles.length && !isOpen"
165
+ class="email-attachments-clip cursor-pointer"
166
+ @click.stop="openAndScrollToAttachments"
167
+ >
168
+ <span class="clip-icon">
169
+ <fa-icon :icon="['fas', 'paperclip']" />
170
+ <span class="clip-badge">{{ filteredFiles.length }}</span>
171
+ </span>
172
+ </div>
173
+ <!-- Status da mensagem -->
174
+ <transition name="fade" mode="out-in">
175
+ <span class="check" v-if="status == 'D'" :content="contentTooltip" v-tippy key="check-padrao">
176
+ <fa-icon :icon="['fas', 'check']" />
177
+ </span>
178
+ <span class="check cinza" v-else-if="status == 'Q'" :content="contentTooltip" v-tippy key="check-cinza">
179
+ <fa-icon :icon="['fas', 'check']" />
180
+ </span>
181
+ <span class="check preto" v-else-if="status == 'G'" :content="contentTooltip" v-tippy key="check-preto">
182
+ <fa-icon :icon="['fas', 'check']" />
183
+ </span>
184
+ <span class="check preto" v-else-if="status == 'E'" :content="contentTooltip" v-tippy key="double-check-preto">
185
+ <fa-icon :icon="['fas', 'check-double']" />
186
+ </span>
187
+ <span class="check visualizado" v-else-if="status == 'L'" :content="contentTooltip" v-tippy
188
+ key="double-check-visualizado">
189
+ <fa-icon :icon="['fas', 'check-double']" />
190
+ </span>
191
+ <!-- Status finalizador -->
192
+ <span class="check vermelho" v-else-if="status == 'C' || status == 'ERRO'" :content="contentTooltip" v-tippy
193
+ key="times-circle">
194
+ <fa-icon :icon="['fas', 'times-circle']" />
195
+ </span>
196
+ <!-- Status finalizador -->
197
+ <span class="check vermelho" v-else-if="status == 'T'" :content="contentTooltip" v-tippy key="hourglass">
198
+ <fa-icon :icon="['fas', 'hourglass']" />
199
+ </span>
200
+ <!-- Status finalizador -->
201
+ <span class="check vermelho" v-else-if="status == 'O'" :content="contentTooltip" v-tippy key="deleted">
202
+ <fa-icon :icon="['fas', 'times']" />
203
+ </span>
204
+ <!-- Status de mensagem deletada -->
205
+ </transition>
206
+ </div>
207
+ </template>
208
+
209
+ <script>
210
+ import EmailFile from "./EmailFile.vue";
211
+ import EmailTo from "./EmailTo.vue";
212
+ import { textoLongo } from "@/mixins/formatarTexto";
213
+ import Clickaway from '@/directives/clickaway';
214
+ import '../../styles/style.css';
215
+
216
+ export default {
217
+ mixins: [textoLongo],
218
+ directives: {
219
+ clickaway: Clickaway
220
+ },
221
+ components: { EmailFile, EmailTo },
222
+ props: {
223
+ dominio: {
224
+ type: String,
225
+ required: true
226
+ },
227
+ dicionario: {
228
+ type: Object,
229
+ required: true
230
+ },
231
+ customClass: {
232
+ type: String,
233
+ default: ''
234
+ },
235
+ from: {
236
+ type: Array,
237
+ default: () => []
238
+ },
239
+ para: {
240
+ type: Array,
241
+ default: () => []
242
+ },
243
+ copia: {
244
+ type: Array,
245
+ default: () => []
246
+ },
247
+ html: {
248
+ type: String,
249
+ default: ""
250
+ },
251
+ assunto: {
252
+ type: String,
253
+ default: ""
254
+ },
255
+ dataHora: {
256
+ type: String,
257
+ default: ""
258
+ },
259
+ mensagem: {
260
+ type: String,
261
+ default: ""
262
+ },
263
+ anexos: {
264
+ type: [Array, String],
265
+ default: () => []
266
+ },
267
+ iniciarAberto: {
268
+ type: Boolean,
269
+ default: false
270
+ },
271
+ dataServer: {
272
+ type: String,
273
+ default: ""
274
+ },
275
+ isOpenClass: {
276
+ type: String,
277
+ default: 'bg-dark-white-2'
278
+ },
279
+ isClosedClass: {
280
+ type: String,
281
+ default: 'bg-white'
282
+ },
283
+ refKey: {
284
+ type: String,
285
+ },
286
+ showRawMessageInsideEmail: {
287
+ type: Boolean,
288
+ default: false
289
+ },
290
+ origem: {
291
+ type: String,
292
+ default: 'outros'
293
+ },
294
+ autor: {
295
+ type: String
296
+ },
297
+ isMainEmail: {
298
+ type: Boolean,
299
+ default: true
300
+ },
301
+ customButtons: {
302
+ type: Array
303
+ },
304
+ customActionButtons: {
305
+ type: Array
306
+ },
307
+ status: {
308
+ type: String,
309
+ default: ''
310
+ },
311
+ status_msg: {
312
+ type: String,
313
+ default: ''
314
+ },
315
+ hasReplyEmail: {
316
+ type: Boolean,
317
+ default: false
318
+ },
319
+ id_lig: {
320
+ type: String,
321
+ },
322
+ token_cliente: {
323
+ type: String,
324
+ },
325
+ infos: {
326
+ type: Object,
327
+ default: () => ({}),
328
+ },
329
+ jaMarcadoSpam: {
330
+ type: Boolean,
331
+ default: false
332
+ },
333
+ msgTooltip: {
334
+ type: String,
335
+ default: ''
336
+ }
337
+ },
338
+ data() {
339
+ return {
340
+ isOpen: this.iniciarAberto,
341
+ openMessage: false,
342
+ actionsOpen: false,
343
+ showInfos: false,
344
+ isIframeLoading: true,
345
+ hasError: false,
346
+ errorCount: 0,
347
+ scrollToFile: false,
348
+ };
349
+ },
350
+ computed: {
351
+ statusTitle() {
352
+ if(this.status !== 'C') {
353
+ return `Enviado por: ${this.autor}`
354
+ }
355
+
356
+ if(!this.status_msg) {
357
+ return `Enviado com erro por: ${this.autor}`
358
+ }
359
+
360
+ return `Enviado com erro por: ${this.autor} - ${this.status_msg}`
361
+ },
362
+ paraCopia() {
363
+ if (!this.copia || !this.copia.length) return this.para && this.para.length ? this.para : []
364
+ return this.para && this.para.length ? this.para.concat(this.copia) : this.copia
365
+ },
366
+ formattedDate() {
367
+ return this.formataDateHoraDateFns(this.dataHora, this.dataServer, this.dicionario);
368
+ },
369
+ contentTooltip: {
370
+ get() {
371
+ if(!this.status || !this.msgTooltip) return ''
372
+ if (this.status && !this.msgTooltip) {
373
+ const msgStatus = "msg_status_" + this.status;
374
+ return (this.strTooltipAux = this.dicionario[msgStatus]);
375
+ } else if (this.status && this.msgTooltip) {
376
+ return (this.strTooltipAux = this.msgTooltip);
377
+ }
378
+ },
379
+ set(msg) {
380
+ return (this.contentTooltip = msg);
381
+ },
382
+ },
383
+ mailInfos() {
384
+ const formatAsString = (arr) => {
385
+ let str = ''
386
+ arr.forEach(({ name, email }, index) => {
387
+ if (!name && !email) str += ''
388
+ else str += `${name || ''} ${email ? `<${email}>` : ''}${((name || email) && index !== arr.length - 1) ? ', ' : ''}`
389
+ })
390
+ return str
391
+ }
392
+
393
+ const infos = [
394
+ {
395
+ label: 'De:',
396
+ value: this.from && this.from.length ? formatAsString(this.from) : '--'
397
+ },
398
+ {
399
+ label: 'Para:',
400
+ value: this.para && this.para.length ? formatAsString(this.para) : '--'
401
+ },
402
+ {
403
+ label: 'Assunto:',
404
+ value: this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
405
+ },
406
+ {
407
+ label: 'Data:',
408
+ value: this.formataDataHora(this.dataHora) || '--'
409
+ },
410
+ ]
411
+
412
+ if (this.copia && this.copia.length) {
413
+ infos.splice(2, 0, {
414
+ label: `${this.dicionario.tit_copia}:` || 'Copia:',
415
+ value: formatAsString(this.copia)
416
+ })
417
+ }
418
+
419
+ return infos
420
+ },
421
+ filteredFiles() {
422
+ if (!this.anexos || !this.anexos.length) return
423
+
424
+ return this.anexos.filter(anexo => {
425
+ return !this.html.includes(anexo.name);
426
+ })
427
+ },
428
+ returnAuthorName() {
429
+ if (!this.from || !this.from.length) return this.autor || ''
430
+ const { email, name } = this.from[0]
431
+ if (!name) return email
432
+ if (!email) return name
433
+ if (this.isOpen) return `${name} (${email})`
434
+ return name
435
+ },
436
+ formattedToName() {
437
+ return (name, index, length) => {
438
+ let addVirgulaDps = index < length - 1
439
+ const text = index === 0 ? `Para: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
440
+ return text
441
+ }
442
+ },
443
+ formattedCcName() {
444
+ return (name, index, length) => {
445
+ let addVirgulaDps = index < length - 1
446
+ const text = index === 0 ? `${this.dicionario.tit_copia || 'Cópia'}: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
447
+ return text
448
+ }
449
+ }
450
+ },
451
+ watch: {
452
+ isOpen: 'updateIframeContent'
453
+ },
454
+ mounted() {
455
+ this.updateIframeContent();
456
+ this.adjustMaxWidth()
457
+
458
+ if (this.refKey) this.$root.$refs[`${refKey}`] = this
459
+
460
+ setTimeout(() => {
461
+ if (this.isIframeLoading) this.adjustIframeHeight()
462
+ }, 15000);
463
+ },
464
+ methods: {
465
+ openAndScrollToAttachments() {
466
+ if (!this.isOpen) {
467
+ this.scrollToFile = true;
468
+ this.isIframeLoading = true;
469
+ this.isOpen = true;
470
+ } else if (!this.isIframeLoading) {
471
+ this.scrollToAttachments();
472
+ } else {
473
+ this.scrollToFile = true;
474
+ }
475
+ },
476
+ scrollToAttachments() {
477
+ this.$nextTick(() => {
478
+ const files = this.$el.querySelector('.email-files');
479
+ if (files) {
480
+ files.scrollIntoView({ behavior: 'smooth', block: 'center' });
481
+ }
482
+ });
483
+ },
484
+ handleTryAgain() {
485
+ this.isOpen = true
486
+ this.isIframeLoading = true
487
+ this.hasError = false
488
+
489
+ this.$nextTick(this.updateIframeContent())
490
+ },
491
+
492
+ emitReplyEmail() {
493
+ if(!this.hasReplyEmail) return
494
+
495
+ this.$emit('reply-email', {
496
+ html: this.html,
497
+ mensagem: this.mensagem,
498
+ assunto: this.assunto,
499
+ from: this.from,
500
+ para: this.para,
501
+ dataHora: this.dataHora,
502
+ anexos: this.anexos,
503
+ status: this.status,
504
+ status_msg: this.status_msg,
505
+ copia: this.copia,
506
+ origem: this.origem,
507
+ autor: this.autor,
508
+ id_lig: this.id_lig,
509
+ token_cliente: this.token_cliente,
510
+ infos: this.infos,
511
+ });
512
+ },
513
+
514
+ gerarMensagemEstilizada(msg) {
515
+ try {
516
+ const currentStyles = [
517
+ { tagAbertura: "<i>", tagFechamento: "</i>", find: /_(.*?)_/g },
518
+ { tagAbertura: "<b>", tagFechamento: "</b>", find: /\*(.*?)\*/g },
519
+ { tagAbertura: "<del>", tagFechamento: "</del>", find: /~(.*?)~/g }
520
+ ]
521
+
522
+ const isLetterOrUnderscore = (char) => {
523
+ return /[a-zA-Z_]/.test(char)
524
+ }
525
+
526
+ const isValidMatch = (message, fullMatch, startIndex) => {
527
+ const beforeChar = message[startIndex - 1]
528
+ const afterChar = message[startIndex + fullMatch.length]
529
+ return (
530
+ (beforeChar === undefined || !isLetterOrUnderscore(beforeChar)) &&
531
+ (afterChar === undefined || !isLetterOrUnderscore(afterChar))
532
+ )
533
+ }
534
+
535
+ let message = msg
536
+
537
+ for (const { tagAbertura, tagFechamento, find } of currentStyles) {
538
+ let match
539
+ while ((match = find.exec(message)) !== null) {
540
+ const fullMatch = match[0]
541
+ const content = match[1]
542
+ const startIndex = match.index
543
+
544
+ if (isValidMatch(message, fullMatch, startIndex)) {
545
+ const endIndex = startIndex + fullMatch.length
546
+ const replacedContent = `${tagAbertura}${content}${tagFechamento}`
547
+ message = message.slice(0, startIndex) + replacedContent + message.slice(endIndex)
548
+ }
549
+ }
550
+ }
551
+
552
+ return message
553
+ } catch (err) {
554
+ console.error('Erro ao gerar mensagem estilizada: ', err)
555
+ return msg
556
+ }
557
+ },
558
+ updateIframeContent() {
559
+ this.$nextTick(() => {
560
+ if (this.isOpen && this.isIframeLoading) {
561
+ const iframe = this.$refs.emailIframe;
562
+ if (!iframe) {
563
+ console.warn('Iframe not found');
564
+ this.isIframeLoading = false
565
+ return
566
+ }
567
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
568
+ if (!doc) {
569
+ console.warn('Document not found in iframe');
570
+ this.isIframeLoading = false
571
+ return
572
+ }
573
+ let content = this.html || ''
574
+ if(!content || !content.length) {
575
+ console.warn('No content to display in iframe');
576
+ this.isIframeLoading = false
577
+ return
578
+ }
579
+ if (!/<[a-z][\s\S]*>/i.test(content)) {
580
+ content = content.replace(/\n/g, '<br>');
581
+ content = this.gerarMensagemEstilizada(content)
582
+ content = `<p>${content}</p>`;
583
+ }
584
+
585
+ doc.open();
586
+ doc.write(content);
587
+ doc.close();
588
+
589
+ const images = doc.getElementsByTagName('img');
590
+ let imagesLoaded = 0;
591
+
592
+ const imageLoadHandler = () => {
593
+ imagesLoaded++;
594
+ if (imagesLoaded === images.length) {
595
+ this.adjustIframeHeight();
596
+ }
597
+ };
598
+
599
+ if (images.length === 0) {
600
+ this.adjustIframeHeight();
601
+ } else {
602
+ for (let img of images) {
603
+ img.addEventListener('load', imageLoadHandler);
604
+ img.addEventListener('error', imageLoadHandler);
605
+ }
606
+ }
607
+ }
608
+ });
609
+ },
610
+ adjustIframeHeight() {
611
+ this.$nextTick(() => {
612
+ const iframe = this.$refs.emailIframe;
613
+ const emailParent = this.$refs.emailIframeParent
614
+ if (iframe && emailParent) {
615
+ setTimeout(() => {
616
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
617
+ const margin = 20
618
+ const value = doc.documentElement.offsetHeight + margin
619
+ if (value === 0 || doc.documentElement.querySelector('body').innerHTML === '') {
620
+ this.errorCount++
621
+ if (this.errorCount > 3) {
622
+ this.hasError = true
623
+ if (this.isIframeLoading) this.isIframeLoading = false
624
+ return
625
+ }
626
+ this.isIframeLoading = true
627
+ this.updateIframeContent()
628
+ return
629
+ }
630
+ if (this.hasError || this.errorCount > 0) {
631
+ this.hasError = false
632
+ this.errorCount = 0
633
+ }
634
+ iframe.style.height = `${value}px`;
635
+ emailParent.style.minHeight = `${value}px`
636
+ if (this.scrollToFile) {
637
+ this.scrollToFile = false;
638
+ this.scrollToAttachments();
639
+ }
640
+ }, 100)
641
+ }
642
+
643
+ if (this.isIframeLoading) this.isIframeLoading = false
644
+ });
645
+ },
646
+ toggleShowInfos() {
647
+ this.showInfos = !this.showInfos;
648
+ if (this.showInfos) {
649
+ this.$nextTick(() => {
650
+ this.adjustTopPosition();
651
+ });
652
+ }
653
+ },
654
+ adjustTopPosition() {
655
+ const ulElement = this.$refs.emailToInfos;
656
+ if (!ulElement) return
657
+ const ulHeight = ulElement.offsetHeight;
658
+ const maxHeight = 300
659
+ const finalHeight = ulHeight < maxHeight ? ulHeight : maxHeight
660
+ ulElement.style.bottom = `-${finalHeight}px`;
661
+ },
662
+ toggleIsOpen() {
663
+ this.isOpen = !this.isOpen;
664
+ if (this.isOpen) {
665
+ this.isIframeLoading = true;
666
+ } else {
667
+ this.actionsOpen = false;
668
+ this.openMessage = false;
669
+ this.showInfos = false;
670
+ this.scrollToFile = false;
671
+ }
672
+ },
673
+ adjustMaxWidth() {
674
+ this.$nextTick(() => {
675
+ const toContainer = this.$refs.emailToContainer
676
+ const dateContainer = this.$refs.emailDate
677
+ if (!toContainer || !dateContainer) return
678
+ toContainer.style.maxWidth = `calc(100% - ${dateContainer.offsetWidth}px)`
679
+ })
680
+ },
681
+ toggleActions() {
682
+ this.actionsOpen = !this.actionsOpen;
683
+ },
684
+ toggleOpenMessage() {
685
+ if (this.showRawMessageInsideEmail) {
686
+ this.openMessage = !this.openMessage;
687
+ }
688
+
689
+ this.$emit('open-message', {
690
+ dicionario: this.dicionario,
691
+ from: this.from,
692
+ para: this.para,
693
+ html: this.html,
694
+ assunto: this.assunto,
695
+ dataHora: this.dataHora,
696
+ mensagem: this.mensagem,
697
+ anexos: this.filteredFiles,
698
+ dataServer: this.dataServer,
699
+ dominio: this.dominio
700
+ })
701
+ },
702
+ closeActions() {
703
+ this.actionsOpen = false;
704
+ },
705
+ returnMainValue() {
706
+ if (this.isMainEmail) return this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
707
+ return ''
708
+ },
709
+ openByItem(event) {
710
+ if (this.isOpen) return;
711
+
712
+ event.preventDefault();
713
+ event.stopPropagation();
714
+
715
+ this.toggleIsOpen();
716
+ },
717
+ returnParams(params) {
718
+ const defaultParams = {
719
+ message: this.mensagem,
720
+ };
721
+
722
+ if (!params) return defaultParams;
723
+
724
+ const keys = params.instanceKeys.split("|");
725
+ if (!keys || !keys.length)
726
+ return {
727
+ defaultParams,
728
+ ...params.values,
729
+ };
730
+
731
+ const customParams = { ...params.values };
732
+ keys.forEach((key) => {
733
+ if (this[key]) customParams[key] = this[key];
734
+ else console.warn(`Cant find ${key} on 'this' instance`);
735
+ });
736
+
737
+ return Object.keys(customParams).length ? customParams : defaultParams;
738
+ }
739
+ }
740
+ };
741
+ </script>