# 十七、修改群公告

# 1. 修改群公告接口说明

接口文档查看:二十六、修改群公告(成功后通过webSocket通知群聊用户)

# 2. 修改群公告功能实现

  1. 修复上一节课的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
    }
},
  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">
					<!-- 头像部分 -->
					...
					<!-- 群相关设置 -->
					<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}&timestamp=${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', ()=>{});
},
...
更新时间: 2025年8月24日星期日下午1点15分