# 一、多进程处理前端调整

在项目上线前,为了应对高并发量和高可用性的海量webscoket请求,后端[具体文档查看:eggjs多进程处理]会使用多进程处理,那么对应前端部分基本不用改动什么,只是对有些地方请求websocket的逻辑做一下调整即可。

# 1. 针对登录用户(角色为user的用户)

在类文件 /common/js/chatClass.js

    ...
    // 连接websocket
	connectSocket() {
		this.chatSocket = uni.connectSocket({
			// http://192.168.2.7:7001
			// ws://192.168.2.7:7001/ws
			// https://lesson07.51yrc.com
			// wss://lesson07.51yrc.com/ws
			url: this.url + `/ws?token=${this.user.token}`,
			complete: () => {},
			timeout: 10000, // 10秒超时
		});

		// 连接成功
		this.chatSocket.onOpen(() => {
			console.log('websocket连接成功');
			// 调用方法
			this.onOpen();
			//启动心跳
			this.heartbeatTimer = setInterval(() => {
				if (this.chatSocket && this.chatSocket.readyState === 1) {
					// 确保发送的是字符串格式的JSON
					const heartbeatMsg = JSON.stringify({
						type: 'ping',
						token: this.user.token,
						timestamp: Date.now() // 添加时间戳便于调试
					});
					// console.log('发送心跳消息:', heartbeatMsg);
					// this.chatSocket.send(heartbeatMsg);
				}
			}, 5000); // 每隔5秒发送一次心跳
		});
		// 接收信息
		this.chatSocket.onMessage(res => {
			// 处理一下不同平台消息格式
			try {
				const data = typeof res.data === 'string' ?
					JSON.parse(res.data) : res.data;
				console.log('监听接收消息', data);
				// 处理接收的websocket消息
				this.onMessage(data);
				// 如果服务器返回ping
				if (data.type === 'ping') {
					console.log('响应服务器心跳');
					// 响应心跳 -- 自由发挥
				}
			} catch (e) {
				console.error('接收信息错误', e);
			}
		});
		// 断开连接
		this.chatSocket.onClose(res => {
			console.log('断开连接的原因', res);
			// 清除心跳
			clearInterval(this.heartbeatTimer); 
			this.heartbeatTimer = null;
			//调用方法
			this.onClose();
			
			// 对用户做个提示
			if(this.user.role == 'user'){
				// 如果修改服务器代码可能异常关闭1006,这种情况除外
				if(!(res.code && res.code == 1006)){
					uni.showModal({
						title: '账号异地登录',
						content: '您的账号在异地登录,本设备将会退出',
						showCancel: false,
						confirmText: '我知道了',
						success: res => {},
					});
					console.log('则清空本地登录信息,在换成游客模式');
					let _that = this;
					store.dispatch('logoutAction', ()=>{
						_that.doRegisterGuest();
					});
				}else{
					// 尝试重新连接
					setTimeout(() => {
						console.log('断开连接尝试重新连接websocket');
						//dispatch('initChatuserAction');
						this.connectSocket();
					}, 1000);
				}
			}else{
				// 游客尝试重新连接
				setTimeout(() => {
					console.log('断开连接尝试重新连接websocket');
					//dispatch('initChatuserAction');
					this.connectSocket();
				}, 1000);
			}

		});
		// 错误处理
		this.chatSocket.onError(err => {
			console.error('websocket 错误:', err);
			// 清除心跳
			clearInterval(this.heartbeatTimer); 
			this.heartbeatTimer = null;
			//调用方法
			this.onClose();
			
			// 尝试重新连接
			setTimeout(() => {
				console.log('错误处理尝试重新连接websocket');
				//dispatch('initChatuserAction');
				this.connectSocket();
			}, 1000);
		});
	}

    ...

    // 关闭链接
	close() {
		// 用户退出登录
		// 调用socketTask 对象 close方法
		if (this.chatSocket) {
			this.chatSocket.close();
		}
	}
    ...
    // 获取离线消息(不在线的时候别人或者群发的消息)
	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();
					});
				}
			}
		});
	}
    ...

# 2. 类文件 /common/js/chatClass.js 完整代码

具体查看:类文件 /common/js/chatClass.js 完整代码

# 3. 聊天页

在页面 /pages/chat/chat.nvue

	<!-- 底部聊天输入区域 --><!-- 修改:添加ref获取textarea实例 -->
	<view v-if="arg.action != 'searhChatData' && arg.id"
	...>
	</view>
	...

	computed:{
		...
		//标题
		pagetitle(){
			if(this.arg && this.arg.name){
				// #ifdef H5 || APP
				if(this.arg.name.length > 15){
					return this.arg.name.substring(0,15) + '...';
				}
				return this.arg.name;
				// #endif
				// #ifdef MP
				if(this.arg.name.length > 5){
					return this.arg.name.substring(0,5) + '...';
				}
				return this.arg.name;
				// #endif
			}
			return ``;
		},
		...
	}

# 二、游客扫码加入群聊

# 1. H5端扫码(比如用微信扫一扫、手机浏览器等)

说明:

  1. 注意H5端打开群二维码,(如果你用的是本地服务器)需要用ip地址作为前缀,不要用localhost打开,否则页面无法开发;

# ① 页面处理

在页面 /pages/setpageInfo/setpageInfo.vue

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 内容 -->
		<view>
			<!-- 聊天相关 -->
			...
			<!-- 聊天页设置 -->
			...
			<!-- 群二维码 -->
			...
			<!-- 扫码之后的页面 -->
			<view v-if="setdata.action == 'autoAddGroup'">
				<!-- 群头像及介绍 -->
				...
				<!-- 加群按钮 -->
				<view class="p-3">
					<view v-if="chatpageset.showAddGroupDesc"
					class="mb-2">
						<u-textarea v-model="chatpageset.addGroupDesc"
						border="surround" :maxlength="500"
						:adjustPosition="false" 
						placeholder="说明一下加群理由,方便群主快速通过,选填(可不填)"
						count :autoHeight="false"
						@confirm="ScanQrcodeApplyAddGroup"
						:height = "100"></u-textarea>
					</view>
					<!-- 页面按钮 -->
					<u-button v-if="!chatpageset.showAddGroupDesc"
					:text="chatpageset.buttonText" 
					type="success" @click="addGroupfn"></u-button>
					<!-- 申请加群 -->
					<u-button v-if="chatpageset.showAddGroupDesc"
					text="提 交 加 群 申 请" 
					type="primary" @click="ScanQrcodeApplyAddGroup"></u-button>
				</view>
				<!-- 群公告 -->
				...
				<!-- h5端页面在微信打开没有导航栏给它一个底部导航栏 -->
				...
			</view>
			<!-- 账号信息设置 -->
			...
			<!-- 头像剪裁500rpx * 500rpx -->
			...
		    <!-- 删除群成员 -->
		    ...
		    <!-- 添加好友进群 -->
		    ...
		    <!-- 群主审批进群处理 -->
		    <view ...>
				<!-- 要加入的群 -->
				...
				<!-- 申请信息 -->
				<view v-if="chatpageset.applydesc">
					<!-- 进群方式 -->
					...
					<!-- 邀请人 -->
					...
					<!-- 邀请时间 -->
					...
					<!-- 加群申请说明 -->
					...
				</view>
			    <!-- 申请人 -->
				<view>
					<!-- 申请人头像昵称 -->
					<view ...>
						...
						<view ...>
							<!-- 申请人头像 -->
							...
							<!-- 申请人昵称 -->
							...
							<!-- 申请人角色 -->
							<text class="font text-warning ml-2">{{chatpageset.addGroupUserRole}}</text>
						</view>
					</view>
				</view>
			    <!-- 处理 -->
				...
			</view>
		
		
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		data() {
			return {
				...
				chatpageset:{
					...,
					showAddGroupDesc: false, // 是否显示加群说明输入框
				},
			}
		},
		onLoad(e) {
			...
			// 动态生成数据
			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'){
					...
				}else if(this.setdata.action == 'autoAddGroup'){
					...
				}else if(this.setdata.action == 'userinfoSet'){
					...
				}else if(this.setdata.action == 'avatarCut'){
					...
				}else if(this.setdata.action == 'deleteUserFromGroup'){
					...
				}else if(this.setdata.action == 'addUserFromGroup'){
					...
				}else if(this.setdata.action == 'applyAddGroup'){
					...
					// 点击申请人跳转到用户详情
					...
					// 申请人角色
					this.chatpageset.addGroupUserRole = this.chatpageset.applydesc ?
					this.chatpageset.applydesc.addGroupUserRole : '';
					this.chatpageset.addGroupUserRole = 
					this.chatpageset.addGroupUserRole == 'visitor' ? '游客' : '平台用户';
					
				}
			}
		},
		...
	}
