router.js
// 生成群二维码
router.get('/group_qrcode/:id',controller.group.qrcode);
extend/content.js
// app/extend/context.js
var qr = require('qr-image');
module.exports = {
// 成功提示
apiSuccess(data = '', msg = 'ok', code = 200) {
this.body = { msg, data };
this.status = code;
},
// 失败提示
apiFail(data = '', msg = 'fail', code = 400) {
this.body = { msg, data };
this.status = code;
},
// 生成token
getToken(value) {
return this.app.jwt.sign(value, this.app.config.jwt.secret);
},
// 验证token
checkToken(token) {
return this.app.jwt.verify(token, this.app.config.jwt.secret);
},
// 发送或者存到消息队列中
sendAndSaveMessage(to_id,message){
const { app,service } = this;
let current_user_id = this.authUser.id;
// 拿到当前的socket
// let socket = app.ws.user[to_id];
// 验证对方是否在线,不在线记录到待接收消息队列中 在线:消息推送 存储到对方的聊天记录中 chatlog_对方用户id_user_当前用户id
if(app.ws.user && app.ws.user[to_id]){
// 消息推送
app.ws.user[to_id].send(JSON.stringify({
msg:'ok',
data:message
}))
// 存到历史记录中
service.cache.setList(`chatlog_${to_id}_${message.chat_type}_${current_user_id}`,message);
}else{
service.cache.setList('getmessage_'+to_id,message);
}
},
// 生成唯一id
qrcode(url){
var img = qr.image(url,{size:10});
this.response.type = 'image/png';
this.body = img;
}
};
middleware/auth.js
module.exports=(option,app)=>{
return async (ctx,next)=>{
//1. 获取 header 头token
// const { token } = ctx.header;
let token = ctx.header.token || ctx.query.token;
// console.log(ctx.header);
if (!token) {
ctx.throw(400, '您没有权限访问该接口!');
}
//2. 根据token解密,换取用户信息
let user = {};
try {
user = ctx.checkToken(token);
} catch (error) {
let fail = error.name === 'TokenExpiredError' ? 'token 已过期! 请重新获取令牌' : 'Token 令牌不合法!';
ctx.throw(400, fail);
}
//3. 判断当前用户是否登录
let t = await ctx.service.cache.get('user_' + user.id);
if (!t || t !== token) {
ctx.throw(400, 'Token 令牌不合法!');
}
//4. 获取当前用户,验证当前用户是否被禁用
user = await app.model.User.findByPk(user.id);
if (!user || user.status == 0) {
ctx.throw(400,'用户不存在或已被禁用');
}
// 5. 把 user 信息挂载到全局ctx上
ctx.authUser = user;
await next();
}
}
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;
// 拿到当前用户id
let 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,后端生成唯一id
from_avatar:ctx.authUser.avatar,// 发送者头像
from_name:ctx.authUser.nickname || ctx.authUser.username,// 发送者昵称
from_id:current_user_id, // 发送者id
to_id:group.id,// 接收人id
to_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,后端生成唯一id
from_avatar:ctx.authUser.avatar,// 发送者头像
from_name,// 发送者昵称
from_id:current_user_id, // 发送者id
to_id:group.id,// 接收人id
to_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,后端生成唯一id
from_avatar:ctx.authUser.avatar,// 发送者头像
from_name,// 发送者昵称
from_id:current_user_id, // 发送者id
to_id:group.id,// 接收人id
to_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');
}
// 修改我在本群中的昵称
async nickname(){
const { ctx, app, service } = this;
let current_user_id = ctx.authUser.id;
// 参数验证
ctx.validate({
id:{
required:true,
type:'int',
desc:'群组id'
},
nickname:{
required:true,
type:'string',
desc:'昵称'
}
});
let { id,nickname } = 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('你不是该群成员');
}
// 修改昵称
let group_user = await app.model.GroupUser.findOne({
where:{
user_id:current_user_id,
group_id:group.id
}
});
if(group_user){
await group_user.update({
nickname
})
}
return ctx.apiSuccess('ok');
}
// 删除并退出群聊
async quit(){
const { ctx, app, service } = this;
let current_user_id = ctx.authUser.id;
// 参数验证
ctx.validate({
id:{
required:true,
type:'int',
desc:'群组id'
}
});
let { id } = ctx.request.body;
// 是否存在
let group = await app.model.Group.findOne({
where:{
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 || ctx.authUser.nickname || ctx.authUser.username;
// 组织消息格式
let message = {
id:(new Date()).getTime(), // 唯一id,后端生成唯一id
from_avatar:ctx.authUser.avatar,// 发送者头像
from_name,// 发送者昵称
from_id:current_user_id, // 发送者id
to_id:group.id,// 接收人id
to_name:group.name,// 接收人/群 名称
to_avatar:group.avatar,// 接收人/群 头像
chat_type:'group', // 接收类型
type:'system', // 消息类型
data:``, // 消息内容
options:{}, // 其他参数
create_time:(new Date()).getTime(),// 创建时间
isremove:0, // 是否撤回
group:group
}
if(group.user_id===current_user_id){
// 解散群
await app.model.Group.destroy({
where:{
id:group.id
}
});
message.data = '该群已被解散';
}else{
// 退出群
await app.model.GroupUser.destroy({
where:{
user_id:current_user_id,
group_id:id
}
});
message.data = `${from_name} 退出该群聊`;
}
// 推送消息
group.group_users.forEach(item=>{
ctx.sendAndSaveMessage(item.user_id,message);
});
return ctx.apiSuccess('ok');
}
// 生成群二维码
async qrcode(){
const {ctx,app} = this;
ctx.qrcode(JSON.stringify({
id:1
}));
}
}
module.exports = GroupController;
接口测试如下图所示
感谢大家观看,我们下次见