接口

router.js

   // 推送群公告router.post('/group/remark',controller.group.remark);

app/controller/group.js

'use strict';const Controller = require('egg').Controller;class GroupController extends Controller {// 获取群聊列表async list() {const { ctx, app } = this;let current_user_id = ctx.authUser.id;let page = ctx.params.page ? parseInt(ctx.params.page) : 1;let limit = ctx.query.limit ? parseInt(ctx.query.limit) : 10;let offset = (page - 1) * limit;let rows = await app.model.Group.findAll({where: {status: 1},include: [{model: app.model.GroupUser,where: {user_id: current_user_id}}]});return ctx.apiSuccess(rows);}// 创建群聊async create() {const { ctx,app } = this;// 拿到当前用户idlet current_user_id = ctx.authUser.id;// 验证参数ctx.validate({ids:{require:true,type:'array'}});let { ids } = ctx.request.body;// 验证是否是我的好友let friends = await app.model.Friend.findAll({where:{user_id:current_user_id,friend_id:ids},include:[{model:app.model.User,as:'friendInfo',attributes:['nickname','username']}]});if (!friends.length) {return ctx.apiFail('请选择需要加入群聊的好友');}// 创建群聊let name = friends.map(item=>item.friendInfo.nickname || item.friendInfo.username);name.push(ctx.authUser.nickname || ctx.authUser.username); // 将自己的数据加入let group = await app.model.Group.create({name:name.join(','),avatar:'',user_id:current_user_id});// 加入群聊用户let data = friends.map(item=>{return {user_id:item.friend_id,group_id:group.id}});data.unshift({user_id:current_user_id,group_id:group.id});await app.model.GroupUser.bulkCreate(data);// 消息推送let message = {id:(new Date()).getTime(), // 唯一id,后端生成唯一idfrom_avatar:ctx.authUser.avatar,// 发送者头像from_name:ctx.authUser.nickname || ctx.authUser.username,// 发送者昵称from_id:current_user_id, // 发送者idto_id:group.id,// 接收人idto_name:group.name,// 接收人/群 名称to_avatar:group.avatar,// 接收人/群 头像 chat_type:'group', // 接收类型type:'system', // 消息类型data:'创建群聊成功,可以聊天了', // 消息内容options:{}, // 其他参数create_time:(new Date()).getTime(),// 创建时间isremove:0, // 是否撤回group:group}data.forEach(item =>{ctx.sendAndSaveMessage(item.user_id,message);});ctx.apiSuccess('ok');}// 查看群资料async info() {const { ctx, app } = this;let current_user_id = ctx.authUser.id;// 验证参数ctx.validate({id: {required: true,type: 'int',desc: "群组id"}});let { id } = ctx.params;// 群组是否存在let group = await app.model.Group.findOne({where: {status: 1,id},include: [{model: app.model.GroupUser,attributes: ['user_id', 'nickname'],include: [{model: app.model.User,attributes: ['id', 'nickname', 'avatar', 'username']}]}]});if (!group) {return ctx.apiFail('该群聊不存在或者已被封禁');}// 当前用户是否是该群成员let index = group.group_users.findIndex(item => item.user_id === current_user_id);if (index === -1) {return ctx.apiFail('你不是该群成员,没有权限');}ctx.apiSuccess(group);}// 修改群名称async rename(){const { ctx,app } = this;let current_user_id = ctx.authUser.id;// 参数验证ctx.validate({id:{required:true,type:'int',desc:'群组id'},name:{required:true,type:'string',desc:'群名称'}});let { id,name } = ctx.request.body;// 是否存在 let group = await app.model.Group.findOne({where:{id,status:1 },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('你不是该群成员');}// 验证是否是群主if(group.user_id !== current_user_id){return ctx.apiFail('你不是管理员,没有权限');}// 修改群名称group.name = name;await group.save();let from_name = group.group_users[index].nickname || ctx.authUser.nickname || ctx.authUser.username;// 消息推送let message = {id:(new Date()).getTime(), // 唯一id,后端生成唯一idfrom_avatar:ctx.authUser.avatar,// 发送者头像from_name,// 发送者昵称from_id:current_user_id, // 发送者idto_id:group.id,// 接收人idto_name:group.name,// 接收人/群 名称to_avatar:group.name,// 接收人/群 头像 chat_type:'group', // 接收类型type:'system', // 消息类型data:`${from_name} 修改群名称为 ${name}`, // 消息内容options:{}, // 其他参数create_time:(new Date()).getTime(),// 创建时间isremove:0, // 是否撤回group:group}// 推送消息group.group_users.forEach(item=>{ctx.sendAndSaveMessage(item.user_id,message);});ctx.apiSuccess('ok');}// 推送群公告async remark(){const { ctx,app } = this;let current_user_id = ctx.authUser.id;// 参数验证ctx.validate({id:{required:true,type:'int',desc:'群组id'},remark:{required:true,type:'string',desc:'群公告'}});let { id,remark } = ctx.request.body;// 是否存在 let group = await app.model.Group.findOne({where:{id,status:1 },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('你不是该群成员');}// 验证是否是群主if(group.user_id !== current_user_id){return ctx.apiFail('你不是管理员,没有权限');}// 修改群公告group.remark = remark;await group.save();let from_name = group.group_users[index].nickname || ctx.authUser.nickname || ctx.authUser.username;// 消息推送let message = {id:(new Date()).getTime(), // 唯一id,后端生成唯一idfrom_avatar:ctx.authUser.avatar,// 发送者头像from_name,// 发送者昵称from_id:current_user_id, // 发送者idto_id:group.id,// 接收人idto_name:group.name,// 接收人/群 名称to_avatar:group.name,// 接收人/群 头像 chat_type:'group', // 接收类型type:'system', // 消息类型data:`[新公告] ${remark}`, // 消息内容options:{}, // 其他参数create_time:(new Date()).getTime(),// 创建时间isremove:0, // 是否撤回group:group}// 推送消息group.group_users.forEach(item=>{ctx.sendAndSaveMessage(item.user_id,message);});ctx.apiSuccess('ok');}
}
module.exports = GroupController;