</script>

# ② 功能实现

在文件 /pages/setpageInfo/group.js

...
export default {
	...,
	methods: {
		// 扫二维码申请加群
		ScanQrcodeApplyAddGroup(){
			console.log('扫二维码申请加群提交');
			this.addGroupUser({
				friend_id: this.me.id,
				inviteuser_id: -1, // 邀请者如果小于0,则是自主进群
				addGroupDesc: this.chatpageset.addGroupDesc, // 进群说明
			});
		},
		// 处理进群的申请
		...,
		// 进群设置
		...,
		// 添加好友进群
		...,
		// 搜索好友
		...,
		// 往群里面加人
		...,
		// 点击群成员
		...,
		// 搜索群成员
		...,
		// 清空搜索
		...,
		// 删除群成员
		...,
		// 加入群聊
		addGroupfn(){
			console.log('加入群聊,看管理员怎么设置的');
			console.log('看一下群信息', this.chatpageset);
			// 如果扫码用户就是群成员或者群主,则直接进群聊天
			if(this.chatpageset.isGroupUser){
				// 是群成员则直接进群
				// 进入聊天页 传一下用户的信息过去在页面展示
				const userchat = {
					id: this.chatpageset.id,
					name: this.chatpageset.name,
					avatar: this.chatpageset.avatar,
					chatType: 'group', // 单聊 single 群聊 group
				};
				uni.navigateTo({
					url: `/pages/chat/chat?arg=${encodeURIComponent(JSON.stringify(userchat))}`,
				});
				return;
			}
			// 非群成员
			if(this.chatpageset.invite_confirm == 0){
				// 不需要群主同意可直接提交进群
				this.ScanQrcodeApplyAddGroup();
			}else if(this.chatpageset.invite_confirm == 1){
				// 需要经过群主同意
				this.chatpageset.showAddGroupDesc = true;
			}else if(this.chatpageset.invite_confirm == 2){
				// 游客需要先登录在申请,登录用户需要群主同意
				if(this.me.role == 'visitor'){
					let redirectUrl = ``;
					// #ifdef H5
					redirectUrl = window.location.href.split('#')[1];
					// #endif
					uni.showModal({
						content: '群主设为:先登录或注册账号再进群',
						cancelText: '取消',
						confirmText: '登录或注册',
						success: res => {
							if(res.confirm){
								uni.navigateTo({
									url: `/pages/loginCenter/loginCenter?redirectUrl=${redirectUrl}`,
								});
							}
						},
					});
				}
			}
		},
		// 解散群或者退群或者删除好友
		...,
		// 获取群资料
		getgroupinfo(){
			return new Promise((resolve,reject)=>{
				uni.$u.http.get(...).then(res => {
					...
					// 群名称
					...
					console.log('显示到页面的群资料',this.chatpageset);
					
					// 新增一个判断当前用户是不是群成员
					this.chatpageset.isGroupUser = false;
					this.chatpageset.buttonText = '加入群聊';
					// 获取群成员的id集合
					let groupUsersIds = [];
					if(this.chatpageset.users.length){
						groupUsersIds = this.chatpageset.users.map(v => v.user_id);
					}
					if(groupUsersIds.length){
						if(groupUsersIds.includes(this.me.id)){
							// 是群成员
							this.chatpageset.isGroupUser = true;
							this.chatpageset.buttonText = '进群聊天';
						}
					}
					
					resolve(this.chatpageset);
					
				}).catch(err =>{
					this.navigateBack();
				});
			});
		},
		...
	}
}

# 三、游客界面调整

#消息页页面调整

由于我的页面很多需要登录,作为游客可简化页面只留一个消息页, 在页面 /pages/xiaoxi/xiaoxi.nvue

<template>
	<view>
		...
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	...
	export default {
		mixins:[parseTimeJs,toolJs],
		...
		onLoad() {
           ...
		   // 是否显示底部tab栏
		   this.tabbarShow();
		},
		onShow() {
		   ...
		   // 是否显示底部tab栏
		   this.tabbarShow();
		},
		...
	}
</script>

# ② 混入方法计算属性等到tool.js

在文件 /common/mixins/tool.js

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
export default {
	computed: {
		...mapState({
			me : state => state.Chatuser.regloginUser,
		}),
		// 是否是游客
		isVisitor(){
			if(this.me && this.me.role == 'visitor'){
				return true;
			}
			return false;
		},
	},
	methods: {
		// 是否显示底部tab栏
		tabbarShow(){
			if(this.me.role == 'visitor'){
				uni.hideTabBar();
			}else{
				uni.showTabBar();
			}
		},
		...
	}
}

# ③ 顶部导航栏处理

在组件 /components/chat-navbar/chat-navbar.vue

<template>
	<view>
		<!-- 导航栏 -->
		<view ...>
			<!-- 状态栏 -->
			...
			<!-- 导航 -->
			<!-- #ifdef APP || H5 -->
			<view ...>
				<!-- 左边 -->
				...
				<!-- 右边 -->
				<view class="flex align-center">
					<!-- 游客 -->
					<view v-if="isVisitor">
						<chat-navbar-icon-button @click="openAddGroup">
							<text class="iconfont font-lg">&#xe60b;</text>
						</chat-navbar-icon-button>
					</view>
					<!-- 登录用户 -->
					<view v-else
					class="flex align-center">
						<chat-navbar-icon-button @click="openUser" v-if="showUser">
							<text class="iconfont font-lg">&#xe650;</text>
						</chat-navbar-icon-button>
						<chat-navbar-icon-button @click="openPlus" v-if="showPlus">
							<text class="iconfont font-md">&#xe655;</text>
						</chat-navbar-icon-button>
						<slot name="right"></slot>
					</view>
				</view>
			</view>
			<!-- #endif -->
			<!-- #ifdef MP -->
			<view ...>
			    <!-- 左边 -->
				<view class="flex align-center flex-1">
					<!-- 返回箭头 -->
					<chat-navbar-icon-button  v-if="showBack" @click="navigateBack">
						<text class="iconfont font-md">&#xe68e;</text>
					</chat-navbar-icon-button>
					<!-- 游客 -->
					<view v-if="isVisitor">
						<chat-navbar-icon-button @click="openAddGroup">
							<text class="iconfont font-lg">&#xe60b;</text>
						</chat-navbar-icon-button>
					</view>
					<!-- 登录用户 -->
					<view v-else
					class="flex align-center flex-1">
						<chat-navbar-icon-button @click="openPlus" v-if="showPlus">
							<text class="iconfont font-md">&#xe655;</text>
						</chat-navbar-icon-button>
						<chat-navbar-icon-button @click="openUser" v-if="showUser">
							<text class="iconfont font-lg">&#xe650;</text>
						</chat-navbar-icon-button>
					</view>
				</view>
				<!-- 中间 -->
				...
				<!-- 右边 -->
				...
			</view>
			<!-- #endif -->
			
		</view>
		<!-- 占位符:占用 状态栏 + 导航栏的高度 -->
		...
		
		<!-- 导航栏点击加号的弹出菜单 -->
		...
		
		
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	export default {
		...
		mixins:[toolJs],
		...,
		methods: {
			...,
			openAddGroup(){
				uni.redirectTo({
					url:`/pages/applyMyfriend/applyMyfriend?action=grouplist&title=${encodeURIComponent('我的群聊列表')}`,
				});
			},
			
		},
		...
	}
