uni-app 117撤回消息功能(一)

简介: uni-app 117撤回消息功能(一)


chat.js

// app/controller/chat.js
const Controller = require('egg').Controller;
class ChatController extends Controller {
    // 连接socket
    async connect() {
        const { ctx, app, service } = this;
        if (!ctx.websocket) {
            ctx.throw(400, '非法访问');
        }
        // console.log(`clients: ${app.ws.clients.size}`);
        // 监听接收消息和关闭socket
        ctx.websocket
            .on('message', msg => {
                // console.log('接收消息', msg);
            })
            .on('close', (code, reason) => {
                // 用户下线
                console.log('用户下线', code, reason);
                let user_id = ctx.websocket.user_id;
                // 移除redis中的用户上线记录
                service.cache.remove('online_' + user_id);
                if (app.ws.user && app.ws.user[user_id]) {
                    delete app.ws.user[user_id];
                }
            });
    }
    // 发送消息
    async send() {
        const { ctx, app, service } = this;
        // 拿到当前用户id
        let current_user_id = ctx.authUser.id;
        // 验证参数
        ctx.validate({
            to_id: {
                type: 'int',
                required: true,
                desc: '接收人/群id'
            },
            chat_type: {
                type: 'string',
                required: true,
                range: {
                    in: ['user', 'group']
                },
                desc: '接收类型'
            },
            type: {
                type: 'string',
                required: true,
                range: {
                    in: ['text', 'image', 'video', 'audio', 'emoticon', 'card']
                },
                desc: '消息类型'
            },
            data: {
                type: 'string',
                required: true,
                desc: '消息内容'
            },
            options: {
                type: 'string',
                required: true
            }
        });
        // 获取参数
        let { to_id, chat_type, type, data, options } = ctx.request.body;
        // 单聊
        if (chat_type === 'user') {
            // 验证好友是否存在,并且对方没有把你拉黑
            let Friend = await app.model.Friend.findOne({
                where: {
                    user_id: to_id,
                    friend_id: current_user_id,
                    isblack: 0
                },
                include: [{
                    model: app.model.User,
                    as: "userInfo"
                }, {
                    model: app.model.User,
                    as: "friendInfo"
                }]
            });
            if (!Friend) {
                return ctx.apiFail('对方不存在或者已经把你拉黑');
            }
            // 验证好友是否被禁用
            if (!Friend.userInfo.status) {
                return ctx.apiFail('对方已被禁用');
            }
            // 构建消息格式
            let from_name = Friend.friendInfo.nickname ? Friend.friendInfo.nickname : Friend.friendInfo.username;
            if (Friend.nickname) {
                from_name = Friend.nickname;
            }
            let message = {
                id: (new Date()).getTime(), // 唯一id,后端生成唯一id
                from_avatar: Friend.friendInfo.avatar,// 发送者头像
                from_name, // 发送者昵称
                from_id: current_user_id, // 发送者id
                to_id, // 接收人/群 id
                to_name: Friend.userInfo.nickname ? Friend.userInfo.nickname : Friend.userInfo.username, // 接收人/群 名称
                to_avatar: Friend.userInfo.avatar, // 接收人/群 头像
                chat_type: 'user', // 接收类型
                type,// 消息类型
                data, // 消息内容
                options: {}, // 其他参数
                create_time: (new Date()).getTime(), // 创建时间
                isremove: 0, // 是否撤回
            }
            // 视频,截取封面
            if (message.type === 'video') {
                message.options.poster = message.data + '?x-oss-process=video/snapshot,t_10,m_fast,w_300,f_png';
            }
            // 音频,带上音频时长
            if (message.type === 'audio') {
                options = JSON.parse(options);
                message.options.time = options.time || 1;
            }
            // 名片
            if (message.type === 'card') {
                // 验证名片用户是否存在
                message.options = JSON.parse(options)
            }
            ctx.sendAndSaveMessage(to_id, message);
            // 存储到自己的聊天记录中 chatlog_当前用户id_user_对方用户id
            service.cache.setList(`chatlog_${current_user_id}_${message.chat_type}_${to_id}`, message);
            // 返回成功
            return ctx.apiSuccess(message);
        }
        // 群聊
        // 验证群聊是否存在,且你是否在该群中
        let group = await app.model.Group.findOne({
            where: {
                status: 1,
                id: to_id
            },
            include: [{
                model: app.model.GroupUser,
                attributes: ['user_id', 'nickname']
            }]
        });
        if (!group) {
            return ctx.apiFail('该群聊不存在或者已被封禁');
        }
        let index = group.group_users.findIndex(item => item.user_id === current_user_id);
        if (index === -1) {
            return ctx.apiFail('你不是该群的成员');
        }
        // 组织数据格式
        let from_name = group.group_users[index].nickname;
        let message = {
            id: (new Date()).getTime(), // 唯一id,后端生成唯一id
            from_avatar: ctx.authUser.avatar,// 发送者头像
            from_name: from_name || ctx.authUser.nickname || ctx.authUser.username, // 发送者昵称
            from_id: current_user_id, // 发送者id
            to_id, // 接收人/群 id
            to_name: group.name, // 接收人/群 名称
            to_avatar: group.avatar, // 接收人/群 头像
            chat_type: 'group', // 接收类型
            type,// 消息类型
            data, // 消息内容
            options: {}, // 其他参数
            create_time: (new Date()).getTime(), // 创建时间
            isremove: 0, // 是否撤回
            group: group
        }
        
        // 视频,截取封面
        if (message.type === 'video') {
            message.options.poster = message.data + '?x-oss-process=video/snapshot,t_10,m_fast,w_300,f_png';
        }
        // 音频,带上音频时长
        if (message.type === 'audio') {
            options = JSON.parse(options);
            message.options.time = options.time || 1;
        }
        // 名片
        if (message.type === 'card') {
            // 验证名片用户是否存在
            message.options = JSON.parse(options)
        }
        // 推送消息
        group.group_users.forEach(item => {
            if (item.user_id !== current_user_id) {
                ctx.sendAndSaveMessage(item.user_id, message);
            }
        });
        ctx.apiSuccess(message);
    }
    
