uni-app+php+workman实现简单聊天功能之交互实现(会话列表)

2022-09-08 16:29:46 浏览数 (1)

前面介绍了【Laravel中Websocket基本使用(Workerman)】 基于workman的基础上实现了【uni-app php workman实现简单聊天功能之API开发】、【uni-app php workman实现简单聊天功能之聊天模块封装】 接下来完成前后端交互,本文只介绍主要页面和主要代码 我们涉及到的页面有主要两个

  1. 消息列表页
  2. 消息详情页

msg.vue

代码语言:javascript复制
<template>
    <view>
        <!-- 消息列表 -->
        <template v-if="list.length>0">
            <block v-for="item,index in list" :key="index">
                <msg-list :item="item" :index="index"></msg-list>
            </block> 
        </template>
        <view>
<template>
代码语言:javascript复制
<script>
    import msgList from "@/components/msg/msg-list.vue"
    export default {
    components:{msgList},
    data() {
        return {
            firstload:false,
            show:false,
            list:[]
        }
    },
    onShow(){
        //获取消息列表
        this.getdata()
        console.log(this.list)
    },
    onLoad() {
        //监听消息
        uni.$on('UserChat',data=>{
            //将最新消息置顶更新
            let index = this.list.findIndex(val=>{
                return val.userid === data.from_id;
            });
            //如果当前会话存在则更新时间、内容、未读数,并进行置顶
            if(index!==-1){
                this.list[index].data = data.data
                this.list[index].time = data.time
                this.list[index].noreadnum  ;
                //置顶
                this.list = this.$chat.__toFirst(this.list,index)
                return

            }
            //如果当前会话不存在--新消息 则将当前消息追加到消息列表最前面
            let obj = this.$chat.__format(data,{type:"chatlist"});
            obj.noreadnum=1;
            this.list.unshift(obj);
        })
    },
    methods: {
        getdata(){
            try{
                let userid = User.userinfo.id;
                if(!userid) return this.firstload = true;
                this.list = [];
                let list = uni.getStorageSync('chatlist' userid)//获取消息列表
                list = list?JSON.parse(list):[];
                this.list = list;//添加到消息列表
            }catch(e){
                uni.showToast({
                    title: '加载失败~',
                    icon:'none'
                });
            }
            this.firstload = true;

        }

...

在页面初始化的时候,我们调用getdata获取消息列表数据,从本地存储中取到,因为我们在收到消息的时候会将其存储到本地存储,并进行未读消息的统计。可参照前面【uni-app php workman实现简单聊天功能之聊天模块封装】 同时本页面还监听消息事件,当收到消息的时候,对最新消息进行置顶 本页面使用了msgList组件

代码语言:javascript复制
<template>
        <view class="flex align-center p-2 border-bottom animate__animated animate__fast animate__fadeIn" @click="open">
            <image :src="item.userpic" style="height: 80rpx;width: 80rpx;" 
            class="rounded-circle mr-2">
            </image>
            <view class="flex flex-column flex-1">
                <view class="flex align-center justify-between">
                    <text class="font-md">{{item.username}}</text>
                    <text class="font font-sm text-secondary">{{item.time}}</text>
                </view>
                <view class="flex align-center justify-between">
                    <text class="text-secondary text-ellipsis" style="max-width: 500rpx;">
                        {{item.data}}
                    </text>
                    
                    <uni-badge :text="getItemNoreadnum" type="error" v-if="getItemNoreadnum"></uni-badge>
                </view>
            </view>
        </view>
</template>

<script>
    import uniBadge from "@/components/uni-ui/uni-badge/uni-badge.vue"
    export default{
        components:{
            uniBadge
        },
        //接受聊天数据
        props:['item'],
        methods:{
            open(){
                
                uni.navigateTo({
                    "url":"../../pages/user-chat/user-chat?userinfo=" JSON.stringify({
                        userid:this.item.userid,
                        username:this.item.username,
                        userpic:this.item.userpic
                    })
                })
                this.$chat.Read(this.item)//更新未读数据   
            }
            
        },
        computed:{
            getItemNoreadnum(){
                return this.item.noreadnum
            }
        }
    }
    ...

该组件主要实现列表消息渲染和跳转操作,消息未读清零 当消息列表被点击时,会跳转到消息详情页并传递对方用户的相关参数,在进行调用chat模块的Read进行消息清零操作 效果图展示

user-chat

代码语言:javascript复制
<template>
    <view>
        <!-- 聊天列表 -->
        <scroll-view scroll-y="true" 
        style="position: absolute;left:0;top:0;right:0;bottom: 100rpx;"
        :scroll-into-view="scrollInfo" scroll-with-animation>
            <block v-for="item,index in list" :key="index">
                <view :id="'chat' index">
                    <!-- 头像一直左上方 | 左边 | 如果不是第一条消息传入上一次消息时间-->
                    <user-chat-list  v-if="!item.isme" :item="item" :index="index " :pretime="index>0?list[index-1].create_time:0"></user-chat-list>
                    
                </view>
                <!-- 右边 -->
                <view v-if="item.isme" class="flex align-start px-2" style="flex-direction: row-reverse;">
                    <image :src="item.userpic" style="width:100rpx;height:100rpx" class="rounded-circle">
                        <view class="bg-light p-2 rounded mx-2" style="min-width: 200rpx;max-width: 400rpx;">
                            {{item.data }}{{item.userid}}
                        </view>
                    </image>
                </view>
            </block>
            
        </scroll-view>
        <bottom-input @submit="submit"></bottom-input>
    </view>
</template>
代码语言:javascript复制
export default {
        components:{
            userChatList,bottomInput
        },
        data() {
            return {
                scrollInfo:"",
                scrollH:500,
                focus:true,
                loadtext:'加载更多',
                list:[]
            }
        },
        onLoad(e){
             //获取发送方用户信息
             let userinfo = JSON.parse(e.userinfo)
             //没有该用户
             if(!userinfo.userid){
                 uni.showToast({
                     title: '该用户不存在',
                    icon:'none'
                 });
                 return uni.navigateBack({
                     delta:1
                 })
             }
             //设置当前聊天对象
             this.$chat.CurrentToUser = {
                 userid:userinfo.userid,
                 username:userinfo.username,
                 userpic:userinfo.userpic
             }
             //修改导航标题
             uni.setNavigationBarTitle({
                 'title':userinfo.username
             })
        },//退出聊天的时候
        onUnload() {
            //初始化聊天对象
            this.$chat.CurrentToUser = {
                userid:0,
                username:"",
                userpic:"",
            }
        },
        onReady(){
            this.__init()
        },
        methods: {
            //接受聊天数据(首次只获取10条数据)
            async getdata(isall = false){
                try{
                    let key = 'chatdetail_' this.User.userinfo.id '_' this.$chat.CurrentToUser.userid;
                    //获取聊天记录
                    let list = uni.getStorageSync(key);
                    // console.log(list)
                    list = list?JSON.parse(list):[];
                    //首次加载10条
                    if(!isall && list.length>10){
                        return this.list = list.splice(0,10);
                    }
                    //加载剩下的数据
                    this.list = list;
                    this.loadtext = '';
                    
                    
                }catch(e){
                    uni.showToast({
                        title:'加载失败',
                        icon:'none'
                    })
                }
            },
            submit(data){
                //发送消息
                let obj = this.$chat.Send({'type':'text','data':data,'isme':true});
                console.log(obj)
                this.$.post('chat/send',{
                     'to_id':this.$chat.CurrentToUser.userid,
                    'from_userpic':'https://cdn.learnku.com/uploads/images/201710/14/1/s5ehp11z6s.png',
                    'type':'text',
                    'data':data
                },{
                    header: {
                        'Accept':'application/json',
                        'Authorization':'Bearer ' uni.getStorageSync('access_token')
                    }
                }).then(res=>{
                    console.log(res)
                    console.log('发送完毕')
                    
                    //错判断
                     //成功处理
                     // return this.resultUserBind(res.data.data)
                })
                
                this.list.push(obj)
                
                this.pageToBottom()
            },
            //滚动底部
            pageToBottom(){
                let lastIndex = this.list.length-1
                if(lastIndex<0)return;
                this.scrollInfo = 'chat' lastIndex
            },
            //初始化参数
            __init(){
                //获取窗口消息
                try{
                    const res = uni.getSystemInfoSync();
                    this.scrollH = res.windowHeight-uni.upx2px(101);
                    
                }catch(e){
                    
                }
                //获取聊天历史记录
                this.getdata();
                //至于底部
                this.pageToBottom()
                //监听消息
                uni.$on('UserChat',data=>{
                    this.list.push(this.$chat.__format(data,{
                        type:'chatdetail',
                        isme:false,
                        olddata:this.list
                    }));
                this.pageToBottom()
                console.log('监听到数据')
                // console.log(data)
                })
            }
        }
        
    }
</script>

消息详情页加载的时候首先对聊天用户进行了初始化,保存在chat模块,然后调用初始化函数__init()该函数用于

  1. 设置内容滚动高度
  2. 获取聊天记录
  3. 监听消息,对消息存储(chat模块),最新消息展示

当发送消息时,调用chat模块的Send函数,进行数据格式,数据存储等 然后在发送ajax与服务器进行交互 服务端拿到数据后首先判断接收方用户是否在线,如果在线则转发,不在线则存储到缓存

代码语言:javascript复制
public function send(ChatRequest $request){
        // 1. 验证数据是否合法
        // 2. 组织数据

        $data = $this->resdata($request);
        // return response()->json($data);
        $to_id = $request->to_id;
        // 3. 验证对方用户是否在线
        if (Gateway::isUidOnline($to_id)) {
            // 直接发送
            Gateway::sendToUid($to_id,json_encode($data));
            // 写入数据库
            // 返回发送成功
            return $this->showResCodeWithOutData('ok');
        }
        // 不在线,写入消息队列
        // 获取之前消息
       
        $Cache = Cache::get('userchat_'.$to_id);
        if (!$Cache || !is_array($Cache)) $Cache = [];
        $Cache[] = $data;
        // 写入数据库
        // 写入消息队列(含id)
        Cache::set('userchat_'.$to_id,$Cache);
        return $this->showResCodeWithOutData('ok');
    }

效果展示

0 人点赞