</script>

#我的页面调整

在页面 /pages/wode/wode.nvue

<template>
	<view>
		...
		<!-- 我的二维码 -->
		<view v-if="!isVisitor">
		    <!-- 间隔槽 -->
			<u-gap height="10" bgColor="#EDEDED"></u-gap>
			<u-cell-group>
				<u-cell icon="grid" title="我的二维码"
				:border="false" clickable isLink
				:customStyle="customStyles"
				:iconStyle="iconStyles"
				:titleStyle="titleStyles"
				@click="openMyQrcode"></u-cell>
			</u-cell-group>
		</view>
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	import {requestUrl} from '@/common/mixins/configData.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	export default {
		mixins:[toolJs],
		data() {
			return {
				...
				uCellMenus:[
					{icon:'plus-people-fill',title:'添加朋友',url:'/pages/search/search'},
					{icon:'man-add-fill',title:'我的群聊',url:`/pages/applyMyfriend/applyMyfriend?action=grouplist&title=${encodeURIComponent('我的群聊列表')}`},
					// #ifndef H5
					{icon:'scan',title:'扫一扫',url:''},
					// #endif
					
				],
			}
		},
		onLoad() {
			...
			
			console.log('用户或者游客的信息', this.me);
		},
		computed:{
			// ...mapState({
			// 	user : state => state.Chatuser.regloginUser,
			// }),
			...,
			//头像
			avatarShow(){
				let avatar = ``;
				if(this.me){
					avatar = this.me.avatar;
					if(avatar && avatar.startsWith('/')){
						avatar = requestUrl.http + avatar;
					}
				}
				return avatar;
			},
			// 账号
			nicknameShow(){
				let str = ``;
				if(this.me){
					if(this.me.role == 'user'){
						str = this.me.nickname || this.me.username;
					}else if(this.me.role == 'visitor'){
						str = `登 录`;
					}
				}
				return str;
			},
			// 账号下面的小字
			nicknameNextShow(){
				let str = ``;
				if(this.me){
					if(this.me.role == 'user'){
						str = `账号:${this.me.username}`;
					}else if(this.me.role == 'visitor'){
						str = `登录获取更多服务`;
					}
				}
				return str;
			},
		},
		methods: {
			//点击Cell菜单
			openCell(item,index){
				console.log('点击Cell菜单',item);
				if(!item.url) return;
				if(!this.me || this.me.role == 'visitor'){
					return uni.navigateTo({
						url:'/pages/loginCenter/loginCenter'
					});
				}
				uni.navigateTo({
					url:item.url,
				});
			},
			//点击头像昵称
			clickAvatarNickname(){
				if(!this.me || this.me.role == 'visitor'){
					return uni.navigateTo({
						url: '/pages/loginCenter/loginCenter',
					});
				}
				// 打开设置页
				uni.navigateTo({
					url: '/pages/setpage/setpage',
				});
			},
			// 我的二维码
			openMyQrcode(){
				console.log('打开我的二维码');
				let name = this.me.nickname || this.me.username;
				let op = {
					action: 'groupQrcode',
					title: encodeURIComponent(`我的二维码`),
					id: this.me.id,
					name: encodeURIComponent(name),
					avatar: encodeURIComponent(this.me.avatar),
					chatType: 'single',
				};
				uni.redirectTo({
					url:`/pages/setpageInfo/setpageInfo?action=${op.action}&title=${op.title}&id=${op.id}&name=${op.name}&avatar=${op.avatar}&chatType=${op.chatType}`,
				});
			},
		}
	}
</script>

# 四、游客扫码加好友

# 1、完成界面部分

# ① 在页面 /pages/setpageInfo/setpageInfo.vue

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 内容 -->
		<view>
			<!-- 聊天相关 -->
			...
			<!-- 聊天页设置 -->
			...
			<!-- 扫码之后的页面 -->
			<view v-if="setdata.action == 'autoAddGroup'">
				<!-- 群头像及介绍 -->
				<view class="m-3 bg-light p-3">
					<!-- 群 -->
					<view v-if="chatpageset.chatType == 'group'"
					class="flex flex-row align-center">
						<!-- 群头像 -->
						...
						<!-- 群名称及介绍 -->
						...
					</view>
					<!-- 个人 -->
					<view v-if="chatpageset.chatType == 'single'"
					class="flex flex-row align-center">
					    <!-- 头像 -->
					    <u--image :src="chatpageset.avatar" mode="widthFix"
					    width="90rpx" height="90rpx" radius="8rpx"></u--image>
						<!-- 介绍 -->
						<view class="flex flex-column justify-center ml-2">
							<text class="mb-1 u-line-1">{{chatpageset.name}}</text>
							<!-- 关注度 -->
							<!-- 粉丝 -->
						</view>
					</view>
				</view>
				<!-- 加群按钮 -->
				<view class="p-3">
					<!-- 进群理由 -->
					<view v-if="chatpageset.showAddGroupDesc"
					class="mb-2">
						<u-textarea v-model="chatpageset.addGroupDesc"
						border="surround" :maxlength="500"
						:adjustPosition="false" 
						:placeholder="chatpageset.areaPlaceHolder || 
						`说明一下加群理由,方便群主快速通过,选填(可不填)`"
						count :autoHeight="false"
						:height="100"
						@confirm="ScanQrcodeApplyAddGroup"></u-textarea>
					</view>
					<!-- 页面初始按钮 -->
					<u-button v-if="!chatpageset.showAddGroupDesc"
					:text="chatpageset.buttonText" type="success" @click="addGroupfn"></u-button>
					<!-- 申请加群按钮 -->
					<u-button v-if="chatpageset.showAddGroupDesc"
					:text="chatpageset.btnText || `提 交 加 群 申 请`" 
					type="primary" 
					@click="ScanQrcodeApplyAddGroup"></u-button>
				</view>
				<!-- 群公告 -->
				...
				<!-- h5端页面在微信打开没有导航栏给它一个底部导航栏 -->
				...
			</view>
			<!-- 账号信息设置 -->
			...
			<!-- 头像剪裁500rpx * 500rpx -->
			...
		    <!-- 删除群成员 -->
		    ...
		    <!-- 添加好友进群 -->
		    ...
		    <!-- 群主审批进群处理 -->
		    ...
		
		
		</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'){
					...
				}else if(this.setdata.action == 'groupQrcode'){
					...
					
					//二维码提示说明
					let sysinfo = uni.getSystemInfoSync().appName;
					let _type = this.chatpageset.chatType == 'group' ? '加群' : '加好友';
					// #ifdef H5
					this.chatpageset.sysinfo = `使用微信或者手机浏览器扫码${_type}`;
					// #endif
					// #ifdef MP
					this.chatpageset.sysinfo = `使用${sysinfo}小程序扫码${_type}`;
					// #endif
					// #ifdef APP
					this.chatpageset.sysinfo = `使用${sysinfo}APP扫码${_type}`;
					// #endif
				}else if(this.setdata.action == 'autoAddGroup'){
					console.log('扫码之后打开的地址', e);
					this.chatpageset.id = e.id;
					this.chatpageset.chatType = e.chatType;
					this.chatpageset.name = decodeURIComponent(e.name);
					this.chatpageset.avatar = decodeURIComponent(e.avatar);
					this.chatpageset.avatar = this.chatpageset.avatar && this.chatpageset.avatar.startsWith('/') ? 
					     requestUrl.http + this.chatpageset.avatar : this.chatpageset.avatar;
					// 获取群资料
					if(this.chatpageset.chatType == 'group'){
						this.getgroupinfo();
					}else{
						// 个人
						this.chatpageset.buttonText = `加 为 好 友`;
					}
				}else if(this.setdata.action == 'userinfoSet'){
					...
				}else if(this.setdata.action == 'avatarCut'){
					...
				}else if(this.setdata.action == 'deleteUserFromGroup'){
					...
				}else if(this.setdata.action == 'addUserFromGroup'){
					...
				}else if(this.setdata.action == 'applyAddGroup'){
					...
				}
			}
		},
		...
	}