    // 获取离线消息
    async getmessage() {
        const { ctx, app, service } = this;
        let current_user_id = ctx.authUser.id;
        let key = 'getmessage_' + current_user_id;
        let list = await service.cache.getList(key);
        // 清除离线消息
        await service.cache.remove(key);
        // 批量推送
        list.forEach(async (message) => {
            let d = JSON.parse(message);
            ctx.sendAndSaveMessage(current_user_id, d.message, d.msg);
        });
    }
    
    // 撤回 
    async recall(){
        const { ctx,app } = this;
        let current_user_id = ctx.authUser.id;
        ctx.validate({
            to_id:{
                type:'int',
                required:true,
                desc:'接收人/群id'
            },
            chat_type:{
                type:'string',
                required:true,
                range:{
                    in:['user','group']
                },
                desc:'接收类型'
            },
            id:{
                type:'int',
                required:true,
                desc:'消息id'
            }
        });
        let {to_id,chat_type,id} = ctx.request.body;
        let message = {
            from_id:current_user_id,
            to_id,
            chat_type,
            id
        }
        // 单聊
        if(chat_type === 'user'){
            ctx.sendAndSaveMessage(to_id,message,'recall');
            return ctx.apiSuccess(message);
        }
        // 群聊 
        let group = await app.model.Group.findOne({
            where:{
                id:to_id,
                status:1
            },
            include:[{
                model:app.model.GroupUser,
                attributes:['user_id']
            }]
        });
        if(group){
            group.group_users.forEach(item=>{
                if(item.user_id !== current_user_id){
                    ctx.sendAndSaveMessage(item.user_id,message,'recall');
                }
            });
        }
        return ctx.apiSuccess(message);
    }
    
}
module.exports = ChatController;

router.js

// 撤回消息
  router.post('/chat/recall',controller.chat.recall);

感谢大家观看,我们下次见

