聊天中的通知及好友申请:
如下图效果
聊天的效果:
这里的friends,好友例表,里面有相关代码:
php
<template>
<view class="friends-container">
<view v-if="!isLoggedIn" class="not-logged-in">
<text>您尚未登录。请先登录以查看好友列表。</text>
<button @click="goToLogin">去登录</button>
</view>
<view>
<view v-if="friends.length === 0">
<uni-list>
<uni-list-chat
:avatar-circle="true"
title="增加好友"
note="输入用户帐号或群号"
:avatar="'../../static/addfriend.png'"
showArrow
link
@click="gotadd"
></uni-list-chat>
</uni-list>
</view>
<view>
<uni-list>
<uni-list-chat
v-for="(friend, index) in friendsInv"
:key="index"
:title="friend.group ? friend.group.name : friend.user.username"
:avatar-circle="true"
:note="formatDate(friend.created_at) + ' 邀请'"
badge-position="left"
badge-text="邀请"
showArrow
link
@tap="aggrees(friend.id)"
:avatar="friend.group ? friend.group.avatar_url : friend.user.avatar_url"
></uni-list-chat>
</uni-list>
</view>
<view v-if="friends.length > 0">
<uni-list>
<uni-list-chat
:avatar-circle="true"
title="增加好友"
note="输入用户帐号或群号"
:avatar="'../../static/addfriend.png'"
showArrow
link
@click="gotadd"
></uni-list-chat>
</uni-list>
<uni-list>
<uni-list-chat
v-for="(friend, index) in friends"
:key="index"
:title="friend.type === 'group' ? '[群]' + friend.group.name : friend.user.username"
:avatar-circle="true"
:avatar="friend.type === 'group' ? friend.group.avatar_url : friend.user.avatar_url"
:note="friend.message||'暂无聊天'"
:time="friend.time"
badge-position="left"
:badge-text="friend.type === 'group' ? friend.count + '人' : ''"
showArrow
link
@click="toChat(friend)"
></uni-list-chat>
</uni-list>
</view>
<button @click="loadMoreFriends" v-if="hasMoreFriends">加载更多</button>
</view>
<uni-popup ref="popupBag" type="center">
<view class="bagDetail">
<view class="title flex align-center justify-content-between">
<view class="flex-sub">添加好友</view>
<view class="close-button" style="font-size: 22px" @tap="closepopupBag">×</view>
</view>
<uni-list :border="true">
<uni-list-item title="邀请好友" note="请输入正确的帐号" badge-position="right" badge-text="dot" link @tap="goaddurl"></uni-list-item>
<uni-list-item title="创建群" note="群号创建后不能修改" badge-position="right" badge-text="dot" link @tap="gogroupurl"></uni-list-item>
</uni-list>
</view>
</uni-popup>
<uni-popup ref="popupAggreeBag" type="center">
<view class="bagDetail">
<view class="title flex align-center justify-content-between">
<view class="flex-sub">邀请操作</view>
</view>
<uni-list :border="true">
<uni-list-item title="同意" note="同意后加入" badge-position="right" badge-text="dot" link @tap="aggree(1)"></uni-list-item>
<uni-list-item title="拒绝" note="拒绝后则不再显示" badge-position="right" badge-text="dot" link @tap="aggree(0)"></uni-list-item>
</uni-list>
</view>
</uni-popup>
<button @click="myself">我的信息</button>
</view>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import io from 'socket.io-client';
import config from '@/config/config.js';
export default {
data() {
return {
page: 1,
perPage: 20,
loading: false,
hasMoreFriends: false,
message: '',
friends: [],
friendsInv: [],
aggreeid: '',
};
},
computed: {
...mapState(['token', 'lastMessages']),
isLoggedIn() {
return !!this.token;
},
},
onLoad() {
this.invateFriends();
this.loadFriends();
},
mounted() {
this.socket = io(config.apiBaseUrl, {
query: {
token: this.token,
},
});
this.socket.on('connect', () => {
console.log('Socket connected:', this.socket.id);
});
this.socket.on('disconnect', () => {
console.log('Socket disconnected');
});
this.socket.on('message', (msg) => {
console.log('Received message:', msg);
this.friends = this.friends.map((friend) => {
if (friend.id == msg.group_name || (friend.group && friend.group.id == msg.group_name.replace("g_", ""))) {
friend.message = msg.content;
}
return friend;
});
console.log(this.friends)
});
},
beforeDestroy() {
if (this.socket) {
this.socket.off('message', this.handleNewMessage);
this.socket.disconnect();
}
},
methods: {
...mapActions(['fetchFriends']),
handleNewMessage(msg) {
this.friends = this.friends.map((friend) => {
if (friend.id == msg.group_name || (friend.group && friend.group.id == msg.group_name.replace("g_", ""))) {
friend.message = msg.content;
}
return friend;
});
console.log(this.friends)
},
async aggrees(id) {
this.aggreeid = id;
this.$refs.popupAggreeBag.open();
},
async aggree(agid) {
try {
this.$refs.popupAggreeBag.close();
const token = uni.getStorageSync('token');
const [error, response] = await uni.request({
url: `${config.apiBaseUrl}/agree`,
method: 'POST',
header: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
data: {
id: this.aggreeid,
status: agid === 1 ? 'accepted' : 'declined',
},
});
if (response.data.code === 0) {
uni.showToast({
title: response.data.message,
duration: 2000,
});
this.loadFriends();
this.invateFriends();
} else {
uni.showToast({
title: response.data.message,
});
}
} catch (error) {
console.error(error);
}
},
formatDate(date) {
const d = new Date(date);
const year = d.getFullYear();
const month = (d.getMonth() + 1).toString().padStart(2, '0');
const day = d.getDate().toString().padStart(2, '0');
const hours = d.getHours().toString().padStart(2, '0');
const minutes = d.getMinutes().toString().padStart(2, '0');
return `${year}年${month}月${day}日 ${hours}:${minutes}`;
},
async loadFriends() {
const token = uni.getStorageSync('token');
if (!token) return;
try {
const [error, response] = await uni.request({
url: `${config.apiBaseUrl}/friends`,
method: 'GET',
header: {
Authorization: `Bearer ${token}`,
},
});
if (response.data) {
this.friends = response.data.data;
}
} catch (error) {
console.error(error);
}
},
toChat(item) {
const url = item.type === 'user'
? `/pages/index/chat?id=${item.id}&type=${item.type}&tid=${item.group_friend_id}`
: `/pages/index/chat?id=g_${item.group_friend_id}&type=${item.type}&tid=${item.group_friend_id}`;
uni.navigateTo({ url });
},
loadMoreFriends() {
this.page++;
this.loadFriends();
},
async invateFriends() {
try {
const token = uni.getStorageSync('token');
const [error, response] = await uni.request({
url: `${config.apiBaseUrl}/invateFriends`,
method: 'GET',
header: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
if (response.data.code === 0) {
this.friendsInv = response.data.data.map(friend => ({
...friend,
id: friend.id.toString(),
}));
} else {
this.friendsInv = [];
}
} catch (error) {
console.error(error);
}
},
goToLogin() {
uni.navigateTo({
url: '/pages/index/login',
});
},
gotadd() {
this.$refs.popupBag.open();
},
goaddurl() {
this.closepopupBag();
uni.navigateTo({
url: '/pages/index/addfriend',
});
},
gogroupurl() {
this.closepopupBag();
uni.navigateTo({
url: '/pages/index/addgroup',
});
},
myself() {
uni.navigateTo({
url: '/pages/index/profile',
});
},
closepopupBag() {
this.$refs.popupBag.close();
},
},
};
</script>
<style>
.container {
padding: 20px;
}
.bagDetail {
padding: 10px;
width: 100%;
height: 30%;
position: fixed;
background-color: #ffffff;
left: 0;
display: flex;
flex-direction: column;
}
#messages {
height: 300px;
overflow-y: scroll;
border: 1px solid #ccc;
margin-bottom: 10px;
}
input {
display: block;
margin: 10px 0;
}
button {
display: block;
margin: 10px 0;
}
.user-list {
margin-top: 20px;
border: 1px solid #ccc;
padding: 10px;
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 10px;
}
.close-button {
font-size: 22px;
cursor: pointer;
}
</style>