</script>

# ② 在文件 /pages/setpageInfo/group.js

...
export default {
	...,
	methods: {
		// 申请加好友提交
		ScanQrcodeApplyAddUser(){
			console.log('申请加好友提交', this.chatpageset);
		},
		// 加个人为好友
		addUserFriend(){
			console.log('加个人为好友', this.chatpageset);
			this.chatpageset.showAddGroupDesc = true;
			this.chatpageset.areaPlaceHolder = `可描述一下加好友理由,方便对方快速通过`;
            this.chatpageset.btnText = '申 请 加 为 好 友';
		},
		// 通过扫码方式来申请加入群聊
		ScanQrcodeApplyAddGroup(){
			if(this.chatpageset.chatType == 'single') return this.ScanQrcodeApplyAddUser();
			console.log('通过扫码方式来申请加入群聊提交申请',this.chatpageset.addGroupDesc);
			...
		},
		// 处理进群的申请
		...,
		// 进群设置
		...,
		// 添加好友进群
		...,
		// 搜索好友
		...,
		// 往群里面加人
		...,
		// 点击群成员
		...,
		// 搜索群成员
		...,
		// 清空搜索
		...,
		// 删除群成员
		...,
		// 加入群聊
		addGroupfn(){
			if(this.chatpageset.chatType == 'single') return this.addUserFriend();
			console.log('加入群聊,看管理员怎么设置的');
			console.log('显示到页面的群资料',this.chatpageset);
			...
		},
		...
	}
}

# 2. 关于 游客:visitor用户:user 在消息页初始化接收消息的处理

大家可以发现,本节课开始我们的消息页会在刚打开的时候接收到一些消息。

# ① 聊天类文件 /common/js/chatClass.js 更新

具体是对:针对跳转链接的消息,消息页只接收一次:doMessage(msg)方法,具体查看类文件代码:类文件 /common/js/chatClass.js 完整代码

# ② 针对混入文件 /common/mixins/tool.js 更新

  1. 完善底部导航栏tabbar的显示隐藏;
  2. 完善返回上一页(新增对网址中有跳转链接redirectUrl及跳转类型redirectType的判断);
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
export default {
	onShow() {
		// 是否显示底部tabbar
		this.tabbarShow();
	},
	computed: {
		...mapState({
			me : state => state.Chatuser.regloginUser,
			// xiaoxiList : state => state.Chatuser.xiaoxiList,
			// totalNoReadNum : state => state.Chatuser.totalNoReadNum,
			// chatClass : state => state.Chatuser.chatClass,
		}),
		// 是否是游客
		isVisitor(){
			if(this.me && this.me.role == 'visitor'){
				return true;
			}
			return false;
		},
	},
	methods: {
		// 是否显示底部tabbar
		tabbarShow(){
			  // 获取当前页面实例
			  const currentPage = getCurrentPages().pop();
			  if (!currentPage) return;
			  
			  // 检查当前页面是否是TabBar页面
			  const tabBarPages = [
				'/pages/xiaoxi/xiaoxi',   
				'/pages/wode/wode',     
				// 添加所有TabBar页面路径
			  ];
			  
			  const isTabBarPage = tabBarPages.includes('/' + currentPage.route);
			  
			  if (this.me && this.me.role == 'visitor') {
				isTabBarPage && uni.hideTabBar().catch(() => {});
			  } else {
				isTabBarPage && uni.showTabBar().catch(() => {});
			  }
		},
		/**
		 * 判断当前H5环境是否在微信内置浏览器打开
		 * @returns {Boolean} true:微信环境 false:非微信环境
		 */
		isWeixinBrowser() {
			// 非H5环境直接返回false
			if (process.env.VUE_APP_PLATFORM !== 'h5') return false

			// 获取浏览器userAgent并转换为小写
			const ua = navigator.userAgent.toLowerCase()

			// 检测微信特有标识
			return ua.includes('micromessenger')
		},

		/**
		 * 扩展方法:获取详细的H5环境信息
		 * @returns {Object} 环境信息对象
		 */
		getBrowserEnv() {
			if (process.env.VUE_APP_PLATFORM !== 'h5') {
				return {
					inWeixin: false,
					inQQ: false,
					inWeibo: false
				}
			}

			const ua = navigator.userAgent.toLowerCase()
			return {
				inWeixin: ua.includes('micromessenger'), // 微信浏览器
				inQQ: ua.includes('qq/'), // QQ内置浏览器
				inWeibo: ua.includes('weibo'), // 微博内置浏览器
				inAlipay: ua.includes('alipay'), // 支付宝浏览器
				inUC: ua.includes('ucbrowser'), // UC浏览器
				isMobile: /mobile|android|iphone|ipad/.test(ua) // 是否移动设备
			}
		},
		
		/**
		 * 从URL中获取指定参数(增强版,解决双重编码问题)
		 * @param {String} name 参数名
		 * @returns {String} 解码后的参数值
		 */
		getQueryParam(name) {
			let value = null;
			
			// 在H5环境中
			if (process.env.VUE_APP_PLATFORM === 'h5') {
				// 方法1: 尝试从URL的search参数获取
				const urlParams = new URLSearchParams(window.location.search);
				value = urlParams.get(name);
				
				// 方法2: 如果search中没有,尝试从hash中获取
				if (value === null && window.location.hash.includes('?')) {
					const hashParts = window.location.hash.split('?');
					if (hashParts.length > 1) {
						const hashParams = new URLSearchParams(hashParts[1]);
						value = hashParams.get(name);
					}
				}
			} 
			// 在小程序或App环境中
			else {
				// 获取当前页面实例
				const pages = getCurrentPages();
				const currentPage = pages[pages.length - 1];
				if (currentPage && currentPage.options) {
					value = currentPage.options[name];
				}
			}
			
			// 双重解码处理:先解码一次,再解码第二次(处理双重编码情况)
			if (value !== null && value !== undefined) {
				try {
					// 先解码一次
					let decodedValue = decodeURIComponent(value);
					// 检查是否还包含编码字符,如果是则再次解码
					if (decodedValue.includes('%')) {
						decodedValue = decodeURIComponent(decodedValue);
					}
					return decodedValue;
				} catch (e) {
					console.error('参数解码错误:', e);
					return value;
				}
			}
			
			return value;
		},
		
		/**
		 * 处理URL参数重定向
		 */
		handleUrlRedirect() {
			const redirectUrl = this.getQueryParam('redirectUrl');
			const redirectType = this.getQueryParam('redirectType');
			
			console.log('重定向参数:', { redirectUrl, redirectType });
			
			if (redirectUrl && redirectType) {
				// 检查redirectType是否有效
				if (typeof uni[redirectType] === 'function') {
					try {
						console.log(`执行重定向: uni.${redirectType}(${redirectUrl})`);
						uni[redirectType]({ url: redirectUrl });
					} catch (e) {
						console.error('跳转失败:', e);
						this.navigateBack(); // 失败时使用默认返回逻辑
					}
				} else {
					console.error('无效的跳转类型:', redirectType);
					this.navigateBack(); // 无效的跳转类型使用默认返回逻辑
				}
			} else {
				console.log('无重定向参数,使用默认返回逻辑');
				this.navigateBack(); // 无参数时使用默认返回逻辑
			}
		},
		
		//页面返回逻辑
		// 返回首页逻辑
		async redirectToHome() {
			try {
				// 优先尝试标准跳转
				await uni.redirectTo({
					url: '/pages/xiaoxi/xiaoxi'
				})
			} catch (e) {
				// 处理tab页情况
				try {
					await uni.switchTab({
						url: '/pages/xiaoxi/xiaoxi'
					})
				} catch (e) {
					// 终极兜底方案
					uni.reLaunch({
						url: '/pages/xiaoxi/xiaoxi'
					})
				}
			}
		},
		
		//页面返回
		navigateBack() {
			// 首先检查是否有URL重定向参数
			const redirectUrl = this.getQueryParam('redirectUrl');
			const redirectType = this.getQueryParam('redirectType');
			
			console.log('URL重定向参数检查:', {
				redirectUrl,
				redirectType
			});
			
			if (redirectUrl && redirectType) {
				// 如果有重定向参数,优先使用重定向逻辑
				this.handleUrlRedirect();
				return;
			}
			
			const pages = getCurrentPages()
			// 判断是否是分享进入的独立页面
			if (pages.length === 1 || pages.length === 0) {
				// 尝试多种跳转方式确保可靠性
				this.redirectToHome().catch(() => {
					uni.showToast({
						title: '返回首页失败',
						icon: 'none'
					})
				})
			} else {
				uni.navigateBack()
			}
		},
	}
}

