huangyinfeng
6 天以前 a9a03d64cf190188d3db04d14970fc0908b03491
提交 | 用户 | age
00fe0e 1 <template>
ccfd07 2   <div class="p-3">
H 3     <a-spin :spinning="loading" class="p-1">
4       <a-form ref="formRef" :label-col="{ span: 2 }" :wrapper-col="{ span: 24 }" :model="modelRef">
5         <a-form-item :wrapper-col="{ span: 8 }">
6           <div style="display: flex; justify-content: space-evenly">
7             <a-button type="primary" shape="round" @click="fnHandleSubmit(modelRef)">发送</a-button>
8             <a-button shape="round" @click="fnSaveMailDrafts">存草稿</a-button>
9             <a-button shape="round" @click="fnPreview">预览</a-button>
10             <a-button shape="round">提交审批</a-button>
11             <a-button shape="round">取消</a-button></div
12           >
13         </a-form-item>
14         <a-form-item label="发件人" v-bind="validateInfos.sender" :wrapper-col="{ span: 12 }">
15           <a-select
16             v-model:value="modelRef.sender"
17             placeholder="选择发件人"
18             show-search
19             :field-names="{ label: 'email', value: 'email' }"
20             :options="state.senderList"
21             :filter-option="fnFilterOption"
22           >
23           </a-select>
24         </a-form-item>
25         <a-form-item label="收件人" v-bind="validateInfos.recipients" :wrapper-col="{ span: 18 }">
26           <a-row>
27             <a-col class="gutter-row" :span="16">
28               <a-select
29                 mode="tags"
30                 placeholder="请选择收件人或者输入收件人邮箱"
31                 v-model:value="modelRef.recipients"
32                 :options="state.recipientsList"
63d608 33                 :field-names="{ label: 'email', value: 'email' }"
ccfd07 34                 :maxTagCount="4"
H 35                 @search="fetchUser"
00fe0e 36               >
ccfd07 37                 <template #tagRender="{ label, closable, onClose, option }">
H 38                   <a-tag
39                     :closable="closable"
40                     style="margin-right: 3px"
41                     @close="onClose"
42                     :color="validateEmail(label) ? 'default' : 'red'"
00fe0e 43                   >
ccfd07 44                     {{ label }}&nbsp;&nbsp;
H 45                   </a-tag>
46                 </template>
47               </a-select>
48             </a-col>
49             <a-col
50               class="gutter-row"
51               :span="2"
52               style="display: flex; align-items: center; justify-content: center"
53             >
54               <plus-circle-outlined
55                 style="color: rgb(0 0 0 / 45%)"
56                 @click="fnHandleSelect('recipients')"
57               />
58             </a-col>
59             <a-col class="gutter-row" :span="1">
60               <a-form-item-rest>
61                 <a-button
62                   shape="round"
63                   type="link"
64                   block
65                   size="small"
66                   @click="ccCheckboxChange($event)"
67                 >
68                   {{ !isSecretDeliveryPerson ? '抄送' : '取消抄送' }}
69                 </a-button>
70               </a-form-item-rest>
71             </a-col>
72             <a-col class="gutter-row" :span="1">
73               <a-form-item-rest>
74                 <a-button
75                   shape="round"
76                   type="link"
77                   block
78                   size="small"
79                   @click="bccCheckboxChange($event)"
80                 >
81                   {{ !isCRecipient ? '密送' : '取消密送' }}
82                 </a-button>
83               </a-form-item-rest>
84             </a-col>
85           </a-row>
86         </a-form-item>
87         <span style="position: relative; top: -18px; left: 9%" v-if="modelRef.recipients.length">
88           {{ userParticulars && `${userParticulars.userName}<${userParticulars.email}` }}>
89           <span v-if="!userParticulars.title" style="margin-right: 10px; margin-left: 5px">
90             暂未查询到该客户的当地时间
91             <a @click="fnHandleTimeZone(userParticulars, 'add')">补充时区</a>
92           </span>
93           <span v-else>
94             {{ userParticulars.title }}
95             <a @click="fnHandleTimeZone(userParticulars, 'update')">时区不对?</a>
00fe0e 96           </span>
H 97
ccfd07 98           <a v-if="modelRef.recipients.length > 2">查看全部</a>
H 99         </span>
00fe0e 100
ccfd07 101         <a-form-item
H 102           label="抄送人"
103           v-bind="validateInfos.ccRecipients"
104           v-if="isSecretDeliveryPerson"
105           :wrapper-col="{ span: 18 }"
106         >
107           <a-row>
108             <a-col class="gutter-row" :span="16">
109               <a-select
110                 mode="tags"
111                 placeholder="请选择抄送人或者输入抄送人邮箱"
74a35f 112                 v-model:value="modelRef.ccRecipients"
ccfd07 113                 :options="state.recipientsList"
63d608 114                 :field-names="{ label: 'email', value: 'email' }"
ccfd07 115                 :maxTagCount="4"
H 116               >
117                 <template #tagRender="{ label, closable, onClose }">
118                   <a-tag
119                     :closable="closable"
120                     style="margin-right: 3px"
121                     @close="onClose"
122                     :color="validateEmail(label) ? 'default' : 'red'"
123                   >
124                     {{ label }}&nbsp;&nbsp;
125                   </a-tag>
126                 </template>
127               </a-select>
128             </a-col>
129             <a-col
130               class="gutter-row"
131               :span="2"
132               style="display: flex; align-items: center; justify-content: center"
133             >
134               <plus-circle-outlined
135                 style="color: rgb(0 0 0 / 45%)"
136                 @click="fnHandleSelect('ccRecipients')"
137               />
138             </a-col>
139           </a-row>
140         </a-form-item>
141         <a-form-item
142           label="密送人"
143           v-bind="validateInfos.bccRecipients"
144           v-if="isCRecipient"
145           :wrapper-col="{ span: 18 }"
146         >
147           <a-row>
148             <a-col class="gutter-row" :span="16">
149               <a-select
150                 mode="tags"
151                 placeholder="请选择抄送人或者输入抄送人邮箱"
152                 v-model:value="modelRef.bccRecipients"
153                 :options="state.recipientsList"
63d608 154                 :field-names="{ label: 'email', value: 'email' }"
ccfd07 155                 :maxTagCount="4"
H 156               >
157                 <template #tagRender="{ label, closable, onClose }">
158                   <a-tag
159                     :closable="closable"
160                     style="margin-right: 3px"
161                     @close="onClose"
162                     :color="validateEmail(label) ? 'default' : 'red'"
163                   >
164                     {{ label }}&nbsp;&nbsp;
165                   </a-tag>
166                 </template>
167               </a-select>
168             </a-col>
169             <a-col
170               class="gutter-row"
171               :span="2"
172               style="display: flex; align-items: center; justify-content: center"
173             >
174               <plus-circle-outlined
175                 style="color: rgb(0 0 0 / 45%)"
176                 @click="fnHandleSelect('bccRecipients')"
177               />
178             </a-col>
179           </a-row>
180         </a-form-item>
181         <div
182           style="position: relative; top: -20px; left: 9%; color: #909090; font-size: 12px"
183           v-if="modelRef.recipients.length"
184         >
185           {{ `${userLength}/100 收件人、抄送人和密送的联系人总数不可超过100` }}
186         </div>
187         <a-form-item label="主题" :wrapper-col="{ span: 12 }" :label-col="{ span: 2 }">
188           <a-input placeholder="请输入邮件主题" v-model:value="modelRef.subject" />
189         </a-form-item>
190         <a-form-item
191           v-bind="validateInfos.content"
192           :wrapper-col="{ span: 24 }"
193           :label-col="{ span: 2 }"
194         >
63d608 195           <Tinymce v-model="modelRef.content" @change="fnChangeContent"></Tinymce>
ccfd07 196         </a-form-item>
H 197       </a-form>
198     </a-spin>
199     <SelectUser
200       ref="selectUserRef"
201       v-model="openSelectUser"
202       :selectIds="selectIds"
203       :idName="idName"
204       :title="selectUserTitle"
205       @updateData="fnSelectUser"
206     />
207     <a-modal
208       v-model:open="openTimeZone"
209       :title="`${titleTimeZone}时区`"
210       :confirm-loading="confirmLoading"
211       @ok="fnHandleTimeZoneOk"
212     >
213       <a-form
214         ref="formTimeZoneRef"
215         :label-col="{ span: 6 }"
216         :wrapper-col="{ span: 24 }"
217         :model="modelRef"
218       >
219         <a-form-item label="国家地区:" :wrapper-col="{ span: 12 }">
220           <a-select
221             v-model:value="modelRef.sender"
222             placeholder="选择国家地区"
223             show-search
224             :field-names="{ label: 'name', value: 'id' }"
225             :options="state.data"
226           >
227           </a-select>
228         </a-form-item>
229         <a-form-item label="时区:" :wrapper-col="{ span: 12 }">
230           <a-select
231             v-model:value="modelRef.sender"
232             placeholder="选择时区"
233             show-search
234             :field-names="{ label: 'name', value: 'id' }"
235             :options="state.data"
236           >
237           </a-select>
238         </a-form-item>
239         <a-form-item :label-col="{ span: 6 }">
240           <a-row>
241             <a-col span="6"> </a-col>
242             <a-col span="18">
243               <div style="color: #909090"
244                 >当地实时时间根据时区信息显示<br />
245                 国家地区/时区信息在客户资料-特征信息查看</div
246               >
247             </a-col>
248           </a-row>
249         </a-form-item>
250       </a-form>
251     </a-modal>
252   </div>
00fe0e 253 </template>
H 254
255 <script lang="ts" setup>
ccfd07 256   name: 'Edit';
H 257   import { useDesign } from '@/hooks/web/useDesign';
00fe0e 258
63d608 259   import { ref, reactive, computed, onMounted } from 'vue';
00fe0e 260   import { useMessage } from '@/hooks/web/useMessage';
H 261   import { Tinymce } from '@/components/Tinymce';
262   import { PlusCircleOutlined } from '@ant-design/icons-vue';
12f730 263   import SelectUser from '../components/SelectUser/index.vue';
00fe0e 264   import { Form } from 'ant-design-vue';
H 265   const modelRef = reactive({
266     sender: '',
267     recipients: [],
268     ccRecipients: [],
269     bccRecipients: [],
ccfd07 270     attachmentList: [],
00fe0e 271     subject: '',
H 272     content: '',
273   });
ccfd07 274   const loading = ref(false);
00fe0e 275   const rulesRef = reactive({
H 276     sender: [
277       {
278         required: true,
279         message: '发件人不能为空',
280       },
281     ],
282     recipients: [
283       {
284         required: true,
285         message: '收件人不能为空',
286       },
287     ],
288     content: [
289       {
290         required: true,
291         message: '内容不能为空',
292       },
293     ],
294   });
63d608 295   const TYPE = computed(() => {
H 296     return router.currentRoute.value.query.type || 'send';
297   });
298   onMounted(() => {
299     fnGetRecipientsList();
300     if (TYPE.value === 'reply') {
301       fuGetReplyEmailData();
302     }
a9a03d 303     if (TYPE.value === 'edit') {
H 304       fuGetEditEmailData();
305     }
63d608 306   });
00fe0e 307   const useForm = Form.useForm;
H 308   const { validate, validateInfos } = useForm(modelRef, rulesRef);
309
310   const formRef = ref();
311
312   let isSecretDeliveryPerson = ref(false);
313
314   let isCRecipient = ref(false);
315   const handleCheckboxChange = (ref, e) => {
316     ref.value = !ref.value;
317   };
318
319   const ccCheckboxChange = (e) => {
320     handleCheckboxChange(isSecretDeliveryPerson, e);
321   };
322   const bccCheckboxChange = (e) => {
323     handleCheckboxChange(isCRecipient, e);
324   };
325
326   const { createMessage } = useMessage();
ccfd07 327   import {
H 328     getAccountListApi,
329     sendingMailApi,
330     saveMailDraftsApi,
331     emailListAPi,
a9a03d 332     getMailInfoApi,
ccfd07 333   } from '@/api/email/userList';
00fe0e 334   // 定义状态管理对象
H 335   const state = reactive({
336     data: [],
337     fetching: false,
338     error: null,
ccfd07 339     senderList: [],
H 340     recipientsList: [],
00fe0e 341   });
H 342
343   // 获取用户列表的函数
344   const fnGetUserList = async (params) => {
345     try {
346       state.fetching = true;
ccfd07 347       const res = await getAccountListApi();
H 348       console.log(res, 'res');
00fe0e 349
ccfd07 350       if (res && res.data && Array.isArray(res.data)) {
H 351         state.senderList = res.data;
00fe0e 352       } else {
H 353         console.error('Invalid response format:', res);
354       }
355     } catch (error) {
356       console.error('Failed to fetch user list:', error);
357     } finally {
358       state.fetching = false;
359     }
360   };
361
362   // 初始化用户数据
363   const fetchData = async () => {
364     await fnGetUserList({ page: 1, pageSize: 30 });
365   };
366   console.log(state.data, 'state.data');
367   // 调用初始化函数
368   fetchData();
369
370   const fnFilterOption = (input: string, option: any) => {
ccfd07 371     return option.email.toLowerCase().indexOf(input.toLowerCase()) >= 0;
00fe0e 372   };
H 373
374   const openSelectUser = ref(false);
375   const selectUserTitle = ref('选择收件人');
376   const selectIds = ref([]);
377   const idName = ref('');
378   const fnHandleSelect = (e) => {
379     if (e === 'recipients') {
380       selectUserTitle.value = '选择收件人';
381       idName.value = e;
382     }
383     if (e === 'ccRecipients') {
384       selectUserTitle.value = '选择抄送人';
385       idName.value = e;
386     }
387     if (e === 'bccRecipients') {
388       selectUserTitle.value = '选择密送人';
389       idName.value = e;
390     }
391     selectIds.value = modelRef[e];
392     openSelectUser.value = true;
393   };
394
395   function fnChangeContent(e) {
396     modelRef.content = e.content;
ccfd07 397     modelRef.attachmentList = e.attachmentList;
00fe0e 398   }
H 399
400   function fnBuildingCommitData() {
401     return {
402       sender: modelRef.sender,
403       receiver: modelRef.recipients,
404       cc: modelRef.ccRecipients,
405       bcc: modelRef.bccRecipients,
406       subject: modelRef.subject,
407       content: modelRef.content,
ccfd07 408       attachmentList: '',
00fe0e 409       docCode: docCode.value,
H 410     };
411   }
412   const docCode = ref('');
413   import { Modal } from 'ant-design-vue';
414   function fnHandleSubmit(values: any) {
415     validate()
416       .then((res) => {
417         if (!modelRef.subject) {
418           Modal.confirm({
419             title: '提示',
420             content: '邮件主题为空,确定要发送吗?',
421             onOk() {
422               pushSendingMail();
423             },
424             onCancel() {},
425           });
426         } else {
427           pushSendingMail();
428         }
429       })
430       .catch((error) => {
431         createMessage.error('表单验证失败');
432       });
433   }
ccfd07 434   import { useRouter } from 'vue-router';
H 435   const router = useRouter();
00fe0e 436   function pushSendingMail() {
H 437     const data = fnBuildingCommitData();
ccfd07 438     loading.value = true;
H 439     sendingMailApi(data)
440       .then((res) => {
74a35f 441         loading.value = false;
ccfd07 442         if (res.code === 0) {
H 443           createMessage.success(res.msg);
444           router.push('/email/list');
445         }
446       })
447       .catch((error) => {
448         loading.value = false;
449       });
00fe0e 450   }
74a35f 451   function fnPreview() {
H 452     router.push({ path: '/preview/index', query: { docCode: docCode.value } });
453   }
00fe0e 454
H 455   function fnSaveMailDrafts() {
456     const data = fnBuildingCommitData();
ccfd07 457     loading.value = true;
H 458
459     saveMailDraftsApi(data)
460       .then((res) => {
461         loading.value = false;
74a35f 462         if (res.code == 0) {
ccfd07 463           docCode.value = res.data.docCode;
H 464           createMessage.success('保存成功');
465         }
466       })
467       .catch((error) => {
468         loading.value = false;
469       });
00fe0e 470   }
H 471
472   const fnSelectUser = (e) => {
473     modelRef[e.idName] = e.selectedRowKeys;
474   };
475
476   const userLength = computed(() => {
477     return (
478       modelRef.recipients.length + modelRef.ccRecipients.length + modelRef.bccRecipients.length
479     );
480   });
481
482   interface Recipient {
483     value: string;
484     email: string;
485     title: string;
486   }
487
488   const userParticulars = computed<Recipient | null>(() => {
489     const recipientId = modelRef.recipients?.[0];
490     if (!recipientId) {
491       console.error('Recipient ID is not defined.');
492       return { value: '', email: '', title: '' };
493     }
494     // 使用 find 方法查找匹配项
ccfd07 495     const foundItem = state.recipientsList.find((item) => item.email === recipientId);
00fe0e 496
H 497     // 返回找到的项,如果未找到则返回 null
498     return foundItem || { value: '', email: '', title: '' };
499   });
500   const fnHandleTimeZone = (e, type) => {
501     console.log('fnHandleTimeZone');
502     if (type == 'add') {
503       titleTimeZone.value = '添加';
504       typeTimeZone.value = 1;
505     } else {
506       titleTimeZone.value = '修改';
507       typeTimeZone.value = 2;
508     }
509     openTimeZone.value = true;
510   };
511
512   const openTimeZone = ref<boolean>(false);
513   const confirmLoading = ref<boolean>(false);
514   const titleTimeZone = ref<string>('添加');
515   const typeTimeZone = ref<number>(1);
516
517   const fnHandleTimeZoneOk = () => {
518     confirmLoading.value = true;
519     setTimeout(() => {
520       openTimeZone.value = false;
521       confirmLoading.value = false;
522     }, 2000);
523   };
ccfd07 524
63d608 525   function fnGetRecipientsList() {
H 526     emailListAPi({ key: '' }).then((body) => {
527       state.recipientsList = body.data;
528     });
ccfd07 529   }
H 530   // 邮箱校验正则表达式
531   const validateEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
532   import { debounce } from 'lodash-es';
533   let lastFetchId = 0;
534
535   const fetchUser = debounce((value) => {
536     lastFetchId += 1;
537     const fetchId = lastFetchId;
538     state.data = [];
539     state.fetching = true;
540     emailListAPi({ key: value }).then((body) => {
541       if (fetchId !== lastFetchId) {
542         // for fetch callback order
543         return;
544       }
545
546       state.recipientsList = body.data;
547       state.fetching = false;
548     });
549   }, 300);
a9a03d 550   // 编辑
H 551   function fuGetEditEmailData() {
552     getMailInfoApi({ docCode: router.currentRoute.value.query.docCode })
553       .then((res) => {
554         modelRef.sender = res.data.sender;
555         modelRef.recipients = res.data.receiver;
556         modelRef.subject = res.data.subject;
557         modelRef.content = res.data.content;
558       })
559       .catch(() => {});
560   }
63d608 561
H 562   // 回复
563   function fuGetReplyEmailData() {
564     getMailInfoApi({ docCode: router.currentRoute.value.query.docCode })
565       .then((res) => {
a9a03d 566         console.log(ref.data, '---3022');
H 567         modelRef.sender = res.data.receiver[0];
568         modelRef.recipients = [res.data.sender];
569         modelRef.subject = 'Re:' + res.data.subject;
570         modelRef.content = setContent(res.data);
63d608 571         // tableRowData.value = res.data;
H 572       })
573       .catch(() => {});
574     console.log('----------------4');
575   }
576   const setContent = (row) => {
a9a03d 577     const text = `<div style=\"font-size: 12px; font-family: Arial Narrow,serif; padding: 2px 0 2px 0;\">------------------&nbsp;Original&nbsp;------------------</div>\n<div style=\"font-size: 12px; background: #efefef; padding: 8px;\">\n<div><strong>From:&nbsp;</strong>&nbsp;${row.sender} &lt;<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.sender}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.sender}</a>&gt;</div>\n<div><strong>Send time:&nbsp;</strong>&nbsp;${row.createTime}</div>\n<div><strong>To:&nbsp;</strong>&nbsp;${row.userName} &lt;<a style=\"color: #1e7bf9; text-decoration: none;\" href=\"mailto:${row.receiver}\" target=\"_blank\" rel=\"noopener noreferrer\">${row.receiver}</a>&gt;</div>\n<div><strong>Subject:&nbsp;</strong> ${row.subject}</div>\n</div>`;
H 578     return text + row.content;
63d608 579   };
00fe0e 580 </script>
H 581 <style lang="less" scoped>
582   @prefix-cls: ~'@{namespace}-email';
583   .@{prefix-cls} {
584     .splitpanes__pane {
585       display: flex;
586       align-items: stretch;
587       justify-content: center;
588       // background-color: var(--component-background-color);
589     }
590   }
591 </style>