You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
7.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="page">
<view class="body">
<!-- 头像 + 名称 -->
<view class="user-card">
<image class="avatar" :src="userInfo.headImage || defaultAvatar" mode="aspectFill"></image>
<view class="nickname">{{ displayName }}</view>
<view class="uid">ID:{{ userInfo.id || userInfo.userId || '-' }}</view>
</view>
<!-- 黑名单开关行 仿微信 -->
<!-- <view class="black-row">-->
<!-- <text class="black-label">加入黑名单</text>-->
<!-- <switch-->
<!-- :checked="isBlacked"-->
<!-- active-color="#00a89b"-->
<!-- @change="onBlackSwitchChange"-->
<!-- />-->
<!-- </view>-->
<view class="black-row">
<text class="black-label">加入黑名单</text>
<view class="custom-switch" :class="{ on: isBlacked }" @tap="handleSwitchTap">
<view class="switch-dot"></view>
</view>
</view>
<!-- 发消息按钮 -->
<view class="actions">
<button class="btn-chat" @tap="onSendMessage">发消息</button>
</view>
</view>
</view>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
data() {
return {
userId: '',
userInfo: {},
isBlacked: false,
defaultAvatar: '/static/image/kff.png',
chatIndex:null
}
},
computed: {
...mapGetters('chatStore', ['findChatIdx']),
displayName() {
if (!this.userInfo) return ''
return this.userInfo.remarkNickName || this.userInfo.nickName || this.userInfo.showNickName || '未命名'
}
},
onLoad(options) {
this.userId = options.id || ''
this.chatIndex = options.chatIndex || ''
console.log('chatIndex...',this.chatIndex)
if (this.userId) {
this.loadFriend()
this.checkBlack()
}
},
methods: {
...mapActions('chatStore', ['removeChat','openChat']),
async loadFriend() {
try {
const { data: res } = await uni.$http.get('/api/friend/find/' + this.userId)
if (res.data) {
this.userInfo = res.data
}
} catch (e) {
console.error('加载好友信息失败', e)
}
},
async checkBlack() {
try {
const { data: res } = await uni.$http.post(`/api/blacklist/check?targetUid=${this.userId}`)
if (res && res.data) {
console.log('查询黑名单状态', res.data)
this.isBlacked = !!res.data.meBlackTarget
}
} catch (e) {
console.error('查询黑名单状态失败', e)
}
},
/**
* switch点击,不直接改状态,弹出确认弹窗
*/
onBlackSwitchChange(e) {
// e.detail.value 是用户想要切换到的目标状态
const targetStatus = e.detail.value
const title = targetStatus ? '加入黑名单' : '取消黑名单'
const content = targetStatus
? '加入黑名单后,对方将无法给你发送消息,确定?'
: '确定将该用户移出黑名单?'
uni.showModal({
title,
content,
success: async (res) => {
if (!res.confirm) {
// 用户点取消,不做任何操作,switch会自动回弹回旧状态,无需手动赋值
return
}
try {
const url = targetStatus ? '/api/blacklist/add?targetUid=' : '/api/blacklist/cancel?targetUid='
await uni.$http.post(`${url}${this.userId}`)
// 接口成功才更新本地状态
this.isBlacked = targetStatus
uni.showToast({
title: this.isBlacked ? '已加入黑名单' : '已取消黑名单',
icon: 'none'
})
} catch (err) {
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
})
},
onSendMessage() {
// if (this.isBlacked) {
// uni.showToast({ title: '你已将对方加入黑名单', icon: 'none' })
// return
// }
let chat = {
type: 'PRIVATE',
targetId: this.userId,
showName: this.displayName,
headImage: this.userInfo.headImage || ''
}
this.openChat(chat)
let chatIdx = this.findChatIdx(chat)
uni.navigateTo({ url: `/pages/chatbox/chat-box?chatIdx=${chatIdx}` })
},
findChatIdxByUser(){
let chat = {
type: 'PRIVATE',
targetId: this.userId,
showName: this.displayName,
headImage: this.userInfo.headImage || ''
}
return this.findChatIdx(chat)
},
handleSwitchTap() {
// 用户想要切换到的目标状态
const targetStatus = !this.isBlacked
const title = targetStatus ? '加入黑名单' : '取消黑名单'
const content = targetStatus
? '加入黑名单后,对方将无法给你发送消息,确定?'
: '确定将该用户移出黑名单?'
uni.showModal({
title,
content,
success: async (res) => {
if (!res.confirm) {
// 用户点取消,不做任何变更
return
}
try {
const url = targetStatus ? '/api/blacklist/add?targetUid=' : '/api/blacklist/cancel?targetUid='
await uni.$http.post(`${url}${this.userId}`)
this.isBlacked = targetStatus
uni.showToast({
title: this.isBlacked ? '已加入黑名单' : '已取消黑名单',
icon: 'none'
})
//聊天框 - 删除
if (this.isBlacked && this.chatIndex){
this.removeChat(Number(this.chatIndex)) // 调用 Vuex action
}
const privateChatIdx=this.findChatIdxByUser();
if (this.isBlacked && privateChatIdx>-1){
this.removeChat(Number(privateChatIdx))
}
} catch (err) {
uni.showToast({ title: '操作失败', icon: 'none' })
}
}
})
},
goBackChat() {
uni.reLaunch({
url: `/pages/chatbox/chat`
});
}
},
// 拦截返回
onBackPress(e) {
// 来源是左上角返回 / 安卓返回键
if(e.from === 'backbutton'){
if(this.isBlacked){
// 拉黑成功,自定义跳转chat
this.goBackChat()
return true // return true 阻止原生默认返回
}else{
// 未拉黑,放行,走原来的返回(回到chat-box)
return false
}
}
return false
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background-color: #f4f4f4;
}
.body {
padding: 24rpx 0;
}
.user-card {
background: #fff;
padding: 60rpx 0 40rpx;
display: flex;
flex-direction: column;
align-items: center;
.avatar {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
background: #eee;
}
.nickname {
margin-top: 24rpx;
font-size: 36rpx;
font-weight: 600;
color: #222;
}
.uid {
margin-top: 10rpx;
font-size: 24rpx;
color: #999;
}
}
/* 黑名单开关行 */
.black-row {
margin-top: 24rpx;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 40rpx;
.black-label {
font-size: 32rpx;
color: #333;
}
}
.custom-switch {
width: 88rpx;
height: 52rpx;
border-radius: 26rpx;
background-color: #e5e5e5;
position: relative;
transition: background-color 0.24s ease;
.switch-dot {
position: absolute;
top: 3rpx;
left: 3rpx;
width: 46rpx;
height: 46rpx;
border-radius: 50%;
background-color: #ffffff;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.18);
transition: left 0.24s ease;
}
&.on {
background-color: #00a89b;
.switch-dot {
left: 39rpx;
}
}
}
.actions {
margin-top: 40rpx;
padding: 0 40rpx;
.btn-chat {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #00a89b;
color: #fff;
font-size: 32rpx;
border-radius: 12rpx;
&::after { border: none; }
&:active { opacity: 0.85; }
}
}
</style>