# 3. 提交加好友申请

(跟着一起学习后端,在本地调试的同学注意):
后端在之前的设计中没有 invite_confirm(是否需要用户确认才能加为好友(0-不需要 1- 需要用户确认 2-其他情况))字段,如果有同学用的我们本课之前的数据库,那么你可以加上这个字段在数据库中。
另外,记得把迁移文件模型都加上这个字段。
或者你可以直接下载本节课课件,把数据库替换一下(更建议大家去群里面下载最终的后端完整代码和数据库)。

# ① 页面处理

在页面 /pages/setpageInfo/setpageInfo.vue

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 内容 -->
		<view>
			<!-- 聊天相关 -->
			...
			<!-- 聊天页设置 -->
			...
			<!-- 群二维码 -->
			...
			<!-- 扫码之后的页面 -->
			<view v-if="setdata.action == 'autoAddGroup'">
				...
				<!-- 加群按钮 -->
				<view class="p-3">
					<!-- 进群理由 -->
					<view v-if="chatpageset.showAddGroupDesc"
					class="mb-2">
						<u-textarea v-model="chatpageset.addGroupDesc"
						border="surround" :maxlength="500"
						:adjustPosition="false" 
						:placeholder="chatpageset.areaPlaceHolder || `说明一下加群理由,方便群主快速通过,选填(可不填)`"
						count :autoHeight="false"
						:height="100"
						@confirm="ScanQrcodeApplyAddGroup"></u-textarea>
					</view>
					<!-- 页面初始按钮 -->
					<u-button v-if="!chatpageset.showAddGroupDesc"
					:text="chatpageset.buttonText" type="success" @click="addGroupfn"
					:disabled="chatpageset.btndisabled"></u-button>
					<!-- 申请加群按钮 -->
					<u-button v-if="chatpageset.showAddGroupDesc"
					:text="chatpageset.btnText || `提 交 加 群 申 请`" 
					type="primary" @click="ScanQrcodeApplyAddGroup"
					></u-button>
				</view>
				<!-- 群公告 -->
				...
				<!-- h5端页面在微信打开没有导航栏给它一个底部导航栏 -->
				...
			</view>
			<!-- 账号信息设置 -->
			...
			<!-- 头像剪裁500rpx * 500rpx -->
			...
		    <!-- 删除群成员 -->
		    ...
		    <!-- 添加好友进群 -->
		    ...
		    <!-- 群主审批进群处理 -->
		    ...
		
		
		</view>
	</view>
</template>

<script>
	...
	export default {
		mixins:[toolJs,updateUserInfoJs,avatarCutJs,GroupJs,parseTimeJs],
		data() {
			return {
				...
				chatpageset:{
					users:[],
					avatar:'',
					applydesc:'',
					showAddGroupDesc:false, //是否显示加入群聊的说明文本框
					btndisabled: false, // 初始时候按钮不可用状态
					buttonText: '', //初始时按钮文字
				},
			}
		},
		onLoad(e) {
			...
			// 动态生成数据
			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'){
					...
				}else if(this.setdata.action == 'autoAddGroup'){
					console.log('扫码之后打开的地址', e);
					this.chatpageset.id = e.id;
					this.chatpageset.chatType = e.chatType;
					this.chatpageset.name = decodeURIComponent(e.name);
					this.chatpageset.avatar = decodeURIComponent(e.avatar);
					this.chatpageset.avatar = this.chatpageset.avatar && this.chatpageset.avatar.startsWith('/') ?
					requestUrl.http + this.chatpageset.avatar : this.chatpageset.avatar;
					// 获取群资料
					if(this.chatpageset.chatType == 'group'){
						this.getgroupinfo();
					}else{
						// 个人
						this.chatpageset.buttonText = '加 为 好 友';
						// 获取用户设置信息
						this.getUserSetInfo();
					}
				}else if(this.setdata.action == 'userinfoSet'){
					...
				}else if(this.setdata.action == 'avatarCut'){
					...
				}else if(this.setdata.action == 'deleteUserFromGroup'){
					...
				}else if(this.setdata.action == 'addUserFromGroup'){
					...
				}else if(this.setdata.action == 'applyAddGroup'){
					...
				}
			}
		},
		...
	}
</script>

# ② 逻辑处理

用到先获取用户加好友的设置信息,接口查看:三十九、获取用户一些设置信息
在混入文件 /pages/setpageInfo/group.js