页面

chat.js

import $U from "./util.js";
import $H from './request.js';
class chat {constructor(arg) {this.url = arg.urlthis.isOnline = falsethis.socket = null// 获取当前用户相关信息let user = $U.getStorage('user');this.user = user ? JSON.parse(user) : {},// 初始化聊天对象this.TO = false;// 连接和监听if (this.user.token) {this.connectSocket()}}// 连接socketconnectSocket() {console.log(this.user);this.socket = uni.connectSocket({url: this.url + '?token=' + this.user.token,complete: () => {}})// 监听连接成功this.socket.onOpen(() => this.onOpen())// 监听接收信息this.socket.onMessage((res) => this.onMessage(res))// 监听断开this.socket.onClose(() => this.onClose())// 监听错误this.socket.onError(() => this.onError())}// 监听打开onOpen() {// 用户状态上线this.isOnline = true;console.log('socket连接成功');// 获取用户离线消息this.getMessage();}// 获取离线消息getMessage(){$H.post('/chat/getmessage');}// 监听关闭onClose() {// 用户下线this.isOnline = false;this.socket = null;console.log('socket连接关闭');}// 监听消息onMessage(data) {console.log('监听消息', data);let res = JSON.parse(data.data)// console.log('监听接收消息',res)// 错误switch (res.msg) {case 'fail':return uni.showToast({title: res.data,icon: 'none'});break;case 'recall': // 撤回消息this.handleOnRecall(res.data)break;case 'updateApplyList': // 新的好友申请$store.dispatch('getApply');break;case 'moment': // 朋友圈更新this.handleMoment(res.data)break;default:// 处理消息this.handleOnMessage(res.data)break;}}// 处理消息async handleOnMessage(message) {// 添加消息记录到本地存储中let { data } = this.addChatDetail(message, false)// 更新会话列表this.updateChatList(data, false)// 全局通知uni.$emit('onMessage', data)// 消息提示// this.messageNotice()}// 监听连接错误onError() {// 用户下线this.isOnline = false;this.socket = null;console.log('socket连接错误');}// 关闭连接close() {this.socket.close()}// 创建聊天对象createChatObject(detail) {this.TO = detail;console.log('创建聊天对象', this.TO)}// 销毁聊天对象destoryChatObject() {this.TO = false}// 组织发送信息格式formatSendData(params) {return {id: 0, // 唯一id,后端生成,用于撤回指定消息from_avatar: this.user.avatar, // 发送者头像from_name: this.user.nickname || this.user.username, // 发送者昵称from_id: this.user.id, // 发送者idto_id: params.to_id || this.TO.id, // 接收人/群 idto_name: params.to_name || this.TO.name, // 接收人/群 名称to_avatar: params.to_avatar || this.TO.avatar, // 接收人/群 头像chat_type: params.chat_type || this.TO.chat_type, // 接收类型type: params.type, // 消息类型data: params.data, // 消息内容options: params.options ? params.options : {}, // 其他参数create_time: (new Date()).getTime(), // 创建时间isremove: 0, // 是否撤回sendStatus: params.sendStatus ? params.sendStatus : "pending" // 发送状态,success发送成功,fail发送失败,pending发送中}}// 发送信息send(message, onProgress = false) {return new Promise((result, reject) => {// 添加消息历史记录// this.addChatDetail();let { k } = this.addChatDetail(message);// 更新会话列表 this.updateChatList(message);// 验证是否上线if (!this.checkOnLine()) return reject('未上线');// 上传文件let isUpload = (message.type !== 'text' && message.type !== 'emoticon' && message.type !=='card' && !message.data.startsWith('http://tangzhe123-com'))let uploadResult = ''if (isUpload) {uploadResult = $H.upload('/upload', {filePath: message.data}, onProgress)if (!uploadResult) {// 发送失败message.sendStatus = 'fail'// 更新指定历史记录this.updateChatDetail(message, k)// 断线重连提示return reject(err)}}$H.post('/chat/send', {to_id: this.TO.id,type: message.type,chat_type: this.TO.chat_type,data: message.data,}).then(res => {// 发送成功console.log('chat.js发送成功');message.id = res.idmessage.sendStatus = 'success';// 更新指定历史记录this.updateChatDetail(message, k);result(res);}).catch(err => {// 发送失败console.log('chat.js发送失败');message.sendStatus = 'fail';// 更新指定历史记录this.updateChatDetail(message, k);// 断线重连提示result(err);});})}// 验证是否上线checkOnLine() {if (!this.isOnline) {// 断线重连提示this.reconnectConfirm();return false;}return true;}// 断线重连提示reconnectConfirm() {uni.showModal({title: '你已经断线,是否重新连接?',content: '重新连接',success: res => {if (res.confirm) {this.connectSocket();}},});}// 添加聊天记录addChatDetail(message, isSend = true) {console.log('添加到聊天记录');// 获取对方idlet id = message.chat_type === 'user' ? (isSend ? message.to_id : message.from_id) : message.to_id;if (!id) {return {data: {},k: 0}}// key值:chatDetail_当前用户id_会话类型_接收人/群idlet key = `chatDetail_${this.user.id}_${message.chat_type}_${id}`;console.log(key);// 获取原来的聊天记录let list = this.getChatdetail(key)console.log('获取原来的聊天记录', list);// 标识message.k = 'k' + list.lengthlist.push(message)// 加入存储console.log('加入存储', message);this.setStorage(key, list);// 返回return {data: message,k: message.k}}// 更新指定历史记录async updateChatDetail(message, k, isSend = true) {// 获取对方idlet id = message.chat_type === 'user' ? (isSend ? message.to_id : message.from_id) : message.to_id;// key值:chatDetail_当前用户id_会话类型_接收人/群idlet key = `chatDetail_${this.user.id}_${message.chat_type}_${id}`;// 获取原来的聊天记录let list = this.getChatdetail(key);// 根据k查找对应聊天记录let index = list.findIndex(item => item.k === k);if (index === -1) return;list[index] = message;// 存储this.setStorage(key, list);}// 获取聊天记录getChatdetail(key = false) {key = key ? key : `chatDetail_${this.user.id}_${this.TO.chat_type}_${this.TO.id}`;return this.getStorage(key);}// 格式化会话最后一条消息显示formatChatItemData(message, isSend) {let data = message.data.length > 18 ? message.data.slice(0,17) + '...' : message.data;switch (message.type) {case 'emoticon':data = '[表情]'break;case 'image':data = '[图片]'break;case 'audio':data = '[语音]'break;case 'video':data = '[视频]'break;case 'card':data = '[名片]'break;}data = isSend ? data : `${message.from_name}: ${data}`return data}// 更新会话列表updateChatList(message, isSend = true) {// 获取本地存储会话列表let list = this.getChatList()// 是否处于当前聊天中let isCurrentChat = false// 接收人/群 id/头像/昵称let id = 0let avatar = ''let name = ''// 判断私聊还是群聊if (message.chat_type === 'user') { // 私聊// 聊天对象是否存在isCurrentChat = this.TO ? (isSend ? this.TO.id === message.to_id : this.TO.id === message.from_id) :falseid = isSend ? message.to_id : message.from_idavatar = isSend ? message.to_avatar : message.from_avatarname = isSend ? message.to_name : message.from_name} else { // 群聊isCurrentChat = this.TO && (this.TO.id === message.to_id)id = message.to_idavatar = message.to_avatarname = message.to_name}// 会话是否存在let index = list.findIndex(item => {return item.chat_type === message.chat_type && item.id === id})// 最后一条消息展现形式// let data = isSend ? message.data : `${message.from_name}: ${message.data}`let data = this.formatChatItemData(message, isSend)// 会话不存在,创建会话// 未读数是否 + 1let noreadnum = (isSend || isCurrentChat) ? 0 : 1if (index === -1) {let chatItem = {id, // 接收人/群 idchat_type: message.chat_type, // 接收类型 user单聊 group群聊avatar, // 接收人/群 头像name, // 接收人/群 昵称update_time: (new Date()).getTime(), // 最后一条消息的时间戳data, // 最后一条消息内容type: message.type, // 最后一条消息类型noreadnum, // 未读数istop: false, // 是否置顶shownickname: false, // 是否显示昵称nowarn: false, // 消息免打扰strongwarn: false, // 是否开启强提醒}// 群聊if (message.chat_type === 'group' && message.group) {chatItem.shownickname = truechatItem.name = message.to_namechatItem = {...chatItem,user_id: message.group.user_id, // 群管理员idremark: "", // 群公告invite_confirm: 1, // 邀请确认}list.unshift(chatItem)}} else { // 存在,更新会话// 拿到当前会话let item = list[index]// 更新该会话最后一条消息时间,内容,类型item.update_time = (new Date()).getTime()item.name = message.to_nameitem.data = dataitem.type = message.type// 未读数更新item.noreadnum += noreadnum// 置顶会话list = this.listToFirst(list, index)}// 存储let key = `chatlist_${this.user.id}`this.setStorage(key, list)// 更新未读数this.updateBadge(list)// 通知更新vuex中的聊天会话列表uni.$emit('onUpdateChatList', list)return list}// 获取聊天记录getChatList(message, isSend = true) {// 获取本地存储会话列表let list = this.getChatList();// 是否处在当前聊天中let isCurrentChat = false// 接收人/群 id/头像/昵称let id = 0;let avatar = '';let name = '';// 判断私聊还是群聊if (message.chat_type === 'user') {// 私聊isCurrentChat = this.TO ? (isSend ? this.TO.id === message.to_id : message.from_id) : false;id = isSend ? message.to_id : message.from_id;avatar = isSend ? message.to_avatar : message.from_avatarname = isSend ? message.to_name : message.from_name} else {// 群聊}// 会话是否存在let index = list.findIndex(item => {return item.chat_type === message.chat_type && item.id === id;})// 最后一条消息展现形式let data = isSend ? message.data : `${message.from_name}:${message.data}`;// 未读数是否 +1let noreadnum = (isSend || isCurrentChat) ? 0 : 1;// 会话不存在 创建会话if (index === -1) {let chatItem = {id, // 接收人/群 idchat_type: message.chat_type, // 接收类型 user 单聊 group群聊name, // 接收人/群 昵称avatar, // 接收人/群 头像update_time: (new Date()).getTime(), // 最后发送的时间data, // 最后一条消息的内容type: message.type,noreadnum: 1, // 未读数istop: false, // 是否置顶shownickname: false, // 是否显示昵称nowarn: false, // 是否免打扰strongwarn: false, //  是否强提醒}if (message.chat_type === 'group') {chatItem = {...chatItem,user_id: 0, // 管理员idremark: '', // 群公告invite_confirm: 0 // 邀请确认}}list.unshift(chatItem)} else {// 存在,更新会话// 拿到当前会话let item = list[index]// 更新改会话最后一条消息时间,内容,类型item.update_time = (new Date()).getTime();item.data = data;item.type = message.type;// 未读数更新item.noreadnum += noreadnum// 置顶会话list = this.listToFirst(list, index);}// 存储let key = `chatlist_${this.user.id}`;this.setStorage(key, list);// 更新未读数this.updateBadge(list);// 更新vuex中的聊天会话列表uni.$emit('onUpdateChatList', list);console.log('获取到的会话列表:',list)return list;/*** {id:1,  // 接收人/群 idchat_type:'user', // 接收类型 user 单聊 group群聊name:'昵称', // 接收人/群 昵称avatar:"/static/images/demo/demo6.jpg", // 接收人/群 头像type:'',// 最后一条消息类型update_time:1628069958, // 最后发送的时间data:"你好啊,哈哈哈", // 最后一条消息的内容noreadnum:1, // 未读数istop:false, // 是否置顶shownickname:0, // 是否显示昵称nowarn:0, // 是否免打扰strongwarn:0, //  是否强提醒user_id://管理员id,remark:'公告', // 群公告invite_confirm:0, // 邀请确认},**/}// 获取本地存储会话列表getChatList() {let key = `chatlist_${this.user.id}`;return this.getStorage(key);}// 读取会话async readChatItem(id,chat_type){// 获取所有会话列表let list = this.getChatList();// 找到当前会话let index = list.findIndex(item=>item.id === id && item.chat_type === chat_type);if(index !== -1){list[index].noreadnum = 0;let key = `chatlist_${this.user.id}`;this.setStorage(key,list);// 重新获取未读数this.updateBadge();// 更新会话列表状态uni.$emit('onUpdateChatList',list);}}// 获取指定会话getChatListItem(id,chat_type){// 获取所有会话列表let list = this.getChatList()// 找到当前会话let index = list.findIndex(item=>item.id === id && item.chat_type === chat_type)if(index !== -1){return list[index]}return false}// 更新未读数async updateBadge(list = false) {// 获取所有会话列表list = list ? list : this.getChatList()// 统计所有未读数let total = 0list.forEach(item => {total += item.noreadnum})// 设置底部导航栏角标 if (total > 0) {uni.setTabBarBadge({index: 0,text: total <= 99 ? total.toString() : '99+'})} else {uni.removeTabBarBadge({index: 0})}uni.$emit('totalNoreadnum', total)}// 获取存储getStorage(key) {let list = $U.getStorage(key);return list ? JSON.parse(list) : [];}// 设置存储setStorage(key, value) {return $U.setStorage(key, JSON.stringify(value));}// 数组置顶listToFirst(arr, index) {if (index != 0) {arr.unshift(arr.splice(index, 1)[0]);}return arr;}
}
export default chat

我测试的结果,如下图


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

uni-app 99群公告推送功能(一)相关推荐

