3
3
<div
4
4
v-for =" (item, index) in conversationList"
5
5
:key =" item.id"
6
- :class =" { active: index === activeConversationIndex }"
7
- class =" kefu-conversation flex justify-between items-center"
6
+ :class =" { active: index === activeConversationIndex, pinned: item.adminPinned }"
7
+ class =" kefu-conversation flex items-center"
8
8
@click =" openRightMessage(item, index)"
9
+ @contextmenu.prevent =" rightClick($event as PointerEvent, item)"
9
10
>
10
11
<div class =" flex justify-center items-center w-100%" >
11
- <el-avatar :src =" item.userAvatar" alt =" avatar" />
12
+ <div class =" flex justify-center items-center" style =" width : 50px ; height : 50px " >
13
+ <el-badge
14
+ :hidden =" item.adminUnreadMessageCount === 0"
15
+ :max =" 99"
16
+ :value =" item.adminUnreadMessageCount"
17
+ >
18
+ <el-avatar :src =" item.userAvatar" alt =" avatar" />
19
+ </el-badge >
20
+ </div >
12
21
<div class =" ml-10px w-100%" >
13
22
<div class =" flex justify-between items-center w-100%" >
14
23
<span >{{ item.userNickname }}</span >
24
33
></div >
25
34
</template >
26
35
<!-- 图片消息 -->
27
- <template v-if =" KeFuMessageContentTypeEnum .IMAGE === item .lastMessageContentType " >
28
- <div class =" last-message flex items-center color-[#989EA6]" >【图片消息】</div >
36
+ <template v-else >
37
+ <div class =" last-message flex items-center color-[#989EA6]" >
38
+ {{ getContentType(item.lastMessageContentType) }}
39
+ </div >
29
40
</template >
30
41
</div >
31
42
</div >
32
43
</div >
44
+ <!-- 通过右击获取到的坐标定位 -->
45
+ <ul v-show =" showRightMenu" :style =" rightMenuStyle" class =" right-menu-ul" >
46
+ <li
47
+ v-show =" !selectedConversation.adminPinned"
48
+ class =" flex items-center"
49
+ @click.stop =" updateConversationPinned(true)"
50
+ >
51
+ <Icon class =" mr-5px" icon =" ep:top" />
52
+ 置顶会话
53
+ </li >
54
+ <li
55
+ v-show =" selectedConversation.adminPinned"
56
+ class =" flex items-center"
57
+ @click.stop =" updateConversationPinned(false)"
58
+ >
59
+ <Icon class =" mr-5px" icon =" ep:bottom" />
60
+ 取消置顶
61
+ </li >
62
+ <li class =" flex items-center" @click.stop =" deleteConversation" >
63
+ <Icon class =" mr-5px" color =" red" icon =" ep:delete" />
64
+ 删除会话
65
+ </li >
66
+ <li class =" flex items-center" @click.stop =" closeRightMenu" >
67
+ <Icon class =" mr-5px" color =" red" icon =" ep:close" />
68
+ 取消
69
+ </li >
70
+ </ul >
33
71
</div >
34
72
</template >
35
73
36
74
<script lang="ts" setup>
37
75
import { KeFuConversationApi , KeFuConversationRespVO } from ' @/api/mall/promotion/kefu/conversation'
38
76
import { useEmoji } from ' ./tools/emoji'
39
- import { formatDate } from ' @/utils/formatTime'
77
+ import { formatDate , getNowDateTime } from ' @/utils/formatTime'
40
78
import { KeFuMessageContentTypeEnum } from ' ./tools/constants'
41
79
42
80
defineOptions ({ name: ' KeFuConversationBox' })
81
+ const message = useMessage ()
43
82
const { replaceEmoji } = useEmoji ()
44
83
const activeConversationIndex = ref (- 1 ) // 选中的会话
45
84
const conversationList = ref <KeFuConversationRespVO []>([]) // 会话列表
46
85
const getConversationList = async () => {
47
86
conversationList .value = await KeFuConversationApi .getConversationList ()
87
+ // 测试数据
88
+ for (let i = 0 ; i < 5 ; i ++ ) {
89
+ conversationList .value .push ({
90
+ id: 1 ,
91
+ userId: 283 ,
92
+ userAvatar:
93
+ ' https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKMezSxtOImrC9lbhwHiazYwck3xwrEcO7VJfG6WQo260whaeVNoByE5RreiaGsGfOMlIiaDhSaA991w/132' ,
94
+ userNickname: ' 辉辉鸭' + i ,
95
+ lastMessageTime: getNowDateTime (),
96
+ lastMessageContent:
97
+ ' [爱心][爱心]你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇你好哇' ,
98
+ lastMessageContentType: 1 ,
99
+ adminPinned: false ,
100
+ userDeleted: false ,
101
+ adminDeleted: false ,
102
+ adminUnreadMessageCount: i
103
+ })
104
+ }
48
105
}
49
106
defineExpose ({ getConversationList })
50
107
const emits = defineEmits <{
@@ -55,6 +112,73 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
55
112
activeConversationIndex .value = index
56
113
emits (' change' , item )
57
114
}
115
+ // 获得消息类型
116
+ const getContentType = computed (() => (lastMessageContentType : number ) => {
117
+ switch (lastMessageContentType ) {
118
+ case KeFuMessageContentTypeEnum .SYSTEM :
119
+ return ' [系统消息]'
120
+ case KeFuMessageContentTypeEnum .VIDEO :
121
+ return ' [视频消息]'
122
+ case KeFuMessageContentTypeEnum .IMAGE :
123
+ return ' [图片消息]'
124
+ case KeFuMessageContentTypeEnum .PRODUCT :
125
+ return ' [商品消息]'
126
+ case KeFuMessageContentTypeEnum .ORDER :
127
+ return ' [订单消息]'
128
+ case KeFuMessageContentTypeEnum .VOICE :
129
+ return ' [语音消息]'
130
+ default :
131
+ return ' '
132
+ }
133
+ })
134
+
135
+ // ======================= 右键菜单 =======================
136
+ const showRightMenu = ref (false ) // 显示右键菜单
137
+ const rightMenuStyle = ref <any >({}) // 右键菜单 Style
138
+ const selectedConversation = ref <KeFuConversationRespVO >({} as KeFuConversationRespVO ) // 右键选中的会话对象
139
+ // 右键菜单
140
+ const rightClick = (mouseEvent : PointerEvent , item : KeFuConversationRespVO ) => {
141
+ selectedConversation .value = item
142
+ // 显示右键菜单
143
+ showRightMenu .value = true
144
+ rightMenuStyle .value = {
145
+ top: mouseEvent .clientY - 110 + ' px' ,
146
+ left: mouseEvent .clientX - 80 + ' px'
147
+ }
148
+ }
149
+ // 关闭菜单
150
+ const closeRightMenu = () => {
151
+ showRightMenu .value = false
152
+ }
153
+ // 置顶会话
154
+ const updateConversationPinned = async (adminPinned : boolean ) => {
155
+ // 1. 会话置顶/取消置顶
156
+ await KeFuConversationApi .updateConversationPinned ({
157
+ id: selectedConversation .value .id ,
158
+ adminPinned
159
+ })
160
+ // TODO puhui999: 快速操作两次提示只会提示一次看看怎么优雅解决
161
+ message .success (adminPinned ? ' 置顶成功' : ' 取消置顶成功' )
162
+ // 2. 关闭右键菜单,更新会话列表
163
+ closeRightMenu ()
164
+ await getConversationList ()
165
+ }
166
+ // 删除会话
167
+ const deleteConversation = async () => {
168
+ // 1. 删除会话
169
+ await message .confirm (' 您确定要删除该会话吗?' )
170
+ await KeFuConversationApi .deleteConversation (selectedConversation .value .id )
171
+ // 2. 关闭右键菜单,更新会话列表
172
+ closeRightMenu ()
173
+ await getConversationList ()
174
+ }
175
+ watch (showRightMenu , (val ) => {
176
+ if (val ) {
177
+ document .body .addEventListener (' click' , closeRightMenu )
178
+ } else {
179
+ document .body .removeEventListener (' click' , closeRightMenu )
180
+ }
181
+ })
58
182
</script >
59
183
60
184
<style lang="scss" scoped>
@@ -77,5 +201,30 @@ const openRightMessage = (item: KeFuConversationRespVO, index: number) => {
77
201
border-left : 5px #3271ff solid ;
78
202
background-color : #eff0f1 ;
79
203
}
204
+
205
+ .pinned {
206
+ background-color : #eff0f1 ;
207
+ }
208
+
209
+ .right-menu-ul {
210
+ position : absolute ;
211
+ background-color : #fff ;
212
+ padding : 10px ;
213
+ margin : 0 ;
214
+ list-style-type : none ; /* 移除默认的项目符号 */
215
+ border-radius : 12px ;
216
+ box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 ); /* 阴影效果 */
217
+ width : 130px ;
218
+
219
+ li {
220
+ padding : 8px 16px ;
221
+ cursor : pointer ;
222
+ border-radius : 12px ;
223
+ transition : background-color 0.3s ; /* 平滑过渡 */
224
+ & :hover {
225
+ background-color : #e0e0e0 ; /* 悬停时的背景颜色 */
226
+ }
227
+ }
228
+ }
80
229
}
81
230
</style >
0 commit comments