...
export default {
	...
	methods: {
		// 获取用户设置信息
		getUserSetInfo(){
			// 1. 自己
			if(this.me.id == this.chatpageset.id){
				this.chatpageset.btndisabled = true;
				return;
			};
			// 2. 请求
			return new Promise((resolve,reject)=>{
				uni.$u.http.post(requestUrl.http + `/api/chat/getUserSetInfo`,{
					userid: this.chatpageset.id,
				},{
					header:{
						token: this.me.token,
					}
				}).then(res=>{
					let UserSetInfo = res.data.data;
					console.log('用户的设置信息',UserSetInfo);
					// 1. 是否是自己的好友
					if(UserSetInfo.isgoodfriend){
						if(UserSetInfo.isgoodfriend_status){
							// 是自己好友且状态正常 - 开始聊天
							console.log('开始聊天');
							this.chatpageset.buttonText = `开 始 聊 天`;
						}else{
							console.log('状态异常');
							this.chatpageset.btndisabled = true;
							this.chatpageset.buttonText = `好 友 状 态 异 常,不 能 聊 天`;
						}
					}
					// 2. 设置信息存入chatpageset
					this.chatpageset = {
						...this.chatpageset,
						...UserSetInfo,
					};
					// 回调
					resolve(this.chatpageset);
				});
			});
		},
		// 申请加为好友提交数据
		ScanQrcodeApplyAddUser(){
			console.log('申请加为好友提交数据', this.chatpageset);
			uni.$u.http.post(requestUrl.http + `/api/chat/applyfriend`,{
				friend_id: this.chatpageset.id,
				nickname: this.chatpageset.addGroupDesc,
			},{
				header:{
					token: this.me.token
				}
			}).then(res=>{
				uni.showToast({title: '等待对方同意', icon:'success'});
				setTimeout(()=>{
					this.navigateBack();
				},1500);
			}).catch(err=>{
				uni.showToast({title: err.data.data, icon:'none',duration:5000});
			});
		},
		// 加个人为好友
		addUserFriend(){
			console.log('加个人为好友', this.chatpageset);
			// 是好友
			if(this.chatpageset.isgoodfriend && this.chatpageset.isgoodfriend_status){
				console.log('是我的朋友,可以直接聊天了', this.chatpageset);
				// 进入聊天页 传一下用户的信息过去在页面展示
				const userchat = {
					id: this.chatpageset.id,
					name: this.chatpageset.name,
					avatar: this.chatpageset.avatar,
					chatType: 'single', // 单聊 single 群聊 group
				};
				uni.navigateTo({
					url: `/pages/chat/chat?arg=${encodeURIComponent(JSON.stringify(userchat))}`,
				});
				return;
			}
			// 非好友
			if(this.chatpageset.invite_confirm == 0){
				console.log('直接加为好友');
			}else if(this.chatpageset.invite_confirm == 1){
				console.log('先申请,等待对方同意');
				this.chatpageset.showAddGroupDesc = true;
				this.chatpageset.areaPlaceHolder = `可描述一下加好友的理由,方便对方快速通过`;
				this.chatpageset.btnText = `申 请 加 为 好 友`;
			}
		},
		// 通过扫码方式来申请加入群聊
		...
		// 处理进群的申请
		...
		// 进群设置
		...
		// 添加好友进群
		...
		// 搜索好友
		...
		// 往群里面加人
		...
		// 点击群成员
		...
		// 搜索群成员
		...
		// 清空搜索
		...
		// 删除群成员
		...
		// 加入群聊
		...
		// 解散群或者退群或者删除好友
		...
		// 获取群资料
		...
		// 修改我在群里面的昵称
		...
		// 更新群公告
		...
		// 更新群名称
		...
		// 更新群信息
		...
		// 点击开关
		...
	}
}

# ③ 聊天页显示一下发送消息失败原因

# 1. 在混入文件 /pages/chat/plusIconAction.js

//发送消息
sendMessage(msgType, option = {}){
	...
	// 发给服务器消息
	if(msg.isSendToServer){
		this.chatClass.sendmessage(serverMsg).then(result => {
			...
		}).catch(error => {
			console.log('页面接收服务器错误结果',error);
			this.chatDataList[sendmsgIndex].sendStatus = 'fail';
			this.chatDataList[sendmsgIndex].failText = error.data.data;
			// 返回错误
			reject(error);
		});
	}else{
		...
	}
	...
}

# 2. 在组件 /components/chat-item/chat-item.vue

<!-- 聊天内容主体 -->
<view ...>
	<!-- 昵称的显示  -->
	<view v-if="setdata.shownickname"
	class="position-absolute"
	style="max-width: 500rpx;top: -36rpx;min-width:140rpx ;"
	:style="contentStyle"
	:class="[isMe ? 'right-0' : 'left-0']">
		<text class="text-light-muted u-line-1" style="font-size: 20rpx;">{{item.nickname}}</text>
	</view>
	...
</view>

...
<!-- 给服务器发消息状态 -->
<view v-if="item.sendStatus && item.sendStatus != 'success' && 
item.sendStatus !== 'pendingFile' "
class="flex align-center justify-end pr-5 pb-5">
	<text class="font-small"
	:class="[item.sendStatus == 'fail' ? 
	'text-danger' : 'text-success']">{{item.sendStatus == 'fail' ? 
	`消息发送失败${item.failText?':' + item.failText : ''}` : '消息正在发送中...'}}</text>
</view>

# 3. 如果是游客聊天,加一下标识在聊天页

在页面 /pages/chat/chat.nvue

onLoad(e) {
	if(!e.arg) return this.navigateBack();
	let arg = decodeURIComponent(e.arg);
	try{
		this.arg = JSON.parse(arg);
		console.log('聊天页参数对象',this.arg);
		if(this.arg && this.arg.name.startsWith('VIS')){
			this.arg.name = this.arg.name + `[游客]`;
		}
		...
	}catch(err){
		...
	}
}
...

# 4. 完善申请加我为好友设置

# 1 界面完善

在用户申请加对方为好友时候,一般客服是不需要审核的,用户需要审核,先完善这个页面。

# 1-1. 在页面 /pages/setpage/setpage.vue

	...
	<!-- 账号 -->
	...
	<!-- 加我为好友设置 -->
	<u-cell-group>
		<u-cell title="申请加我为好友设置"
		:customStyle="{'background-color':'#ffffff'}"
		isLink titleStyle="font-size:18px;"
		@click="setfun('applyAddMeFriendSet','申请加我为好友设置')"></u-cell>
	</u-cell-group>
	<!-- 聊天相关 -->
	...