目录
相关文章
|
10月前
|
小程序 视频直播 数据安全/隐私保护
如何在1v1视频直播交友APP中实现防录屏防截屏功能?
婚恋交友市场快速增长,1v1社交应用海外投放增86.49%,中东、东南亚及北美需求旺盛。用户偏好私密高效交流,国内“云相亲”兴起。开发需合规备案、实名认证,并防范诈骗。本文详解原生APP防录屏技术:Android通过MediaProjection检测,iOS监听UIScreen状态,结合动态水印、远程销毁等增强防护,平衡体验与安全。
|
10月前
|
JavaScript API 开发工具
如何在原生App中调用Uniapp的原生功能?
如何在原生App中调用Uniapp的原生功能?
1130 139
|
11月前
|
移动开发 小程序 Android开发
基于 uni-app 开发的废品回收类多端应用功能与界面说明
本文将对一款基于 uni-app 开发的废品回收类多端应用,从多端支持范围、核心功能模块及部分界面展示进行客观说明,相关资源信息也将一并呈现。
333 0
|
10月前
|
存储 自然语言处理 算法
参照Yalla、Hawa等主流APP核心功能,开发一款受欢迎的海外语聊需要从哪些方面入手
海外语聊APP开发需结合Yalla、Hawa等主流产品,聚焦多语言支持、实时音视频、社交互动与安全合规。兼顾技术架构、本地化运营与法律风险,避免劣质成品代码,平衡创新与成本,打造差异化出海产品。(239字)
|
存储 Java PHP
轻量化短视频电商直播带货APP源码全解析:核心功能与设计流程​
在电商直播热潮下,开发专属直播带货APP成为抢占市场关键。本文详解原生开发轻量化APP的核心功能与全流程设计,涵盖用户登录、商品浏览、直播互动、购物车、订单及售后功能,并介绍安卓端Java、苹果端Object-C、后台PHP的技术实现,助力打造高效优质的直播电商平台。
|
数据库
《仿盒马》app开发技术分享-- 回收订单页功能完善(45)
上一节我们实现了订单的待取件、已取消状态展示,并且成功实现了修改订单状态后的列表刷新,实现了云端数据的修改,这一节我们来实现订单页剩下的两个板块的业务逻辑,分别是运输中、已完成状态下的列表展示以及订单状态的修改
233 1
|
存储 移动开发 监控
App Trace功能实战:一键拉起、快速安装与免提写邀请码的应用实践
App Trace系统通过一键拉起、快速安装和免提写邀请码三大功能,显著提升用户转化率、安装成功率和邀请注册率。结合深度技术实现与优化,助力公司用户增长,成为移动端核心基础设施。
《仿盒马》app开发技术分享-- 扫一扫功能(35)
随着app的逐渐完善,我们现在需要在细节处做更多的打磨,在首页我们添加了很多静态的按钮和组件,现在我们开始对这些组件进行功能的添加,这次首先实现的是首页头部的扫一扫功能,扫一扫我们实现扫码后跳转商品详情页
258 0
|
存储 数据库
《仿盒马》app开发技术分享-- 购物车功能完善(14)
上一节我们实现了购物车商品列表的状态切换,已添加商品数量的增减,已添加商品滑动删除,已添加商品在选中情况下的价格计算。这一节我们在这些功能的基础上实现云端记录,因为我们现在只有数据的查询是从云端获取的,其他的操作虽然都实现了相对应的功能,但是当我们操作完,关闭app,再打开不会有对应的记录,有的同学可能会说,那我们把数据用首选项或者数据库的形式存储就可以了吧? 那如果我更换了另一个设备那这些添加的数据是不是就又不能使用了?所以我们的每个操作,最好都是提交到云端,这样我们在其他设备,在退出应用,切换账号这些情况下都能很好的保存我们操作后的购物车状态。
206 0
|
前端开发
《仿盒马》app开发技术分享-- 购物车基础功能实现(13)
上一节我们实现了加入购物车和购物车列表的简单展示。对一个电商类的应用来说,这很显然是不够的,我们的购物车内容应该更加的丰富,他需要用户能自主的去选择想要结算的商品,删除一些不需要的商品,或者取消掉一些本次不结算的商品,同时根据选择的不同,我们需要把相对应的价格和选择的数量等信息传递给用户,帮助用户节省更多的时间。
253 0

热门文章

最新文章