Sanakey
5 天以前 2af71bcf522c485ea005184c977986374a7dcc4a
提交 | 用户 | age
00fe0e 1 <template>
63d608 2   <div style="overflow: auto">
H 3     <div v-if="groupedEmails.length != 0">
4       <div v-for="(item, index) in groupedEmails" :key="index">
5         <div class="span-title">{{ `${item.name}(${item.data.length})` }}</div>
6         <vxe-table
7           ref="vxeTableRef"
8           style="margin: 10px 0"
9           :showHeader="false"
10           :data="item.data"
11           size="small"
12           min-height="40px"
13           :row-config="{ isCurrent: true, isHover: true }"
14           :menu-config="tableMenu"
15           @menu-click="contextMenuClickEvent"
16           @cell-click="cellClickEvent"
17           @checkbox-change="selectChangeEvent"
18         >
19           <vxe-column type="checkbox" width="30"></vxe-column>
20           <vxe-column field="sender" title="发件人" data-index="sender" min-width="300px">
21             <template #default="{ row }">
22               <div style="display: flex; align-items: center">
23                 <div
24                   v-if="row.mailType != 0"
25                   class="dot"
26                   :class="row.readFlag ? 'dot-color' : ''"
27                   @click.stop="fnRowUpdateRead(row)"
28                 ></div>
29                 <a-tooltip placement="bottom">
30                   <template #title>
31                     <span>陌生人</span>
32                   </template>
33                   <a-avatar size="small" style="margin-right: 8px" :src="row.avatar" />
34                 </a-tooltip>
12f730 35
63d608 36                 <a-popover placement="bottom">
H 37                   <template #content>
38                     <div
39                       class="p-2"
40                       style="
41                         display: flex;
42                         align-items: center;
43                         border-bottom: 1px solid rgb(5 5 5 / 6%);
44                       "
45                     >
46                       <a-avatar size="small" style="margin-right: 8px" :src="row.avatar" />
47                       <span style="color: #000; font-weight: 700">{{ row.sender }}</span>
48                       <CopyOutlined />
49                     </div>
50                     <div class="display-flex p-2">
51                       <a-button type="link" size="small">新建客户</a-button>
52                       <a-dropdown>
53                         <a style="margin-right: 5px" class="ant-dropdown-link" @click.prevent>
54                           <DownOutlined />
55                         </a>
56                         <template #overlay>
57                           <a-menu>
58                             <a-menu-item>
59                               <a href="javascript:;">添加到已有客户</a>
60                             </a-menu-item>
61                           </a-menu>
62                         </template>
63                       </a-dropdown>
64                       <a-button type="link" size="small">添加为线索</a-button>
65
66                       <a-dropdown style="margin-right: 5px">
67                         <a style="margin-right: 5px" class="ant-dropdown-link" @click.prevent>
68                           <DownOutlined />
69                         </a>
70                         <template #overlay>
71                           <a-menu>
72                             <a-menu-item>
73                               <a href="javascript:;">添加到通讯录</a>
74                             </a-menu-item>
75                           </a-menu>
76                         </template>
77                       </a-dropdown>
78                       <a-button type="link" size="small">往来邮件</a-button></div
79                     >
80                   </template>
81                   <div class="title-dot" :class="row.readFlag ? 'title-dot-color' : ''">
82                     <span style="font-weight: 700">{{ row.senderName }}</span
83                     ><span style="padding: 0 8px">|</span>
84                     <span style="font-weight: 500">{{ row.sender }}</span>
00fe0e 85                   </div>
63d608 86                 </a-popover>
H 87               </div>
88             </template>
89           </vxe-column>
90           <vxe-column
91             show-overflow
92             field="subject"
93             title="表题"
94             data-index="subject"
95             min-width="250"
96           >
97             <template #default="{ row }">
98               <span
99                 class="title-dot"
100                 :class="row.readFlag ? 'title-dot-color' : ''"
101                 style="font-weight: 500"
102                 >{{ row.subject || '(无主题)' }}</span
103               >
104               -
105               <span style="color: #999">{{ row.subject }}</span>
106             </template>
107           </vxe-column>
108           <vxe-column field="action" title="Action" width="190">
109             <template #default="{ row, rowIndex }">
110               <span style="display: flex; justify-content: space-around">
111                 <span>{{
112                   row.mailType !== 0
113                     ? formatToDateDay(row.receiveTime)
114                     : formatToDateDay(row.createTime)
115                 }}</span>
00fe0e 116
63d608 117                 <TooltipAndDropdown
H 118                   :tooltipTitle="'待处理邮件'"
119                   :initialDropdownOpen="false"
120                   :initialTooltipOpen="false"
121                   :showTooltip="!!row.handleTime"
122                   :row="row"
123                   :docCodeS="[row.docCode]"
124                 />
125                 <span style="margin-left: 5px"><PushpinOutlined @click.stop="fnTagging" /></span>
126               </span>
127             </template>
128           </vxe-column>
129         </vxe-table> 
130         </div
131     ></div>
74a35f 132
63d608 133     <div v-else style="height: 70vh; display: flex; align-items: center; justify-content: center">
H 134       <a-empty />
00fe0e 135     </div>
ccfd07 136     <DrawerDetail
H 137       ref="drawerDetailRef"
138       v-model="openDrawerDetail"
139       :mailId="rowMailId"
74a35f 140       :selectAllRow="selectRow"
ccfd07 141       :allList="dataSource"
H 142     />
74a35f 143     <a-dropdown :trigger="['click']" placement="bottomLeft" ref="dropdownRefs"> </a-dropdown>
00fe0e 144   </div>
H 145 </template>
146
147 <script lang="ts" setup>
148   name: 'ListPageTable';
149   import {
150     FieldTimeOutlined,
151     PushpinOutlined,
152     CopyOutlined,
153     DownOutlined,
154   } from '@ant-design/icons-vue';
155
12f730 156   import { ref, watch, defineProps, defineEmits, computed, defineExpose, inject } from 'vue';
00fe0e 157
H 158   // 定义属性
159   interface Props {
12f730 160     pageList: [];
00fe0e 161   }
12f730 162   const props = defineProps<Props>();
00fe0e 163
12f730 164   const groupedEmails = ref<GroupedDataItem[]>([]);
00fe0e 165
12f730 166   const dataSource = ref([]);
H 167   watch(
168     () => props.pageList,
169     (newValue) => {
63d608 170       dataSource.value = newValue || [];
H 171       groupedEmails.value = groupEmailsByDate(newValue || []);
12f730 172     },
H 173   );
00fe0e 174   import dayjs from 'dayjs';
H 175   import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
176   import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
177   import isoWeek from 'dayjs/plugin/isoWeek';
178   dayjs.extend(isSameOrAfter);
179   dayjs.extend(isSameOrBefore);
180   dayjs.extend(isoWeek);
181
182   interface EmailItem {
183     id: number;
184     subject: string;
185   }
186
187   // 确保 groupedData 的结构正确且 data 是 EmailItem 类型的数组
188   interface GroupedDataItem {
189     key: string;
190     data: EmailItem[];
191     name: string;
192   }
193
194   function groupEmailsByDate(dataSource) {
195     const today = dayjs();
196     const yesterday = dayjs().subtract(1, 'day');
197     const startOfWeek = dayjs().startOf('week');
198     const startOfMonth = dayjs().startOf('month');
199     const startOfLastMonth = dayjs().subtract(1, 'month').startOf('month');
200     const endOfLastMonth = dayjs().subtract(1, 'month').endOf('month');
201
202     const groupedData: GroupedDataItem[] = [
203       {
204         data: [],
205         name: '今天',
206         key: 'today',
207       },
208       {
209         data: [],
210         name: '昨天',
211         key: 'yesterday',
212       },
213       {
214         data: [],
215         name: '本周',
216         key: 'thisWeek',
217       },
218       {
219         data: [],
220         name: '这个月',
221         key: 'thisMonth',
222       },
223       {
224         data: [],
225         name: '上个月',
226         key: 'lastMonth',
227       },
228       {
229         data: [],
230         name: '更早',
231         key: 'earlier',
232       },
233     ];
234
235     dataSource.forEach((item: any) => {
236       try {
74a35f 237         const emailDate = dayjs(item.createTime);
00fe0e 238         if (emailDate.isSame(today, 'day')) {
H 239           groupedData[0].data.push(item);
240         } else if (emailDate.isSame(yesterday, 'day')) {
241           groupedData[1].data.push(item);
242         } else if (emailDate.isSameOrAfter(startOfWeek) && emailDate.isBefore(today, 'day')) {
243           groupedData[2].data.push(item);
244         } else if (emailDate.isSameOrAfter(startOfMonth) && emailDate.isBefore(today, 'day')) {
245           groupedData[3].data.push(item);
246         } else if (
247           emailDate.isSameOrAfter(startOfLastMonth) &&
248           emailDate.isSameOrBefore(endOfLastMonth)
249         ) {
250           groupedData[4].data.push(item);
251         } else {
252           groupedData[5].data.push(item);
253         }
254       } catch (error) {
255         console.error(`Error processing item date: ${item.date}`, error);
256       }
257     });
258     // 将结果按中文映射进行返回
259     const result = <{ data: any; name: string; key: string }[]>[];
260     groupedData.forEach((group: { data: any; name: string; key: string }) => {
261       if (group.data.length > 0) {
262         result.push(group);
263       }
264     });
265
266     return result;
267   }
268
269   // 右键菜单
270   const tableMenu = {
271     className: 'my-menus',
272     body: {
273       options: [
274         [
275           {
276             code: 'reply',
277             name: '回复',
278           },
279           { code: 'replyAll', name: '回复全部' },
280           { code: 'replyWithAttachment', name: '带附件回复' },
281           { code: 'replyAllWithAttachment', name: '带附件回复全部' },
282           { code: 'forward', name: '转发' },
283           { code: 'forwardAsAttachment', name: '作为附件转发' },
284           { code: 'distribute', name: '分发' },
285           { code: 'setRemark', name: '设置备注' },
286         ],
287         [
288           { code: 'toHandle', name: '待处理' },
289           { code: 'markAsUnread', name: '标为未读' },
290           { code: 'labelAs', name: '标注为' },
291         ],
292         [
293           { code: 'newRule', name: '新建收发件规则' },
294           { code: 'moveTo', name: '移动到' },
295         ],
296         [
297           { code: 'exportEmail', name: '导出邮件' },
298           { code: 'createFollowUp', name: '建为客户跟进' },
299           { code: 'createSchedule', name: '新建日程' },
300         ],
301         [
302           { code: 'markAsSpam', name: '标为垃圾邮件' },
303           { code: 'delete', name: '删除' },
304         ],
305       ],
306     },
307   };
308
309   function contextMenuClickEvent({ menu, row, column }) {
310     switch (menu.code) {
311       case 'copy':
312         if (row && column) {
313         }
314         break;
315       default:
316     }
317   }
67287b 318   const vxeTableRef = ref();
H 319   function fnSelectAll(is) {
320     vxeTableRef.value.forEach((row) => {
321       row.setAllCheckboxRow(is);
322     });
ccfd07 323     selectChangeEvent();
67287b 324   }
00fe0e 325
12f730 326   function selectChangeEvent() {
H 327     const isAll = getCheckboxRecords().length === dataSource.value.length;
328     const data = {
329       isAll,
330       records: getCheckboxRecords(),
331     };
332     emit('updateSelectAll', data);
67287b 333   }
H 334   function getCheckboxRecords() {
335     const list = new Set();
336
337     vxeTableRef.value.forEach((row) => {
338       const records = row.getCheckboxRecords(); // 假设该方法返回一个数组
339       if (Array.isArray(records)) {
340         // 确保 records 是数组
341         records.forEach((record) => list.add(record)); // 将记录添加到 Set 中
342       }
343     });
344
345     return Array.from(list); // 将 Set 转换回数组
346   }
00fe0e 347   // 操作row
H 348   function fnProcessingTime(row) {
349     console.log(row);
350   }
351   function fnTagging(row) {
352     console.log(row);
353   }
354   import DrawerDetail from './drawerDetail.vue';
355   // 详情内容
356   const openDrawerDetail = ref(false);
ccfd07 357   const rowMailId = ref('');
74a35f 358   const selectRow = ref([]);
00fe0e 359   const cellClickEvent = (event) => {
74a35f 360     selectRow.value = [];
ccfd07 361     rowMailId.value = event.row.docCode;
74a35f 362     selectRow.value.push({ docCode: event.row.docCode });
00fe0e 363     openDrawerDetail.value = true;
H 364   };
67287b 365
12f730 366   // 更新祖父组件数据
H 367   const getDataList = inject('getDataList');
368   console.log(getDataList, '0000004');
369
74a35f 370   import { updateReadApi, updateHandleAPi } from '@/api/email/userList';
12f730 371   // 标志未读/经读
H 372   function fnRowUpdateRead(row) {
373     const data = {
374       status: !row.readFlag,
375       list: [row.docCode],
376     };
377     pushReadApi(data);
378   }
379   function pushReadApi(params) {
380     updateReadApi(params).then((res) => {
381       if (res.code == 0) {
382         //
ccfd07 383         getDataList({});
12f730 384       }
H 385     });
386   }
387   const emit = defineEmits(['selectAll', 'updateSelectAll']);
67287b 388   defineExpose({
H 389     fnSelectAll,
390   });
74a35f 391
H 392   import TooltipAndDropdown from './TooltipAndDropdown .vue';
393   import { formatToDateDay } from '@/utils/dateUtil';
00fe0e 394 </script>
H 395 <style scoped lang="less">
396   .display-flex {
397     display: flex;
398     align-items: center;
399     justify-content: space-between;
400   }
401
402   .head {
403     display: flex;
404     justify-content: space-between;
405     width: 100%;
406     border-bottom: 1px solid rgb(5 5 5 / 6%);
407
408     /* 增加选择器特异性 */
409     & .left {
410       width: 20%;
411
412       & .left-box {
413         display: flex;
414         align-items: center;
415         justify-content: space-flex-start;
416         width: 100%;
417
418         & .icon {
419           margin-right: 15px;
420           font-size: 16px;
421         }
422       }
423     }
424
425     & .right {
426       display: flex;
427       align-items: center;
428     }
429   }
430
431   .left-bt {
432     display: flex;
433     align-items: center;
434     justify-content: center;
435     padding-left: 27px;
436     background: #fffbe6;
437   }
438
439   .span-title {
63d608 440     width: 100%;
H 441     padding: 5px;
00fe0e 442     color: #000;
H 443     font-weight: 700;
63d608 444     text-align: left;
00fe0e 445   }
H 446
447   .table {
448     height: 80vh;
449   }
450
451   .my-menus {
452     background-color: #f8f8f9;
453   }
12f730 454   // 圆点
H 455   .dot {
456     display: inline-block;
457     width: 8px;
458     height: 8px;
459     margin-right: 10px;
460     border-radius: 50%;
461     background-color: #0a6aff;
462   }
463
464   .dot-color {
465     background-color: #d9d9d9;
466     color: #d9d9d9;
467   }
468
469   .title-dot {
470     color: #0a6aff;
471   }
472
473   .title-dot-color {
474     color: #999;
475   }
00fe0e 476 </style>