# 1-2. 在页面 /pages/setpageInfo/setpageInfo.vue

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 内容 -->
		<view>
			<!-- 聊天相关 -->
			...
			<!-- 聊天页设置 -->
			...
			<!-- 群二维码 -->
			...
			<!-- 扫码之后的页面 -->
			...
			<!-- 账号信息设置 -->
			...
			<!-- 头像剪裁500rpx * 500rpx -->
			...
		    <!-- 删除群成员 -->
		    ...
		    <!-- 添加好友进群 -->
		    ...
		    <!-- 群主审批进群处理 -->
		    ...
		    <!-- 申请加我为好友设置 -->
			<view v-if="setdata.action == 'applyAddMeFriendSet'">
			    <!-- 设置选项 -->
				<view>
					<u-cell-group>
						<u-cell
						title="加我为好友时需要我验证"
						:border="false" clickable 
						:customStyle="customStyles"
						:iconStyle="iconStyles"
						:titleStyle="titleStyles">
						    <view slot="value">
						         <u-switch v-model="chatpageset.invite_confirm" 
								 @change="changeSwitch('invite_confirm', setdata.action)"></u-switch>
							</view>
						</u-cell>
					</u-cell-group>
					<u-gap height="10" bgColor="#EDEDED"></u-gap>
				</view>
			</view>
		
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		data() {
			return {
				...,
				chatpageset:{
					...
					buttonText: '', // 初始化按钮文字
					invite_confirm: true, // 加我为好友字段设置
				},
			}
		},
		onLoad(e) {
			...
			// 动态生成数据
			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'){
					...
				}else if(this.setdata.action == 'autoAddGroup'){
					...
					// 是否有跳转字段
					this.chatpageset.redirect =  e.redirect ? e.redirect : false ;
					// 获取群资料
					if(this.chatpageset.chatType == 'group'){
						this.getgroupinfo();
					}else{
						// 个人
						this.chatpageset.buttonText = '加 为 好 友';
						// 获取用户设置信息
						this.getUseraSetInfo().then(res=>{
							this.chatpageset = res;
							console.log('---获取用户设置信息',this.chatpageset);
							if(this.chatpageset.redirect){
								if(this.chatpageset.isgoodfriend && this.chatpageset.isgoodfriend_status){
									this.groupOrSingleChatRedirect('single');
								}else{
									console.log('非好友或者状态有问题');
									if(this.chatpageset.invite_confirm == 0){
										console.log('非好友或者状态有问题,但是你可以加他,不用它审核就可以成为朋友');
										// 接下来自动加好友成功后直接聊天
										this.autoAddFriendAndAgree().then(res=>{
											uni.showToast({title:'连线成功',icon:'success'});
											// 已是好友关系,直接聊天
											setTimeout(()=>{
												this.groupOrSingleChatRedirect('single');
											},1000);
										});
									}else if(this.chatpageset.invite_confirm == 1){
										console.log('非好友或者状态有问题,但是你可以加他,要他审核');
									}
								}
							}
						});
					}
				}else if(this.setdata.action == 'userinfoSet'){
					...
				}else if(this.setdata.action == 'avatarCut'){
					...
				}else if(this.setdata.action == 'deleteUserFromGroup'){
					...
				}else if(this.setdata.action == 'addUserFromGroup'){
					...
				}else if(this.setdata.action == 'applyAddGroup'){
					...
					
				}else if(this.setdata.action == 'applyAddMeFriendSet'){
					// 获取用户设置信息
					this.initGetUseraSetInfo().then(res=>{
						console.log('获取用户设置信息',res);
						if(res){
							this.chatpageset = {
								...res,
								invite_confirm: !!res.invite_confirm,
							};
							console.log('获取用户设置信息this.chatpageset',this.chatpageset);
						}
					});
				}
			}
		},
		...
	}
</script>

# 1-3. 在文件 /pages/setpageInfo/group.js

...
export default {
	...
	methods: {
		// 获取用户设置信息 - 页面初始化就要执行
		initGetUseraSetInfo(){
			return new Promise((resolve,reject)=>{
				let meInfo = uni.getStorageSync('chatuser');
				meInfo =  meInfo ? JSON.parse(meInfo) : '';
				if(meInfo){
					uni.$u.http.post(requestUrl.http + `/api/chat/getUserSetInfo`,{
						userid: meInfo.id,
					},{
						header:{
							token: meInfo.token,
						}
					}).then(res=>{
						let UserSetInfo = res.data.data;
						resolve(UserSetInfo);
					});
				}
			});
		},
		// 获取用户设置信息
		...
		// 申请加为好友提交数据
		...
		// 加个人为好友
		addUserFriend(){
			console.log('加个人为好友', this.chatpageset);
			if(this.chatpageset.isgoodfriend && this.chatpageset.isgoodfriend_status){
				console.log('是好友了,可以直接聊天了',this.chatpageset);
				// 进入聊天页 传一下用户的信息过去在页面展示
				const userchat = {
					id: this.chatpageset.id,
					name: this.chatpageset.name,
					avatar: this.chatpageset.avatar,
					chatType: 'single', // 单聊 single 群聊 group
				};
				uni.navigateTo({
					url: `/pages/chat/chat?arg=${encodeURIComponent(JSON.stringify(userchat))}`,
				});
				return;
			} 
			// 非好友
			if(this.chatpageset.invite_confirm == 0){
				console.log('非好友对方是客服,一般直接聊天,客服一般不会让你加客服为好友');
				
			}else if(this.chatpageset.invite_confirm == 1){
				console.log('先申请,等待对方同意');
				this.chatpageset.showAddGroupDesc = true;
				this.chatpageset.areaPlaceHolder = `可描述一下加好友的理由,方便对方快速通过`;
				this.chatpageset.btnText = `申 请 加 为 好 友`;
			}
		},
		// 通过扫码方式来申请加入群聊
		...
		// 处理进群的申请
		...
		// 进群设置
		...
		// 添加好友进群
		...
		// 搜索好友
		...
		// 往群里面加人
		...
		// 点击群成员
		...
		// 搜索群成员
		...
		// 清空搜索
		...
		// 删除群成员
		...
		// 加入群聊
		...
		// 解散群或者退群或者删除好友
		...
		// 获取群资料
		...
		// 修改我在群里面的昵称
		...
		// 更新群公告
		...
		// 更新群名称
		...
		// 更新群信息
		...
		// 点击开关
		changeSwitch(key,action = false){
			console.log(`点击开关${key}`,this.chatpageset[key]);
			if(action){
				if(action == 'applyAddMeFriendSet'){
					console.log('申请叫我为好友设置',this.chatpageset);
					this.updateUserInfo('invite_confirm');
				}
			}else{
				console.log('通过开关设置单聊或者群聊信息',this.chatpageset);
				this.chatClass.updateSomeOneChatItem({
					id: this.chatpageset.id,
					chatType: this.chatpageset.chatType,
				}, this.chatpageset).then(res =>{
					console.log('设置之后的数据', res);
					// 方式一: 全局通知聊天页
					// 方式二:直接在聊天页获取消息页的信息进行处理
				});
			}
		},
	}
}

# 1-4. 在文件 /pages/setpageInfo/updateUserInfo.js

// 修改我的账号信息
updateUserInfo(fieldname) {
	let arg = {};
	switch (fieldname) {
		case 'nickname':
			...
			break;
		case 'avatar':
			...
			break;
		case 'invite_confirm':
			arg = {
				apiurl: '/api/chat/updateUserinfo',
				data: {
					fieldname: fieldname,
					fieldValue: Number(this.chatpageset.invite_confirm),
				},
			};
			// 我的信息更新一下
			this.me[fieldname] = this.chatpageset.invite_confirm;
			break;
	}
	// 服务器处理 
	...
},

# 5. 根据地址是否有redirect参数来简化按钮操作

如果地址有redirect参数,则不需要点击按钮直达下一步操作。

# 5-1. 在页面 /pages/setpageInfo/setpageInfo.vue

