用uniapp 及socket.io做一个简单聊天app 5

聊天中的通知及好友申请:

如下图效果

聊天的效果:

这里的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>
相关推荐
晨曦_子画16 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
孤客网络科技工作室38 分钟前
AJAX 全面教程:从基础到高级
android·ajax·okhttp
Mr Lee_2 小时前
android 配置鼠标右键快捷对apk进行反编译
android
顾北川_野2 小时前
Android CALL关于电话音频和紧急电话设置和获取
android·音视频
&岁月不待人&3 小时前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
瑶琴AI前端4 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
mosen8684 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
Winston Wood4 小时前
Android Parcelable和Serializable的区别与联系
android·序列化
清风徐来辽5 小时前
Android 项目模型配置管理
android
帅得不敢出门5 小时前
Gradle命令编译Android Studio工程项目并签名
android·ide·android studio·gradlew