用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>
相关推荐
上优1 小时前
uniapp 选择 省市区 省市 以及 回显
大数据·elasticsearch·uni-app
大白要努力!2 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟3 小时前
Android音频采集
android·音视频
小白也想学C4 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程4 小时前
初级数据结构——树
android·java·数据结构
闲暇部落6 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX8 小时前
Android 分区相关介绍
android
大白要努力!9 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee9 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood10 小时前
Perfetto学习大全
android·性能优化·perfetto