...}else if(this.setdata.action == 'autoAddGroup'){
	console.log('扫码之后打开的地址', e);
	this.chatpageset.id = e.id;
	this.chatpageset.chatType = e.chatType;
	this.chatpageset.name = decodeURIComponent(e.name);
	this.chatpageset.avatar = decodeURIComponent(e.avatar);
	this.chatpageset.avatar = this.chatpageset.avatar && this.chatpageset.avatar.startsWith('/') ?
	requestUrl.http + this.chatpageset.avatar : this.chatpageset.avatar;
	// 是否有跳转字段
	this.chatpageset.redirect =  e.redirect ? e.redirect : false ;
	// 获取群资料
	if(this.chatpageset.chatType == 'group'){
		this.getgroupinfo();
	}else{
		// 个人
		this.chatpageset.buttonText = '加 为 好 友';
		// 获取用户设置信息
		this.getUseraSetInfo().then(res=>{
			this.chatpageset = res;
			console.log('---获取用户设置信息',this.chatpageset);
			if(this.chatpageset.redirect){
				if(this.chatpageset.isgoodfriend && this.chatpageset.isgoodfriend_status){
					this.groupOrSingleChatRedirect('single');
				}else{
					console.log('非好友或者状态有问题');
					if(this.chatpageset.invite_confirm == 0){
						console.log('非好友或者状态有问题,但是你可以加他,不用它审核就可以成为朋友');
						// 接下来自动完成两步
						// 自动加对方为好友
						// 加完之后,进入userinfo页面根据聊天设置来判断
						this.autoAddFriendAndAgree().then(res=>{
							uni.showToast({title:'连线成功',icon:'success'});
							// 已是好友关系,直接聊天
							setTimeout(()=>{
								this.groupOrSingleChatRedirect('single');
							},1000);
						});
					}else if(this.chatpageset.invite_confirm == 1){
						console.log('非好友或者状态有问题,但是你可以加他,要他审核');
					}
				}
			}
		});
	}
}else if(...

# 5-2. 在文件 /pages/setpageInfo/group.js

用到当添加好友设置为:无需我审核的时候,进行自动添加好友并发送websocket消息的接口说明,接口查看:四十、自动添加好友并通知websocket消息

...
export default {
	...
	methods: {
		// 自动加群并同意
		async autoAddGroupAndAgree(){
			return new Promise((resolve,reject)=>{
				console.log('自动加群并同意this.chatpageset',this.chatpageset);
				console.log('自动加群并同意this.me',this.me);
				// return;
				// 交互
				uni.$u.http.post(requestUrl.http + `/api/chat/groupInviteUser`,{
					group_id: this.chatpageset.id,
					user_id: this.me.id,
					inviteuser_id: -1,// 小于0代表自己申请进群,没有人拉我进群
					addGroupDesc: '当群设置为任何人都可以进入时,用户自主加群群聊',
				},{
					header:{
						token: this.me.token,
					}
				}).then(res=>{
					resolve(res);
				});
			});
		},
		// 自动加对方为好友并同意
		async autoAddFriendAndAgree(){
			return new Promise((resolve,reject)=>{
				// 我的信息
				let meInfo = uni.getStorageSync('chatuser');
				meInfo = meInfo ? JSON.parse(meInfo) : '';
				let nickname = ``;
				if(meInfo){
					nickname = meInfo.nickname || meInfo.username;
					nickname += meInfo.role == 'visitor' ? '[游客]' : '[平台注册用户]';
					// 交互
					uni.$u.http.post(requestUrl.http + `/api/chat/autoAddFriendAndAgree`,{
						friend_id: this.chatpageset.id,
						nickname: `我是${nickname},系统自动加为你好友的`,
					},{
						header:{
							token: meInfo.token,
						}
					}).then(res=>{
						resolve(res);
					});
				}
			});
		},
		// 进群|单聊聊天调转
		...
		// 获取用户设置信息 - 页面初始化就要执行
		...
		// 获取用户设置信息
		...
		// 申请加为好友提交数据
		...
		// 加个人为好友
		addUserFriend(){
			console.log('加个人为好友', this.chatpageset);
			if(this.chatpageset.isgoodfriend && this.chatpageset.isgoodfriend_status){
				console.log('是好友了,可以直接聊天了',this.chatpageset);
				this.groupOrSingleChatRedirect(chatType = 'single');
				return;
			} 
			// 非好友
			if(this.chatpageset.invite_confirm == 0){
				console.log('非好友, 但可以加他为好友不用他审核');
				this.autoAddFriendAndAgree().then(res=>{
					uni.showToast({title:'连线成功',icon:'success'});
					// 已是好友关系,直接聊天
					setTimeout(()=>{
						this.groupOrSingleChatRedirect('single');
					},1000);
				});
			}else if(this.chatpageset.invite_confirm == 1){
				console.log('先申请,等待对方同意');
				this.chatpageset.showAddGroupDesc = true;
				this.chatpageset.areaPlaceHolder = `可描述一下加好友的理由,方便对方快速通过`;
				this.chatpageset.btnText = `申 请 加 为 好 友`;
			}
		},
		// 通过扫码方式来申请加入群聊
		...
		// 处理进群的申请
		...
		// 进群设置
		...
		// 添加好友进群
		...
		// 搜索好友
		...
		// 往群里面加人
		...
		// 点击群成员
		openUserInfo(item,action){
			console.log(item);
			if(action == 'chatGroup'){
				// 进入聊天页 传一下用户的信息过去在页面展示
				// const userchat = {
				// 	id: item.id,
				// 	name: item.name,
				// 	avatar: item.avatar,
				// 	chatType: 'group', // 单聊 single 群聊 group
				// };
				// uni.navigateTo({
				// 	url: `/pages/chat/chat?arg=${encodeURIComponent(JSON.stringify(userchat))}`,
				// });
				this.groupOrSingleChatRedirect('group', item);
			}else if(action == 'deleteGroupUser'){
				...
			}else if(action == 'addGroupUser'){
				...
			}else{
				...
			}
		},
		// 搜索群成员
		...
		// 清空搜索
		...
		// 删除群成员
		...
		// 加入群聊
		addGroupfn(){
			if(this.chatpageset.chatType == 'single') return this.addUserFriend();
			console.log('加入群聊,看管理员怎么设置的');
			console.log('显示到页面的群资料',this.chatpageset);
			// 如果你是这个群群成员或者群主
			if(this.chatpageset.isGroupUser){
				this.groupOrSingleChatRedirect();
				return;
			}
			// 你不是群成员
			if(this.chatpageset.invite_confirm == 0){
				// 任何人都能进去聊天
				...
			}else if(this.chatpageset.invite_confirm == 1){
				// 要群主同意你才能进群
				...
			}else if(this.chatpageset.invite_confirm == 2){
				// 如果你是游客,则要先登录再来申请进群,然后在等待群主同意
				...
			}
			
		},
		// 解散群或者退群或者删除好友
		...
		// 获取群资料
		// 获取群资料
		getgroupinfo(){
			return new Promise((resolve,reject)=>{
				uni.$u.http.get(requestUrl.http + `/api/chat/groupinfo/${this.chatpageset.id}`, {
					header: {
						token: this.me.token,
					},
				}).then(res => {
					...
					if(groupUsersIds){
						if(groupUsersIds.includes(this.me.id)){
							// 我是群成员
							this.chatpageset.isGroupUser = true;
							this.chatpageset.buttonText = '进群聊天';
							console.log('我是群成员',this.chatpageset);
							if(this.chatpageset.redirect){
								// 直接进群聊天
								this.groupOrSingleChatRedirect('group');
							}
						}else{
							console.log('我不是群成员',this.chatpageset);
							if(this.chatpageset.redirect && this.chatpageset.invite_confirm == 0){
								console.log('我不是群成员, 但群任何人都可以进,并且需要自动跳转');
								// 自动加群并同意
								this.autoAddGroupAndAgree().then(res=>{
									uni.showToast({title: '连线成功', icon:'success'});
									// 已是群成员,直接聊天
									setTimeout(()=>{
										this.groupOrSingleChatRedirect('group');
									},1000);
									
								});
							}
						}
					}
					
					
					resolve(this.chatpageset);
					
				}).catch(err =>{
					this.navigateBack();
				});
			});
		},
		// 修改我在群里面的昵称
		...
		// 更新群公告
		...
		// 更新群名称
		...
		// 更新群信息
		...
		// 点击开关
		...
	}
}
更新时间: 2025年9月23日星期二晚上9点47分