提交 | 用户 | age
|
00fe0e
|
1 |
<template> |
H |
2 |
<a-drawer |
|
3 |
v-model:open="drawerOpen" |
|
4 |
:placement="placement" |
a9a03d
|
5 |
width="68%" |
00fe0e
|
6 |
:body-style="{ paddingBottom: '80px' }" |
H |
7 |
:footer-style="{ textAlign: 'right' }" |
|
8 |
@after-open-change="afterOpenChange" |
74a35f
|
9 |
@close="drawerClose" |
00fe0e
|
10 |
> |
H |
11 |
<template #title> |
a9a03d
|
12 |
<div> |
cb21a5
|
13 |
<pageHeadLeft |
H |
14 |
:checked="true" |
|
15 |
:selectAllRow="[{ docCode }]" |
|
16 |
@nextNum="drawerClose" |
|
17 |
></pageHeadLeft> |
a9a03d
|
18 |
</div> |
63d608
|
19 |
</template> |
H |
20 |
<template #extra> |
|
21 |
<div style="font-size: 16px"> |
|
22 |
共<span class="m-1">{{ props.allList.length }}</span |
|
23 |
>封 |
|
24 |
<LeftOutlined style="padding: 0 20px" @click="fnPrev" /> |
|
25 |
<RightOutlined @click="fnNext" /> |
|
26 |
</div> |
|
27 |
</template> |
|
28 |
<template #footer> |
|
29 |
<div style="display: flex"> |
|
30 |
<a-textarea autoSize size="large" v-model:value="content" placeholder="快速回复"> |
|
31 |
<template #prefix> |
|
32 |
<RollbackOutlined style="color: #999" /> |
|
33 |
</template> |
|
34 |
</a-textarea> |
|
35 |
<a-button size="large" type="primary" style="margin-left: 10px" @click="fnQuickReply" |
|
36 |
>发送 |
|
37 |
</a-button> |
|
38 |
</div> |
|
39 |
</template> |
a9a03d
|
40 |
<div class="ct-top" :class="isOpen ? 'isOpenTop' : 'onOpenTop'"> |
H |
41 |
<div class="title"> |
|
42 |
<div class="left"> |
|
43 |
<span style="margin-right: 20px; font-size: 24px; font-weight: 700"> |
|
44 |
<a-tooltip placement="bottom"> |
|
45 |
<template #title> |
|
46 |
<span>{{ tableRowData.subject }}</span> |
|
47 |
</template> |
|
48 |
<div :style="{ maxWidth: isOpen ? '300px' : '600px' }" class="text-ellipsis">{{ |
|
49 |
tableRowData.subject |
|
50 |
}}</div> |
|
51 |
</a-tooltip> |
|
52 |
</span> |
|
53 |
<span style="margin-right: 10px; font-size: 16px"> |
|
54 |
<PushpinOutlined /> |
|
55 |
</span> |
|
56 |
</div> |
|
57 |
<div class="right"> |
|
58 |
<div class="tate">{{ formatToDateDay(tableRowData.receiveTime || tableRowData.updateTime) }}</div> |
|
59 |
<div> |
|
60 |
<a-dropdown-button> |
|
61 |
<div v-if="!isDrafts"> |
|
62 |
<span> |
|
63 |
<a-tooltip placement="bottom"> |
|
64 |
<template #title> |
|
65 |
<span>回复</span> |
|
66 |
</template> |
|
67 |
<LeftOutlined @click="replyEmail(tableRowData, 'reply')" /> |
|
68 |
</a-tooltip> |
|
69 |
</span> |
|
70 |
<a-divider type="vertical" /> |
|
71 |
<span> |
|
72 |
<a-tooltip placement="bottom"> |
|
73 |
<template #title> |
|
74 |
<span>快速回复</span> |
|
75 |
</template> |
|
76 |
<DoubleLeftOutlined /> |
|
77 |
</a-tooltip> |
|
78 |
</span> |
|
79 |
</div> |
|
80 |
<div v-else> |
|
81 |
<span @click="replyEmail(tableRowData, 'edit')">再次编辑</span> |
|
82 |
</div> |
|
83 |
|
|
84 |
<template #overlay> |
|
85 |
<a-menu> |
|
86 |
<a-menu-item key="1"> |
|
87 |
<UserOutlined /> |
|
88 |
1st menu item |
|
89 |
</a-menu-item> |
|
90 |
<a-menu-item key="2"> |
|
91 |
<UserOutlined /> |
|
92 |
2nd menu item |
|
93 |
</a-menu-item> |
|
94 |
<a-menu-item key="3"> |
|
95 |
<UserOutlined /> |
|
96 |
3rd item |
|
97 |
</a-menu-item> |
|
98 |
</a-menu> |
|
99 |
</template> |
|
100 |
</a-dropdown-button> |
|
101 |
</div> |
|
102 |
</div> |
|
103 |
</div> |
|
104 |
</div> |
|
105 |
|
63d608
|
106 |
<div> |
cb21a5
|
107 |
<div class="flex-between"> |
H |
108 |
<div class="ct-left p-2" :class="isOpen ? 'isOpen' : 'onOpen'"> |
a9a03d
|
109 |
<div class="user p-1 f-z-14" style="margin-top: 40px"> |
cb21a5
|
110 |
<div style="display: flex; align-items: center"> |
ccfd07
|
111 |
<a-avatar size="small" style="margin-right: 8px" src="#" /> |
a9a03d
|
112 |
<div> |
H |
113 |
<span>{{ tableRowData.senderName }} {{ `<${tableRowData.sender}>` }}</span> |
|
114 |
</div> |
cb21a5
|
115 |
<span style="margin: 0 10px">发送</span> |
H |
116 |
<a-popover placement="bottom"> |
|
117 |
<template #content> |
|
118 |
<div |
|
119 |
class="p-2" |
|
120 |
style=" |
|
121 |
display: flex; |
|
122 |
align-items: center; |
|
123 |
border-bottom: 1px solid rgb(5 5 5 / 6%); |
|
124 |
" |
|
125 |
> |
|
126 |
<a-avatar size="small" style="margin-right: 8px" src="#" /> |
|
127 |
<span style="color: #000; font-weight: 700"> |
|
128 |
{{ `${tableRowData.receiver}` }}</span |
|
129 |
> |
|
130 |
<CopyOutlined /> |
|
131 |
</div> |
|
132 |
<div class="display-flex p-2"> |
|
133 |
<a-button type="link" size="small">往来邮件</a-button> |
|
134 |
</div> |
|
135 |
</template> |
|
136 |
<a-avatar size="small" style="margin-right: 8px" src="#" /> |
|
137 |
{{ `${tableRowData.receiver}` }}<span>{{ `<${tableRowData.receiver}>` }}</span> |
|
138 |
</a-popover> |
|
139 |
</div> |
a9a03d
|
140 |
<div type="info" class="p-2 f-z-14" style="margin-top: 10px; background-color: #e4f1ff"> |
cb21a5
|
141 |
<span>{{ `<${tableRowData.sender}>` }}</span> |
H |
142 |
<span>暂未查询到该客户的当地时间</span> |
|
143 |
<!-- <span>2024-06-08 22:22</span> --> |
|
144 |
</div> |
a9a03d
|
145 |
<div class="ct"> |
H |
146 |
<div v-if="tableRowData.content"> |
|
147 |
<TinymcePw ref="TinymcePwRef" v-model="tableRowData.content" /> |
|
148 |
</div> |
cb21a5
|
149 |
</div> |
ccfd07
|
150 |
</div> |
H |
151 |
</div> |
a9a03d
|
152 |
<div v-show="isOpen" class="ct-right"> |
H |
153 |
<div style="position: relative"> |
|
154 |
<div style="position: absolute; top: 0; left: 10px"> |
|
155 |
<UserTips></UserTips> |
|
156 |
</div> |
|
157 |
</div> |
|
158 |
</div> |
ccfd07
|
159 |
</div> |
cb21a5
|
160 |
<div @click="fuToggleContent" class="toggle-btn" :class="isOpen ? 'onIconOpen' : 'iconOpen'"> |
H |
161 |
<LeftOutlined v-if="!isOpen" /> |
|
162 |
<RightOutlined v-else /> |
|
163 |
</div> |
00fe0e
|
164 |
</div> |
H |
165 |
</a-drawer> |
|
166 |
</template> |
|
167 |
|
ccfd07
|
168 |
<script lang="ts" setup> |
74a35f
|
169 |
name: 'drawerDetail'; |
ccfd07
|
170 |
|
74a35f
|
171 |
import { ref, watch, defineProps, defineEmits, computed } from 'vue'; |
H |
172 |
import { |
|
173 |
LeftOutlined, |
|
174 |
RightOutlined, |
|
175 |
DoubleLeftOutlined, |
|
176 |
PushpinOutlined, |
|
177 |
CopyOutlined, |
|
178 |
UserOutlined, |
|
179 |
RollbackOutlined, |
|
180 |
} from '@ant-design/icons-vue'; |
|
181 |
import pageHeadLeft from './pageHeadLeft.vue'; |
a9a03d
|
182 |
import UserTips from '@/views/email/components/userTips/index.vue'; |
74a35f
|
183 |
import { TinymcePw } from '@/components/Tinymce'; |
H |
184 |
import { getMailInfoApi, setQuickReplyAPi } from '@/api/email/userList'; |
|
185 |
import { useCollapseStore } from '@/store/modules/useCollapseStore'; |
|
186 |
import { nextTick } from 'vue'; |
|
187 |
import { formatToDateDay } from '@/utils/dateUtil'; |
|
188 |
import { useLoading } from '@/components/Loading'; |
00fe0e
|
189 |
|
74a35f
|
190 |
// const [open, close, setTip] = useLoading(); |
H |
191 |
// 定义属性 |
|
192 |
interface Props { |
|
193 |
modelValue: boolean; |
|
194 |
title?: string; |
|
195 |
placement?: 'left' | 'right' | 'top' | 'bottom'; |
|
196 |
idName?: string; |
|
197 |
selectIds?: number[]; |
|
198 |
mailId?: string; |
|
199 |
selectAllRow: Array<any>; |
|
200 |
allList; |
a9a03d
|
201 |
isDrafts?: boolean; |
74a35f
|
202 |
} |
ccfd07
|
203 |
|
74a35f
|
204 |
const props = defineProps<Props>(); |
ccfd07
|
205 |
|
74a35f
|
206 |
const tableRowData = ref<Record<string, any>>({}); |
H |
207 |
const emit = defineEmits(['update:modelValue', 'updateData']); |
|
208 |
const drawerOpen = ref(props.modelValue); |
|
209 |
const TinymcePwRef = ref(); |
|
210 |
const docCode = ref(props.mailId); |
|
211 |
watch( |
|
212 |
() => props.mailId, |
|
213 |
(newVal) => { |
|
214 |
docCode.value = newVal; |
|
215 |
}, |
|
216 |
); |
|
217 |
// 监听属性变化 |
|
218 |
watch( |
|
219 |
() => props.modelValue, |
|
220 |
(newValue) => { |
|
221 |
nextTick(() => { |
a9a03d
|
222 |
drawerOpen.value = newValue; |
H |
223 |
setTimeout(() => { |
|
224 |
console.log(newValue, '---------4', TinymcePwRef.value); |
|
225 |
tableRowData.value.content = tableRowData.value.content; |
|
226 |
}, 500); |
74a35f
|
227 |
}); |
H |
228 |
if (newValue) { |
|
229 |
fnGetMailInfo(props.mailId); |
|
230 |
} |
|
231 |
}, |
|
232 |
); |
|
233 |
|
|
234 |
function fnGetMailInfo(id) { |
|
235 |
getMailInfoApi({ docCode: id }) |
|
236 |
.then((res) => { |
a9a03d
|
237 |
nextTick(() => { |
H |
238 |
docCode.value = id; |
|
239 |
tableRowData.value = res.data; |
|
240 |
}); |
74a35f
|
241 |
}) |
H |
242 |
.catch(() => {}); |
|
243 |
} |
|
244 |
// 更新外部属性 |
|
245 |
watch(drawerOpen, (newValue) => { |
|
246 |
emit('update:modelValue', newValue); |
|
247 |
}); |
|
248 |
|
|
249 |
// 方法 |
|
250 |
const collapseStore = useCollapseStore(); |
|
251 |
const afterOpenChange = (bool: boolean) => { |
|
252 |
if (bool) { |
|
253 |
fnGetUserList({ page: 1, pageSize: 30 }); |
|
254 |
} |
|
255 |
collapseStore.toggle(false); |
|
256 |
}; |
|
257 |
const drawerClose = (e) => { |
|
258 |
drawerOpen.value = false; |
|
259 |
}; |
|
260 |
|
|
261 |
const fnGetUserList = (params) => { |
|
262 |
// 调用接口逻辑 |
|
263 |
}; |
|
264 |
|
|
265 |
// 计算属性 |
|
266 |
const placement = computed(() => props.placement || 'right'); |
|
267 |
|
|
268 |
const content = ref(''); |
|
269 |
const isOpen = ref(false); |
|
270 |
|
|
271 |
function fuToggleContent() { |
|
272 |
isOpen.value = !isOpen.value; |
|
273 |
} |
|
274 |
|
|
275 |
function fnPrev() { |
|
276 |
const id = getPrevId(props.allList, docCode.value); |
|
277 |
fnGetMailInfo(id); |
|
278 |
} |
|
279 |
function fnNext() { |
|
280 |
const id = getNextId(props.allList, docCode.value); |
|
281 |
fnGetMailInfo(id); |
|
282 |
} |
|
283 |
function getNextId(list, id) { |
|
284 |
const index = list.findIndex((item) => item.docCode === id); |
|
285 |
if (index < list.length - 1) { |
|
286 |
return list[index + 1].docCode; |
|
287 |
} else { |
|
288 |
return list[0].docCode; |
|
289 |
} |
|
290 |
} |
|
291 |
function getPrevId(list, id) { |
|
292 |
const index = list.findIndex((item) => item.docCode === id); |
|
293 |
if (index > 0) { |
|
294 |
return list[index - 1].docCode; |
|
295 |
} else { |
|
296 |
return list[list.length - 1].docCode; |
|
297 |
} |
|
298 |
} |
|
299 |
|
|
300 |
import { useMessage } from '@/hooks/web/useMessage'; |
|
301 |
|
|
302 |
const { createMessage } = useMessage(); |
|
303 |
function fnQuickReply() { |
|
304 |
if (!content.value) { |
|
305 |
createMessage.warning('请输入回复内容'); |
|
306 |
return; |
|
307 |
} |
|
308 |
const data = { |
|
309 |
docCode: docCode.value, |
|
310 |
content: content.value, |
|
311 |
}; |
|
312 |
setQuickReplyAPi(data).then((res) => { |
|
313 |
if (res.code == 0) { |
|
314 |
createMessage.success(res.msg); |
|
315 |
|
|
316 |
fnGetMailInfo(props.mailId); |
|
317 |
} |
ccfd07
|
318 |
}); |
00fe0e
|
319 |
} |
cb21a5
|
320 |
import { useRouter } from 'vue-router'; |
63d608
|
321 |
const router = useRouter(); |
a9a03d
|
322 |
function replyEmail(row, type) { |
H |
323 |
router.push({ path: '/email/edit', query: { docCode: row.docCode, type: type } }); |
63d608
|
324 |
} |
00fe0e
|
325 |
</script> |
H |
326 |
|
|
327 |
<style scoped lang="less"> |
74a35f
|
328 |
.table-content { |
00fe0e
|
329 |
display: flex; |
74a35f
|
330 |
justify-content: space-between; |
H |
331 |
border-top: 1px solid #f0f0f0; |
|
332 |
|
|
333 |
.left { |
|
334 |
width: 80%; |
|
335 |
height: 100%; |
|
336 |
border-right: 1px solid #f0f0f0; |
|
337 |
} |
|
338 |
|
|
339 |
.right { |
|
340 |
height: 100%; |
|
341 |
} |
00fe0e
|
342 |
} |
H |
343 |
|
74a35f
|
344 |
::v-deep(.ant-table) { |
H |
345 |
min-height: 355px !important; |
|
346 |
} |
|
347 |
|
|
348 |
.title { |
00fe0e
|
349 |
display: flex; |
H |
350 |
align-items: center; |
|
351 |
justify-content: space-between; |
|
352 |
|
74a35f
|
353 |
& .left { |
H |
354 |
display: flex; |
|
355 |
align-items: center; |
|
356 |
width: 50%; |
|
357 |
} |
|
358 |
|
|
359 |
& .right { |
|
360 |
display: flex; |
a9a03d
|
361 |
flex: 1; |
74a35f
|
362 |
align-items: center; |
a9a03d
|
363 |
justify-content: flex-end; |
74a35f
|
364 |
|
H |
365 |
& .tate { |
a9a03d
|
366 |
margin-right: 10px; |
74a35f
|
367 |
} |
00fe0e
|
368 |
} |
H |
369 |
} |
|
370 |
|
74a35f
|
371 |
.ct { |
H |
372 |
margin: 20px 0; |
|
373 |
} |
00fe0e
|
374 |
|
74a35f
|
375 |
.flex-between { |
H |
376 |
display: flex; |
|
377 |
} |
00fe0e
|
378 |
|
74a35f
|
379 |
.ct-left { |
H |
380 |
padding-right: 20px; |
|
381 |
} |
00fe0e
|
382 |
|
74a35f
|
383 |
.ct-right { |
a9a03d
|
384 |
flex: 1; |
74a35f
|
385 |
} |
00fe0e
|
386 |
|
74a35f
|
387 |
.toggle-btn { |
H |
388 |
display: flex; |
|
389 |
position: absolute; |
|
390 |
z-index: 99; |
|
391 |
top: 50%; |
|
392 |
width: 20px; |
|
393 |
height: 54px; |
|
394 |
padding-left: 5px; |
|
395 |
transform: translateY(-50%); |
|
396 |
border: 1px solid #f0f0f0; |
|
397 |
border-right: none; |
|
398 |
border-radius: 10px 0 0 10px; |
|
399 |
background: #fafafa; |
|
400 |
} |
00fe0e
|
401 |
|
74a35f
|
402 |
.onOpen { |
H |
403 |
width: 100%; |
|
404 |
} |
00fe0e
|
405 |
|
74a35f
|
406 |
.isOpen { |
a9a03d
|
407 |
width: calc(100% - 420px); |
H |
408 |
} |
|
409 |
|
|
410 |
.onOpenTop { |
|
411 |
width: 98%; |
|
412 |
} |
|
413 |
|
|
414 |
.isOpenTop { |
|
415 |
width: calc(98% - 460px); |
74a35f
|
416 |
} |
00fe0e
|
417 |
|
74a35f
|
418 |
.iconOpen { |
H |
419 |
right: 0%; |
|
420 |
} |
00fe0e
|
421 |
|
74a35f
|
422 |
.onIconOpen { |
a9a03d
|
423 |
right: 425px; |
74a35f
|
424 |
} |
cb21a5
|
425 |
|
H |
426 |
.ctb { |
|
427 |
position: relative; |
|
428 |
} |
|
429 |
|
a9a03d
|
430 |
.ct-top { |
cb21a5
|
431 |
position: absolute; |
H |
432 |
z-index: 99; |
a9a03d
|
433 |
top: 57px; |
H |
434 |
left: 10px; |
cb21a5
|
435 |
padding: 10px; |
H |
436 |
background: #fff; |
|
437 |
} |
a9a03d
|
438 |
|
H |
439 |
.text-ellipsis { |
|
440 |
overflow: hidden; |
|
441 |
text-overflow: ellipsis; |
|
442 |
white-space: nowrap; |
|
443 |
} |
|
444 |
|
|
445 |
.f-z-14 { |
|
446 |
font-size: 12px; |
|
447 |
} |
00fe0e
|
448 |
</style> |