  1. 你的 APP 能否精准「推送」击中用户?!

    亲,爆款产品折上折,全场 5.9 元包邮! 福利来袭,充值送好礼~ 道具特惠,入手不亏. 毫无疑问,11 月还没到,"双 11"先到了.不仅是剁手 APP,各大应用都绞尽脑汁趁着这 ...

  2. 技术分享| 基于RTM 实现的呼叫邀请如何添加推送功能?

    RTM 实时消息服务,解决了在线实时信令的传递,如何配合推送服务,去做离线通知功能一直困扰着开发者,本文从 RTM 的功能以及响应机制入手,教大家如何通过RTM配合第三方推送服务来完成离线消息通知. ...

  3. openfire消息通知推送_APP消息推送功能之前端后台设计

    APP消息推送功能之前端后台设计 最近有不少小伙伴问APP消息推送功能,前端.后台如何设计的?消息系统的架构是什么样的?最近刚好做到后台消息推送这块,简单谈谈个人心得,欢迎拍砖. 消息推送是让自己的用 ...

  4. uniapp推送功能实现

    1.manifest.json打开推送功能 2.去推送配置页面 3.填写信息(在云打包页面可以查看) 4.app.vue页面添加代码 onLaunch: function() {//#ifdef AP ...

  5. Android 实现推送功能

    近几天正研究Android推送的事,看到这篇文章觉得总结得真好,好东西一定要转过来.哈哈. 原文地址:http://blog.csdn.net/joshua_yu/article/details/65 ...

  6. uniapp 集成推送功能

    uniapp 集成推送功能 1,在开发后台点击需要开通的应用–点击uniPush–配置对应的信息,默认情况下,Android的包名跟APPID的相同 2,云打包时勾选APP模块配置–push(消息推送 ...

  7. uni-app打包安卓app如何接入极光推送(JG-JPush)?

    最近公司在做uni-app的跨端应用,其中在打包app时需要用到消息推送功能,经过一番摸索也是终于弄通并成功集成了第三方极光推送.话不多说,直接开撸: 一.我们需要用到的一些插件以及极光平台的官网链接 ...

  8. 推荐一款 Flutter Push 推送功能插件

    又到了推荐好插件的时候了.开发 APP 避免不了使用「推送」功能.比如,新上架一个商品,或者最新的一条体育新闻,实时推送给用户. 比较了几家推送平台,貌似「极光」出了 Flutter 插件,所以就拿它 ...

  9. Android之集成友盟推送功能

    友盟是中国最大的移动开发者服务平台,为移动开发者提供免费的应用统计分析.社交分享.消息推送.自动更新.在线参数.移动推广效果分析.微社区等app开发和运营解决方案. 如何快速集成友盟推送功能: 1. ...

最新文章

  1. shell最大出现和连续出现次数_从 1 到 n 整数中 1 出现的次数
  2. 使用PHP Excel类读取和生成excel文件
  3. spring boot 完整集成jsp。(亲测可用)
  4. 801. 二进制中1的个数 【二进制的基本模板】
  5. oracle data guard方案,Oracle Data Guard 概念篇
  6. 蓝桥杯大赛青少年创意编程 推荐考生阅读 相关书籍的相关视频(部分)
  7. OSGB 倾斜摄影数据生产完成后裁剪模型问题
  8. C++11: vector 初始化赋值
  9. 硬盘功率测试软件,CPU功耗检测
  10. python设置excel套打_你不一定知道这个用 Python 快速设置 Excel 表格边框的技巧
  11. 《Redis开发与运维》第一章 初识Redis 读书笔记
  12. 记录一次Tx_LCN连接失败的问题( There is no normal TM )
  13. 【IEEE】IEEE论文接收后proof(校样)全流程实例讲解
  14. Manim文档及源码笔记-CE文档-主题化指南3渲染文本和公式
  15. 如何看中兴70后程序员从公司跳楼
  16. 360助手上app下载地址
  17. Windows 下使用anaconda虚拟环境pip install 安装pytorch出现报错There was a problem confirming the ssl certificate
  18. MIDle生命周期详解,以及工作原理
  19. PHP实现简单计算器
  20. 在没SQL Server数据库情况下怎么打开.MDF文件?

热门文章

  1. java课外兴趣小组管理系统_课外兴趣小组计划
  2. java之冒泡排序8个数
  3. 【Quectel移远展锐平台5G模组RX500U/RG200U使用指南(三)-PCIE】
  4. 高级 JavaScript(一)
  5. 程序员必备神器:一款开源的不良坐姿监测应用 「PoseMon 让爷康康」
  6. esp8266的TCP通信基础教程(结合手机APP)
  7. 解决ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
  8. HKUST-Aerial-Robotics /grad_traj_optimizationPublic
  9. 弥散张量成像(diffusion tensor imaging,DTI)常用指标
  10. 计算机硬件工程师需要学哪些,嵌入式硬件工程师要求是什么?需要掌握哪些内容...