feat(im): 前端增加「黑名单」的操作

im
YunaiV 2026-05-04 16:24:12 +08:00
parent 1b51926b19
commit 7141e431e2
3 changed files with 61 additions and 3 deletions

View File

@ -47,3 +47,13 @@ export const updateFriend = (data: ImFriendUpdateReqVO) => {
return request.put<boolean>({ url: '/im/friend/update', data })
}
// 拉黑好友(必须先是好友;单边屏蔽对方私聊消息)
export const blockFriend = (friendUserId: number | string) => {
return request.put<boolean>({ url: '/im/friend/block', params: { friendUserId } })
}
// 移出黑名单
export const unblockFriend = (friendUserId: number | string) => {
return request.put<boolean>({ url: '/im/friend/unblock', params: { friendUserId } })
}

View File

@ -39,7 +39,7 @@
<div class="truncate">部门{{ deptText }}</div>
</div>
</div>
<!-- 右上 "..." 菜单 friend 态展示菜单项目前只有"删除联系人"其它 WeChat 选项业务上未支持 -->
<!-- 右上 "..." 菜单 friend 态展示加入/移出黑名单 + 删除联系人 -->
<div v-if="relation === 'friend'" class="flex-shrink-0">
<el-dropdown trigger="click" placement="bottom-end" popper-class="im-user-info__more-menu">
<div
@ -49,7 +49,10 @@
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleDeleteFriend">
<!-- 拉黑 / 移出黑名单 friendInfo.blocked 切换文案 -->
<el-dropdown-item v-if="!isBlocked" @click="handleBlock"></el-dropdown-item>
<el-dropdown-item v-else @click="handleUnblock"></el-dropdown-item>
<el-dropdown-item divided @click="handleDeleteFriend">
<span class="text-[var(--el-color-danger)]">删除联系人</span>
</el-dropdown-item>
</el-dropdown-menu>
@ -237,11 +240,14 @@ const deptText = computed(() => full.value?.deptName || '-')
const genderIcon = computed(() => getGenderIcon(full.value?.sex))
const genderColor = computed(() => getGenderColor(full.value?.sex))
/** 好友关系记录:来源 / 添加时间从这里取(仅 friend 态下才有意义) */
/** 好友关系记录:来源 / 添加时间 / 是否拉黑从这里取(仅 friend 态下才有意义) */
const friendInfo = computed(() =>
props.user?.id ? friendStore.getFriend(props.user.id) : undefined
)
/** 是否已拉黑:菜单项「加入黑名单 / 移出黑名单」按这个切换 */
const isBlocked = computed(() => !!friendInfo.value?.blocked)
/** 备注内联编辑editingRemark 控制输入态user 切换时由下面的 watch 复位避免脏态泄漏 */
const editingRemark = ref(false)
const remarkInput = ref('')
@ -346,6 +352,26 @@ function handleAddFriend() {
addFriendVisible.value = true
}
/** 加入黑名单confirm → friendStore.blockFriend后端 FRIEND_BLOCK 推到时由 dispatcher 同步多端 */
async function handleBlock() {
if (!props.user?.id) {
return
}
const target = props.user
await message.confirm(`确定将「${target.nickname || ''}」加入黑名单吗?`, '加入黑名单')
await friendStore.blockFriend(target.id)
message.success('已加入黑名单')
}
/** 移出黑名单:操作温和不弹 confirm后端 FRIEND_UNBLOCK 推到时由 dispatcher 同步多端 */
async function handleUnblock() {
if (!props.user?.id) {
return
}
await friendStore.unblockFriend(props.user.id)
message.success('已移出黑名单')
}
/** 删除联系人confirm → friendStore.deleteFriend内部级联清会话→ 通知父级关浮层 / 清选中 */
async function handleDeleteFriend() {
if (!props.user?.id) {

View File

@ -7,6 +7,8 @@ import {
getFriend as apiGetFriend,
deleteFriend as apiDeleteFriend,
updateFriend as apiUpdateFriend,
blockFriend as apiBlockFriend,
unblockFriend as apiUnblockFriend,
type ImFriendRespVO
} from '@/api/im/friend'
import {
@ -235,6 +237,26 @@ export const useFriendStore = defineStore('imFriendStore', {
}
},
/** 拉黑好友:本端乐观更新 + 调接口;后端 FRIEND_BLOCK 推到时由 dispatcher 兜底同步多端 */
async blockFriend(friendUserId: number) {
await apiBlockFriend(friendUserId)
const friend = this.getFriend(friendUserId)
if (friend) {
friend.blocked = true
this.saveFriends()
}
},
/** 移出黑名单:本端乐观更新 + 调接口;后端 FRIEND_UNBLOCK 推到时由 dispatcher 兜底同步多端 */
async unblockFriend(friendUserId: number) {
await apiUnblockFriend(friendUserId)
const friend = this.getFriend(friendUserId)
if (friend) {
friend.blocked = false
this.saveFriends()
}
},
/** 修改好友展示备注(仅自己可见) */
async setDisplayName(friendUserId: number, displayName: string) {
const value = displayName.trim()