# 十七、修改群公告
# 1. 修改群公告接口说明
接口文档查看:二十六、修改群公告(成功后通过webSocket通知群聊用户)
# 2. 修改群公告功能实现
- 修复上一节课的bug,进入单聊页面标题出错
在页面/pages/chat/chat.nvue
onShow() {
if(this.arg && this.arg.chatType == 'group'){
this.arg.name = this.groupname || this.pagetitle;
// #ifdef H5
document.title = this.groupname || this.pagetitle;
// #endif
}
},
- 在页面
/pages/setpageInfo/setpageInfo.vue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 内容 -->
<view>
<!-- 聊天相关 -->
<view v-if="setdata.action == 'chatset'">
...
</view>
<!-- 聊天页设置 -->
<view v-if="setdata.action == 'chatpageset'">
<view v-if="chatpageset.id && chatpageset.chatType">
<!-- 头像部分 -->
...
<!-- 群相关设置 -->
<view v-if="chatpageset.chatType == 'group'">
<!-- 群名称 -->
<u-cell-group>
<u-cell>
<view slot="title">
<view class="mb-2">
<text class="font-weight-bold">群名称</text>
</view>
<u-input ...
customStyle="padding:20rpx;"></u-input>
</view>
</u-cell>
</u-cell-group>
...
<!-- 群公告 -->
<u-cell-group>
<u-cell>
<view slot="title">
<view class="mb-2">
<text class="font-weight-bold">群公告</text>
</view>
<u-textarea v-model="chatpageset.remark"
border="none" :maxlength="500"
...
@confirm="groupremark"></u-textarea>
</view>
</u-cell>
</u-cell-group>
...
</view>
<!-- 查找聊天内容 -->
...
<!-- 消息设置 -->
...
</view>
</view>
</view>
</view>
</template>
<script>
...
export default {
...,
methods: {
// 群公告
groupremark(){
const arg = {
apiurl: '/api/chat/groupremark',
params:{
id: this.chatpageset.id,
remark: this.chatpageset.remark,
},
}
this.groupUpdate(arg).then(res =>{
uni.showToast({title:'修改群公告成功', icon:'none'});
});
},
// 更新群名称
groupUpdateName(){
const arg = {
apiurl: '/api/chat/groupUpdateName',
params:{
id: this.chatpageset.id,
name: this.chatpageset.name,
},
}
this.groupUpdate(arg).then(res =>{
uni.showToast({title:'群名称修改成功', icon:'none'});
// 使用vuex兼容H5端nvue页面标题
this.$store.dispatch('groupUpdateName',{
name: this.chatpageset.name
});
});
},
// 更新群相关信息
groupUpdate(arg){
return new Promise((resolve,reject) => {
uni.$u.http.post(requestUrl.http + `${arg.apiurl}`, arg.params, {
header: {
token: this.me.token,
},
}).then(res => {
console.log('服务器返回群名称更新结果', res);
if(res.data.data == 'ok'){
resolve();
}
}).catch(err =>{
uni.showModal({
content:err.data.data,
showCancel:false,
confirmText:'我知道了'
});
});
});
},
...
}
}
</script>
# 十八、修改我在群里面的昵称
# 1. 修改我在群里面的昵称接口说明
接口文档查看:二十七、修改我在群里面的昵称
# 2. 修改我在群里面的昵称功能实现
在页面 /pages/setpageInfo/setpageInfo.vue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 内容 -->
<view>
<!-- 聊天相关 -->
<view v-if="setdata.action == 'chatset'">
...
</view>
<!-- 聊天页设置 -->
<view v-if="setdata.action == 'chatpageset'">
<view v-if="chatpageset.id && chatpageset.chatType">
<!-- 头像部分 -->
...
<!-- 群相关设置 -->
<view v-if="chatpageset.chatType == 'group'">
<!-- 我在群里的昵称 -->
<u-cell-group>
<u-cell>
<view slot="title">
<view class="mb-2">
<text class="font-weight-bold">我在群里的昵称</text>
</view>
<u-input v-model="chatpageset.nickname"
border="none" :maxlength="20"
:adjustPosition="false" clearable
placeholder="群昵称最多20个字"
@confirm="groupnickname"
customStyle="padding:20rpx;"></u-input>
</view>
</u-cell>
</u-cell-group>
<u-gap height="10" bgColor="#EDEDED"></u-gap>
<!-- 群名称 -->
...
<!-- 群公告 -->
...
</view>
<!-- 查找聊天内容 -->
...
<!-- 消息设置 -->
...
</view>
</view>
</view>
</view>
</template>
<script>
...
export default {
...,
onLoad(e) {
...
// 动态生成数据
if(e.action){
this.setdata.action = e.action;
if(this.setdata.action == 'chatset'){
...
}else if(this.setdata.action == 'chatpageset'){
...
// 群聊设置
if(this.chatpageset.chatType == 'group'){
this.getgroupinfo();
}
}
}
},
...,
methods: {
// 获取群资料消息
getgroupinfo(){
uni.$u.http.get(requestUrl.http + `/api/chat/groupinfo/${this.chatpageset.id}`, {
header: {
token: this.me.token,
},
}).then(res => {
console.log('服务器返回群资料', res);
let info = res.data.data;
this.chatpageset.user_id = info.user_id;
this.chatpageset.remark = info.remark;
this.chatpageset.invite_confirm = info.invite_confirm;
this.chatpageset.users = info.group_users;
console.log('显示到页面的群资料',this.chatpageset);
this.chatpageset.user_id = this.chatpageset.user_id == this.me.id ? true : false;
// 我在群里的昵称
let me_index = this.chatpageset.users.findIndex(v=> v.user_id == this.me.id);
if(me_index != -1){
this.chatpageset.nickname = this.chatpageset.users[me_index].nickname;
}
});
},
// 更新我在群里的昵称
groupnickname(){
const arg = {
apiurl: '/api/chat/groupnickname',
data: {
id: this.chatpageset.id,
nickname: this.chatpageset.nickname,
},
};
this.groupUpdate(arg).then(res => {
uni.showToast({title:'群昵称设置成功', icon:'none'});
this.getgroupinfo();
});
},
// 更新群公告
...,
// 更新群名称
...,
// 更新群信息
...,
...
}
}
</script>
# 十九、删除群(解散群)或退出群聊
说明:(登录用户和游客都有这个功能,删除群(解散群)(群主可操作)或退出群(群成员可操作))
# 1. 修改我在群里面的昵称接口说明
接口文档查看:二十八、删除群(解散群)(群主可操作)或退出群(群成员可操作)
# 2. 删除群(解散群)或退出群聊功能实现
在页面 /pages/setpageInfo/setpageInfo.vue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 内容 -->
<view>
<!-- 聊天相关 -->
<view v-if="setdata.action == 'chatset'">
...
</view>
<!-- 聊天页设置 -->
<view v-if="setdata.action == 'chatpageset'">
<view v-if="chatpageset.id && chatpageset.chatType">
<!-- 头像部分 -->
...
<!-- 群相关设置 -->
...
<!-- 查找聊天内容 -->
...
<!-- 消息设置 -->
...
<!-- 解散群或者退群 -->
<view class="p-3">
<u-button type="primary" plain :text="deleteOrQuitGroup"
@click="deleteOrQuitGroupfn"></u-button>
</view>
<u-gap height="10" bgColor="#EDEDED"></u-gap>
</view>
</view>
</view>
</view>
</template>
<script>
...
export default {
...,
onLoad(e) {
...
// 动态生成数据
if(e.action){
...
if(this.setdata.action == 'chatset'){
...
}else if(this.setdata.action == 'chatpageset'){
...
// 设置相关
this.chatpageset = {
// 单聊
...this.chatpageset,
istop: getChatPageSet && getChatPageSet.istop ? true : false ,
shownickname: getChatPageSet && getChatPageSet.shownickname ? true : false,
nowarn: getChatPageSet && getChatPageSet.nowarn ? true : false,
stongwarn: getChatPageSet && getChatPageSet.stongwarn ? true : false,
// 群聊还有以下字段
...
}
...
}
}
},
...
computed:{
...,
// 解散该群或者退出该群
deleteOrQuitGroup(){
if(this.chatpageset.chatType == 'group'){
return this.chatpageset.user_id ? '解散该群' : '退出该群';
}
return ``;
},
},
methods: {
// 解散群或者退出群
deleteOrQuitGroupfn(){
const arg = {
apiurl: '/api/chat/groupDeleteOrQuit',
data: {
id: this.chatpageset.id,
},
};
this.groupUpdate(arg).then(res => {
uni.showToast({title:'操作成功', icon:'none'});
if(this.chatpageset.user_id){
return this.navigateBack();
}else{
uni.switchTab({
url:'/pages/xiaoxi/xiaoxi'
});
}
});
},
// 获取群资料消息
getgroupinfo(){
uni.$u.http.get(requestUrl.http + `/api/chat/groupinfo/${this.chatpageset.id}`, {
header: {
token: this.me.token,
},
}).then(res => {
...
}).catch(err=>{
this.navigateBack();
});
},
...
}
}
</script>
# 二十、删除消息页消息记录
在页面 /pages/xiaoxi/xiaoxi.nvue
// 删除某个聊天
deleteChat(){
// this.chatList.splice(this.chatListIndex,1);
let chatItem = this.chatList[this.chatListIndex];
console.log('删除某个聊天',chatItem);
this.chatClass.deleteChatInfo(chatItem.id, chatItem.chatType).then(()=>{
this.getDataList();
});
},
# 二十一、设置页(如:显示群成员昵称,置顶等处理)
# 1. 设置页进行设置
在页面 /pages/setpageInfo/setpageInfo.vue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 内容 -->
<view>
<!-- 聊天相关 -->
<view v-if="setdata.action == 'chatset'">
...
</view>
<!-- 聊天页设置 -->
<view v-if="setdata.action == 'chatpageset'">
<view v-if="chatpageset.id && chatpageset.chatType">
<!-- 头像部分 -->
...
<!-- 群相关设置 -->
...
<!-- 查找聊天内容 -->
...
<!-- 消息设置 -->
<u-cell-group>
<u-cell v-if="chatpageset.chatType == 'group'"
title="是否显示群成员昵称"
:border="false" clickable
:customStyle="customStyles"
:iconStyle="iconStyles"
:titleStyle="titleStyles">
<view slot="value">
<u-switch v-model="chatpageset.shownickname"
@change="changeSwitch('shownickname')"></u-switch>
</view>
</u-cell>
<u-cell title="消息免打扰"
:border="false" clickable
:customStyle="customStyles"
:iconStyle="iconStyles"
:titleStyle="titleStyles">
<view slot="value">
<u-switch v-model="chatpageset.nowarn" @change="changeSwitch('nowarn')"></u-switch>
</view>
</u-cell>
...
...
</u-cell-group>
...
<!-- 解散群或退群 -->
<view v-if="chatpageset.chatType == 'group'">
<view class="p-3">
<u-button type="primary" plain :text="deleteOrQuitGroup"
@click="deleteOrQuitGroupfn"></u-button>
</view>
<u-gap height="10" bgColor="#EDEDED"></u-gap>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
...
export default {
...,
methods: {
...,
// 点击开关
changeSwitch(key){
console.log(`点击开关${key}`,this.chatpageset[key]);
console.log('通过开关设置单聊或者群聊',this.chatpageset);
this.chatClass.updateSomeOneChatItem({
id: this.chatpageset.id,
chatType: this.chatpageset.chatType,
}, this.chatpageset).then((res)=>{
console.log('设置之后的数据', res);
// 方式一: 通知聊天页
// 方式二: 聊天页重新获取聊天信息
});
},
...
}
}
</script>
# 2. 聊天页重新获取聊天信息(对应消息列表信息,设置信息在这个里面)
在页面 /pages/chat/chat.nvue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 聊天内容区域 -->
<scroll-view ...>
<!-- 对话部分 -->
<view ...>
<chat-item ...
:setdata="setdata"></chat-item>
</view>
</scroll-view>
<!-- 针对我们的app端点击聊天区域授权加号扩展菜单 -->
...
<!-- 底部聊天输入区域 --><!-- 修改:添加ref获取textarea实例 -->
...
<!-- 弹出菜单 --><!-- 主要修改区域 -->
...
<!-- 提示用户正在录音的界面 -->
...
</view>
</template>
<script>
...
export default {
...,
computed:{
...mapState({
...,
xiaoxiList :state=>state.Chatuser.xiaoxiList,
}),
//是否显示群昵称(传递设置信息)
setdata(){
// 拿到设置的信息
if(!this.arg) return {};
if(this.xiaoxiList.length){
let index = this.xiaoxiList.findIndex(v=> v.id == this.arg.id &&
v.chatType == this.arg.chatType);
if(index != -1){
console.log('找到了当前单聊或者群聊的设置信息', this.xiaoxiList[index]);
return this.xiaoxiList[index];
}
}
return {};
},
...,
},
...,
}
</script>
# 3. 组件处理
在组件 /components/chat-item/chat-item.vue
<template>
<view class="px-3">
...
<!-- 聊天内容 -->
<view ...>
<!-- 好友 -->
...
<!-- 聊天内容主体 -->
<view class="flex flex-column">
<!-- 昵称的显示 -->
<view v-if="setdata.shownickname"
...>
...
</view>
<!-- 内容 -->
...
</view>
<!-- 我 -->
...
</view>
<!-- 给服务器发消息状态 -->
...
<!-- 弹出菜单 -->
...
</view>
</template>
<script>
...
export default{
...,
props:{
...,
// 是否显示群成员昵称(设置信息)
setdata: {
type: Object,
default: {},
},
},
...
}
</script>
# 二十二、生成群二维码
说明:
由于生成的二维码,uni-app在H5端不支持扫一扫(扫码)功能【查看官网:扫码功能https://uniapp.dcloud.net.cn/api/system/barcode.html (opens new window)】,所以H5端生成的二维码应该是一个完整的网址链接,通过微信或者手机浏览器扫码后,直接打开对应的H5端网页;
# 1. 生成群二维码接口说明
接口文档查看:二十九、生成获取群二维码
# 2. 生成群二维码功能实现
在页面 /pages/setpageInfo/setpageInfo.vue
<template>
<view>
<!-- 导航栏 -->
...
<!-- 内容 -->
<view>
<!-- 聊天相关 -->
<view v-if="setdata.action == 'chatset'">
...
</view>
<!-- 聊天页设置 -->
<view v-if="setdata.action == 'chatpageset'">
<view v-if="chatpageset.id && chatpageset.chatType">
<!-- 头像部分 -->
...
<!-- 群相关设置 -->
<view v-if="chatpageset.chatType == 'group'">
<!-- 群二维码 -->
<u-cell-group>
<u-cell title="群二维码"
:border="false" clickable isLink
:customStyle="customStyles"
:iconStyle="iconStyles"
:titleStyle="titleStyles"
@click="clickCell('群二维码', 'groupQrcode')"></u-cell>
</u-cell-group>
<u-gap height="10" bgColor="#EDEDED"></u-gap>
<!-- 我在群里面的昵称 -->
...
<!-- 群名称 -->
...
<!-- 群公告 -->
...
</view>
<!-- 查找聊天内容 -->
...
<!-- 消息设置 -->
...
<!-- 解散群或退群 -->
<view v-if="chatpageset.chatType == 'group'">
...
</view>
</view>
</view>
<!-- 群二维码 -->
<view v-if="setdata.action == 'groupQrcode'">
<view class="m-3 bg-light p-3">
<!-- 群名称 -->
<view class="mb-3 flex align-center justify-center p-1">
<text class="text-muted">群名称:{{chatpageset.name}}</text>
</view>
<!-- 群二维码 -->
<view class="mb-3 flex align-center justify-center">
<view class="p-1 border bg-white flex align-center justify-center">
<image :src="chatpageset.src"
style="width: 600rpx;height: 600rpx;"></image>
</view>
</view>
<!-- 提示 -->
<view class="mb-3 flex align-center justify-center">
<text class="text-muted">{{chatpageset.sysinfo}}</text>
</view>
</view>
</view>
<!-- 自动申请加群 -->
<view v-if="setdata.action == 'autoAddGroup'">
<!-- 群头像及简介 -->
<view class="m-3 bg-light p-3 flex flex-row align-center">
<!-- 群头像 -->
<view v-if="avatar && avatar.length"
style="width: 150rpx;"
class="flex align-center justify-center position-relative">
<!-- 一张 -->
<view v-if="avatar.length == 1">
<u--image :src="avatar[0]" mode="widthFix"
width="90rpx" height="90rpx" radius="8rpx"></u--image>
</view>
<!-- 多张 -->
<view v-else style="width: 90rpx;background-color: #eeeeee;"
class="rounded">
<!-- 2张 3张 4张 -->
<view v-if="avatar.length == 2 || avatar.length == 3 || avatar.length == 4"
class="flex flex-row flex-wrap align-center justify-center"
style="height: 90rpx;align-content: center;">
<u-avatar v-for="(v,k) in avatar" :key="k"
:src="v" shape="square" size="45rpx"></u-avatar>
</view>
<!-- 5张到9张 -->
<view v-if="avatar.length >= 5"
class="flex flex-row flex-wrap align-center justify-center"
style="height: 90rpx;align-content: center;">
<u-avatar v-for="(v,k) in avatar" :key="k"
:src="v" shape="square" size="30rpx"></u-avatar>
</view>
</view>
</view>
<!-- 群名称及介绍 -->
<view class="flex flex-column justify-center ml-2">
<text class="mb-1 u-line-1">{{chatpageset.name}}</text>
<text class="text-muted mb-1 font-sm">{{chatpageset.users.length}}人加入</text>
</view>
</view>
<!-- 进入群 -->
<view class="p-3">
<u-button text="加入群聊" type="success" @click="addGroupfn"></u-button>
</view>
<!-- 群公告 -->
<view v-if="chatpageset.remark"
class="p-3 flex flex-column"
style="text-align: justify;">
<text class="font mb-2">群介绍</text>
<view class="bg-light p-3">
<text class="font-sm">{{chatpageset.remark}}</text>
</view>
</view>
<!-- H5端页面在微信打开没有导航栏给个底部导航栏 -->
<view v-if="h5weixin">
<u-tabbar
:value="0"
:fixed="true"
:placeholder="true"
:safeAreaInsetBottom="true"
>
<u-tabbar-item text="首页" icon="home"
@click="clickCell('首页', 'switchTab','/')"></u-tabbar-item>
<u-tabbar-item text="消息" icon="chat" :badge="1"
@click="clickCell('消息', 'switchTab','/pages/xiaoxi/xiaoxi')"></u-tabbar-item>
<u-tabbar-item text="我的" icon="account"
@click="clickCell('我的', 'navigateTo','/pages/wode/wode')"></u-tabbar-item>
</u-tabbar>
</view>
</view>
</view>
</view>
</template>
<script>
...
export default {
...,
data() {
return {
...,
chatpageset:{
users:[],
avatar:'',
},
}
},
onLoad(e) {
console.log(e);
// if(!e.action || !this.me || this.me.role == 'visitor') return this.navigateBack();
if(e.title){
...
}
// 动态生成数据
if(e.action){
this.setdata.action = e.action;
if(this.setdata.action == 'chatset'){
...
}else if(this.setdata.action == 'chatpageset'){
...
}else if(this.setdata.action == 'groupQrcode'){
this.chatpageset.id = e.id;
this.chatpageset.chatType = e.chatType;
this.chatpageset.avatar = decodeURIComponent(e.avatar);
this.chatpageset.name = decodeURIComponent(e.name);
console.log('二维码页面信息',this.chatpageset);
// 获取群二维码
// #ifdef H5
// 二维码返回的地址举例:
// http://192.168.2.6:8081/#/pages/setpageInfo/setpageInfo?
// action=autoAddGroup&title=%E7%BE%A4%E4%BB%8B%E7%BB%8D
// &id=33&chatType=group
// 获取完整的URL
const fullURL = window.location.href;
// 截取#之前的部分
const http = fullURL.split('#')[0];
//console.log(http);
// 生成二维码
this.chatpageset.src = requestUrl.http +
`/api/chat/groupQrcode/${this.chatpageset.id}?
token=${this.me.token}&type=H5&
http=${encodeURIComponent(http)}&
chatType=${this.chatpageset.chatType}`;
// #endif
// #ifdef APP || MP
this.chatpageset.src = requestUrl.http +
`/api/chat/groupQrcode/${this.chatpageset.id}?token=${this.me.token}`;
// #endif
//二维码说明
let sysinfo = uni.getSystemInfoSync().appName;
// #ifdef H5
this.chatpageset.sysinfo = `使用微信或者手机浏览器扫码加群`;
// #endif
// #ifdef MP
this.chatpageset.sysinfo = `使用${sysinfo}小程序扫码加群`;
// #endif
// #ifdef APP
this.chatpageset.sysinfo = `使用${sysinfo}APP扫码加群`;
// #endif
}else if(this.setdata.action == 'autoAddGroup'){
this.chatpageset.id = e.id;
this.chatpageset.chatType = e.chatType;
// 群聊信息
if(this.chatpageset.chatType == 'group'){
this.getgroupinfo();
}
}
}
},
...,
computed:{
...,
// 解散群或退群
...,
// 群头像
avatar(){
if(this.chatpageset && this.chatpageset.avatar){
let arr = this.chatpageset.avatar.split(',');
arr = arr.map(v => {
if(v.startsWith('http')){
return v;
}else{
return requestUrl.http + v;
}
});
// console.log('头像',arr);
return arr;
}
return [];
},
// h5端微信打开页面有底部导航栏
h5weixin(){
return this.isWeixinBrowser();
},
},
methods: {
// 加入群聊
addGroupfn(){
console.log('加入群聊,看管理员的设置入群');
},
...,
// 获取群资料
getgroupinfo(){
uni.$u.http.get(requestUrl.http + `/api/chat/groupinfo/${this.chatpageset.id}`, {
header: {
token: this.me.token,
},
}).then(res => {
...
// 我在群里面的昵称
let me_index = this.chatpageset.users.findIndex(v => v.user_id == this.me.id);
if(me_index != -1){
this.chatpageset.nickname = this.chatpageset.users[me_index].nickname;
}
// 头像
this.chatpageset.avatar = info.avatar;
// 群名称
this.chatpageset.name = info.name;
console.log('显示到页面的群资料',this.chatpageset);
}).catch(err =>{
...
});
},
...,
clickCell(title, type ,url = ''){
console.log(title, type);
if(type == 'addUserToGroup'){
// 单独建群
...
}else if(type == 'groupQrcode'){
console.log('打开群二维码');
let op = {
action: 'groupQrcode',
title: encodeURIComponent(title),
id: this.chatpageset.id,
name: encodeURIComponent(this.chatpageset.name),
avatar: encodeURIComponent(this.chatpageset.avatar),
chatType: this.chatpageset.chatType,
};
uni.redirectTo({
url: `/pages/setpageInfo/setpageInfo?
action=${op.action}&title=${op.title}&id=${op.id}
&name=${op.name}&avatar=${op.avatar}&chatType=${op.chatType}`,
});
}else if(type == 'switchTab' || type == 'navigateTo'){
uni[type]({
url:url,
});
}
},
...
}
}
</script>
# 二十三、解决游客扫群二维码打开页面跳转到首页的问题
主要原因是游客的token错误,当token错误时候,重新生成token, 并连接websocket
# 1. 改写游客注册登录逻辑
将 /pages/loginCenter/visitor.js 文件改写,便于在类文件使用
import { getDeviceId } from '@/common/js/deviceId.js';
import { requestUrl, visitorSalt } from '@/common/mixins/configData.js';
import sha256 from '@/common/js/sha256.min.js';
// 导出独立的方法,而不是Vue组件
// 给游客一个身份
export const registerGuest = async function(store) {
const deviceId = getDeviceId();
console.log('设备id', deviceId);
// 给游客注册一个身份
const timestamp = Date.now();
// 生成安全签名(防篡改)
// SHA256签名
const generateSign = async (params) => {
const sortedStr = Object.keys(params).sort().map(k => `${k}=${params[k]}`).join('&');
// 使用sha256加密
return sha256(sortedStr + 'APP_SECRET'); // 真实项目中替换为动态密钥
};
const sign = await generateSign({
deviceId,
timestamp,
salt: visitorSalt, // 固定盐值(混淆用)
});
/*
const sign = sha256(
`deviceId=${deviceId}&salt=${this.visitorSalt}×tamp=${timestamp}APP_SECRET`
);
*/
const systemInfo = uni.getSystemInfoSync();
try {
const res = await uni.request({
url: requestUrl.http + '/api/visitorRegister',
method: 'POST',
header: {
'X-Security-Sign': sign,
},
data: {
deviceId,
timestamp,
//以下参数选填
uniplatform: systemInfo.uniPlatform || 'unknown',
devicemodel: systemInfo.model || systemInfo.deviceModel || 'unknown',
deviceos: systemInfo.osName || systemInfo.platform || 'unknown',
devicebrand: systemInfo.brand || systemInfo.deviceBrand || 'unknown',
}
});
console.log('服务器响应:', res);
if (res.data.msg == 'ok') {
console.log('成功', res.data);
// 调用vuex里面的actions中的方法,执行后续操作,连缀用.then
//this.$store.dispatch('regloginAction',res.data.data);
// return true;
store.dispatch('regloginAction', res.data.data);
return res.data.data;
} else {
console.warn('失败', res.data);
return null;
}
} catch (e) {
console.error('请求失败:', e);
return null;
}
};
// 默认导出(保持原有结构)
export default {
methods: {
registerGuest: function() {
return registerGuest(this.$store);
},
// 其他方法...
}
}
# 2. 游客如果token令牌错误,重新获取token并连接websocket
在类文件 /common/js/chatClass.js
import {requestUrl} from '@/common/mixins/configData.js';
import {registerGuest} from '@/pages/loginCenter/visitor.js'; //导入具体的方法
import store from '@/store'; // 引入vuex store
class chatClass {
// 构造函数
constructor() {
...
// 连接websocket
...
/*
// 连接websocket - 修改为支持游客模式
if (this.user && this.user.token) {
this.connectSocket();
} else {
// 如果没有用户信息,尝试注册游客
this.registerGuestAndConnect();
}
*/
// 心跳
...
}
// 连接websocket
...
// 连接成功
...
// 断开连接
...
// 接收信息
...
// 关闭链接
...
// 创建聊天对象信息
...
// 销毁聊天对象信息
...
// 页面发消息的格式和服务器要一致
...
// 发送消息(单聊)
...
// 把聊天信息存在本地
...
// 获取历史记录, 传key值则找指定聊天记录
...
// 更新指定的历史记录信息(不急着更新可以异步)
...
// 删除指定的历史记录信息
...
// 修改某个对话信息(单聊和群聊, 处理设置功能)
// [如:置顶、免打扰、是否展示昵称、是否提醒、是否确认进群等]
...
// 消息页的聊天列表更新一下
...
// 更新(获取)消息页,整个消息列表的未读数(不急可以异步执行)
...
// 数组元素置顶
...
// 获取消息页列表本地历史信息
...
// 存储消息页列表本地历史信息
...
// 查看我是否在线websocket是否正常连接
...
// 提示我确认重新连接websocket
async connectWebsocketcomfirm(msdata = null, confirmCallback = false, cancelCallback = false) {
uni.showModal({
title: '系统提示',
content: msdata && msdata.content ?
msdata.content : '由于服务器或者网络原因,您已经掉线了,是否重新连接',
showCancel: true,
cancelText: msdata && msdata.cancelText ? msdata.cancelText : '取消',
confirmText: msdata && msdata.confirmText ? msdata.confirmText : '重新连接',
success: res => {
if (res.confirm) {
if(confirmCallback && typeof confirmCallback == 'function'){
confirmCallback();
}else{
this.connectSocket();
}
}else{
console.log('点击了取消');
if(cancelCallback && typeof cancelCallback == 'function'){
cancelCallback();
}
}
},
});
}
// 处理接收到的消息
...
// 进入聊天页,将消息页当前聊天用户的未读数清零
...
// 聊天页设置相关信息获取
...
// 获取离线消息(不在线的时候别人或者群发的消息)
chatGetmessageOffLine(){
uni.$u.http.post(requestUrl.http + `/api/chat/chatGetmessageOffLine`, {}, {
header: {
token: this.user.token,
},
}).then(res => {
console.log('服务器返回离线消息', res);
}).catch(err => {
console.log('服务器返回离线消息失败', err);
if(err.data && err.data.data == 'Token 令牌不合法!'){
if(this.user.role == 'visitor'){
console.log(`游客如果token令牌错误,
重新获取token并连接websocket`);
this.registerGuestAndConnect();
}else if(this.user.role == 'user'){
console.log(`登录用户的token不正确,说明是在别的设备登录了,
则清空本地登录信息,换成游客模式`);
store.dispatch('logoutAction', ()=>{
this.doRegisterGuest();
});
}
}
});
}
// 游客重新获取token给连接提示
async registerGuestAndConnect(){
try{
this.connectWebsocketcomfirm({
content: '您之前在其它设备打开过现已掉线,是否在本设备重新连接',
}, ()=>{
this.doRegisterGuest();
});
}catch(error){
console.error('获取token失败',error);
}
}
// 游客如果token令牌错误,重新获取token并连接websocket
async doRegisterGuest(){
const userData = await registerGuest(store);
console.log('游客重新获取token等信息', userData);
if(userData && userData.token){
// 更新用户信息
this.user = userData;
// 连接websocket
this.connectSocket();
}
}
}
export default chatClass;
# 3. 用户退出登录vuex处理调整
在文件 /store/modules/chatuser.js
...
// 用户退出登录
logoutAction({commit,state}, callback = false) {
// 关闭socket链接
state.chatClass.close();
state.chatClass = null;
// 清空用户信息
state.regloginUser = null;
// 删除本地存储
uni.removeStorageSync('chatuser');
uni.removeStorageSync('chatuser_id');
uni.removeStorageSync('chatuser_token');
// 如果有第二个参数且是函数
if(callback && typeof callback == 'function'){
callback();
}
},
...
# 二十四、清空聊天记录
# 1. 清空聊天记录功能实现
在页面 /pages/setpageInfo/setpageInfo.vue
clickCell(title, type, url = ''){
console.log(title, type);
if(type == 'addUserToGroup'){
...
}else if(type == 'groupQrcode'){
...
}else if(type == 'switchTab' || type == 'navigateTo'){
...
}else if(type == 'deleteChatData'){
uni.showModal({
content:'是否清空聊天记录?',
success: (res) => {
if(res.confirm){
this.chatClass.clearChatInfo(this.chatpageset.id,
this.chatpageset.chatType).then(res=>{
uni.showToast({title:'清空成功',icon:'success'});
//清空完成之后聊天页的数据也应该清空
uni.$emit('clearChatInfo');
});
}
}
});
}
},
# 2. 聊天页清空聊天记录
在页面 /pages/chat/chat.nvue
...
onShow() {
...
// 监听清空聊天记录
uni.$on('clearChatInfo',()=>{
this.chatDataList = [];
});
},
destroyed() {
...
//取消监听清空聊天记录
uni.$off('clearChatInfo', ()=>{});
},
...