# 七、搜索用户

# 1. 搜索用户接口文档

搜索用户接口文档具体查看:四、搜索用户

# 2. 搜索用户界面开发

# ① 新建搜索用户页面 /pages/search/search.vue

pages.json配置页面

{
    "path" : "pages/search/search",
    "style" : 
    {
        "navigationBarTitleText" : "搜索",
        "navigationStyle": "custom"
    }
}

# ② 在页面 /pages/wode/wode.nvue 跳转

<template>
	<view>
		<!-- 头像昵称 -->
		...
	    <!-- 间隔槽 -->
		...
		<!-- cell 单元格 -->
		<u-cell-group>
			<u-cell v-for="(item,index) in uCellMenus" :key="index"
			:icon="item.icon" :title="item.title"
			:border="false" clickable isLink
			:customStyle="customStyles"
			:iconStyle="iconStyles"
			:titleStyle="titleStyles"
			@click="openCell(item,index)"></u-cell>
		</u-cell-group>
		<!-- 间隔槽 -->
		...
	</view>
</template>

<script>
	...
	export default {
		data() {
			return {
				...
				uCellMenus:[
					{icon:'plus-people-fill',title:'添加朋友',url:'/pages/search/search'},
					{icon:'chat',title:'发起群聊',url:''},
					{icon:'scan',title:'扫一扫',url:''},
				],
			}
		},
		...
		methods: {
			// 点击栏目
			openCell(item,index){
				if(!item.url) return;
				if(!this.user || this.user.role == 'visitor'){
					return uni.navigateTo({
						url: '/pages/loginCenter/loginCenter',
					});
				}
				uni.navigateTo({
					url: item.url,
				});
			},
			...
		}
	}
</script>

# ③ 在页面 /pages/search/search.vue

<template>
	<view class="page">
		<!-- 导航栏 -->
		<!-- #ifdef MP -->
		<chat-navbar  :fixed="true" :showPlus="false" :showUser="false" :showBack="true"
			navbarClass="navbar-bgColor" :h5WeiXinNeedNavbar="false">
		</chat-navbar>
		<!-- #endif -->
		<!-- 搜索框 -->
		<view class="flex align-center p-3">
			<u--input placeholder="搜 索" prefixIcon="search"
			prefixIconStyle="font-size:22px;color:#909399;"
			confirmType="search" v-model="keyword" clearable
			:maxlength="50" showWordLimit focus
			:adjustPosition="false"
			:customStyle="inputStyle"
			@input="searchData"></u--input>
			<text class="font text-primary ml-2" @click="navigateBack">取消</text>
		</view>
		<!-- 搜索结果 -->
		<view v-if="keyword">
			<view v-if="searchResStatus">
				<!-- 搜索用户的结果 -->
				<view v-if="searchRes.length"
				class="flex flex-column justify-center">
				    <u-list @scrolltolower="scrolltolower">
					  <u-list-item v-for="(item, index) in searchRes" :key="index">
						<u-cell :title="item.nickname || item.username">
						  <u-avatar
							slot="icon"
							shape="square"
							size="35"
							:src="item.avatar"
							customStyle="margin: -3px 5px -3px 0"
						  ></u-avatar>
						</u-cell>
					  </u-list-item>
					</u-list>
				</view>
				<view v-else>
					<u-empty mode="search"></u-empty>
				</view>
			</view>
			<view v-else class="flex align-center justify-center mt-3">
				<text class="font text-muted">正在搜索中...</text>
			</view>
		</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 {
				inputStyle:{
					"background-color":"#ffffff",
				},
				chatuser_token: '',
				keyword:'',
				searchResStatus:false, // 搜索结果状态
				searchRes:[],
			}
		},
		computed:{
			...mapState({
				user : state => state.Chatuser.regloginUser,
			}),
		},
		onLoad() {
			this.chatuser_token = uni.getStorageSync('chatuser_token');
			if (!this.chatuser_token || this.user.role == 'visitor') {
				return uni.switchTab({
					url: '/pages/wode/wode'
				});
			}
		},
		methods: {
			searchData(e){
				// console.log('搜索内容',e);
				// console.log('搜索内容',this.keyword);
				this.searchResStatus = false;
				if(this.keyword.length >= 1) this.searchAjax();
			},
			searchAjax(){
				uni.$u.http.post(requestUrl.http + `/api/chat/searchUser`, {
					keyword:this.keyword,
				}, {
					header: {
						token: this.chatuser_token,
					},
				}).then(res => {
					console.log('服务器返回的结果', res);
					this.searchResStatus = true;
					this.searchRes = [];
					if(res.data.data.length){
						this.searchRes = res.data.data;
					}
					
				}).catch(err => {
					console.log('出错', err);
					if (err.data && err.data.data) {
						uni.showToast({
							title: err.data.data,
							icon: 'none',
							duration: 5000
						});
					}
				});
			},
			//加载跟多
			scrolltolower(){
				console.log('滚动条滚动到底部了加载更多搜索内容');
			},
		}
	}
</script>

<style>
    /* 导航栏背景色 */
	.navbar-bgColor {
		background-color: #ededed;
	}
</style>

# 八、查看用户信息

# 1. 查看用户资料接口文档

搜索用户接口文档具体查看:十六、查看用户资料

# 2. 查看用户资料界面开发

# ① 新建用户信息页面 /pages/userinfo/userinfo.vue

pages.json配置页面

{
	"path" : "pages/userinfo/userinfo",
	"style" : 
	{
		"navigationBarTitleText" : "用户信息展示",
		"navigationStyle": "custom"
	}
}

# ② 在页面 /pages/search/search.vue 跳转

<template>
	<view class="page">
		...
		<!-- 搜索结果 -->
		<view v-if="keyword">
			<view v-if="searchResStatus">
				<!-- 搜索用户的结果 -->
				<view ...>
				    <u-list ...>
					  <u-list-item ...>
						<u-cell :title="item.nickname || item.username"
						@click="openUserInfo(item, index)">
						  ...
						</u-cell>
					  </u-list-item>
					</u-list>
				</view>
				<view v-else>
					<u-empty mode="search"></u-empty>
				</view>
			</view>
			<view ...>
				...
			</view>
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		methods: {
			openUserInfo(item, index){
				console.log('查看用户信息',item);
				uni.navigateTo({
					url: '/pages/userinfo/userinfo?uuid=' + encodeURIComponent(item.uuid),
				});
			},
			...
		}
	}
</script>

# ③ 在页面 /pages/userinfo/userinfo.vue

<template>
	<view class="page">
		<!-- 导航栏 -->
		<chat-navbar  :fixed="true" :showPlus="false" :showUser="false" :showBack="true"
			navbarClass="navbar-bgColor" :h5WeiXinNeedNavbar="false">
		</chat-navbar>
		<!-- 介绍 -->
		<view class="p-3 flex align-center justify-between">
			<!-- 头像 -->
			<view class="ml-1 mr-3">
				<u--image mode="widthFix"
				:src="avatarShow"        
				width="120rpx" height="120rpx" radius="20rpx"></u--image>
			</view>
			<!-- 昵称 -->
			<view class="flex flex-1 flex-column justify-center">
				<text class="font-lg font-weight-bold">{{nicknameShow}}</text>
				<view class="flex justify-between mt-2">
					<text class="font text-light-muted">{{nicknameNextShow}}</text>
					<!-- <text class="font-lg text-light-muted iconfont">&#xe657;</text> -->
				</view>
			</view>
		</view>
		<!-- 处理 -->
		<view class="p-3 flex align-center">
			<u-button :text="btn.text" :type="btn.type" @click="sendMessageFun"
			:loading="btn.loading" :loadingText="btn.loadingText"
			:loadingMode="btn.loadingMode" :disabled="btn.disabled"></u-button>
		</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 {
				uuid:'',
				user:null,
				// 按钮
				btn:{
					text:'发消息',
					type:'primary',
					loading:false,
					loadingText:'正在处理中',
					loadingMode:'circle', // spinner 雪花
					clicktype:'init', // 初始化
					disabled:false,
				},
			}
		},
		onLoad(e) {
			if(!e.uuid) return this.navigateBack();
			this.uuid = e.uuid;
			this.getUserInfo();
		},
		computed:{
			...mapState({
				me : state => state.Chatuser.regloginUser,
			}),
			//头像
			avatarShow(){
				let avatar = this.user && this.user.avatar;
				avatar = avatar && avatar.startsWith('http') ? avatar : `${requestUrl.http}${avatar}`;
				console.log(avatar);
				return avatar;
			},
			// 账号
			nicknameShow(){
				return this.user && (this.user.nickname || this.user.username);
			},
			// 账号下面的小字
			nicknameNextShow(){
				return this.user && (this.user.userinfo.location || ``);
			}
		},
		methods: {
			// 获取用户信息
			getUserInfo(){
				uni.$u.http.get(requestUrl.http + `/api/userinfo/${this.uuid}`).then(res => {
					console.log('服务器返回的结果', res);
					this.user = res.data.data;
				}).catch(err => {
					console.log('出错', err);
					if (err.data && err.data.data) {
						uni.showToast({
							title: err.data.data,
							icon: 'none',
							duration: 5000
						});
					}
				});
			},
			// 发消息
			sendMessageFun(){
				console.log('发消息逻辑处理',this.me);
				const role = this.me.role; // 'visitor'|'user'
				const { sendCount, needFollow } = this.user.chatset[role];
				// 1. 检查是否需要关注
				// if (needFollow && !this.me.hasFollowed) {
				// 	  console.log('请先关注对方才能发消息');
				// 	  return; // 终止后续逻辑
				// }
				// 2. 根据发送权限处理
				switch (sendCount) {
					case 0:
						if(role == 'visitor'){
							console.log('游客无法发送消息,请登录');
							this.btn.clicktype = 'needLogin';
						}else if(role == 'user'){
							console.log('请先添加对方为好友才能发消息');
							this.btn.clicktype = 'applyFriend';
						}
						break;
					case 1:
						console.log('可以发一条消息');
						this.btn.clicktype = 'sendOne';
						break;
						
					default: // sendCount >= 2
						console.log('发消息不受限制');
						// 实际发送操作...
				}
				// 3. 根据点击类型处理不同逻辑
				if(this.btn.clicktype == 'applyFriend'){
					this.btn.text = '对方设置为:需加为好友才能发消息';
					uni.showModal({
						content: '申请加对方为好友?',
						success:(res)=> {
							if (res.confirm) {
								console.log('处理申请的逻辑');
								this.btn.loading = true;
								this.btn.loadingText = '申请提交中';
								//和服务器提交申请数据
								setTimeout(()=>{
									this.btn.loading = false;
									this.btn.text = '申请提交成功,等待对方同意';
									this.btn.disabled = true;
									this.btn.type = 'success';
								},3000);
							} 
						}
					});
				}else if(this.btn.clicktype == 'needLogin'){
					this.btn.text = '请先登录才能发消息';
					uni.showModal({
						content: '是否去登录?',
						success: function (res) {
							if (res.confirm) {
								console.log('去登录页');
							} 
						}
					});
				}else if(this.btn.clicktype == 'sendOne'){
					this.btn.text = '发消息';
					console.log('跳转到聊天页');
				}
			},
		}
	}
</script>

<style>
    /* 导航栏背景色 */
	.navbar-bgColor {
		background-color: #ededed;
	}
</style>

# 九、申请添加好友

# 1. 申请添加好友接口文档

搜索用户接口文档具体查看:五、申请添加好友

# 2. 申请添加好友代码

在页面 /pages/userinfo/userinfo.vue

<template>
	<view class="page">
		...
		<!-- 处理 -->
		<view v-if="btn.clicktype == 'applyFriend'" class="p-3 flex align-center">
			<u-textarea :placeholder="textarea.placeholder" v-model="textarea.nickname" 
			count :adjustPosition="false"
			height="70"></u-textarea>
		</view>
		<view class="p-3 flex align-center">
			<u-button :text="btn.text" :type="btn.type" 
			@click="sendMessageFun" :loading="btn.loading"
			:loadingText="btn.loadingText" :loadingMode="btn.loadingMode" 
			:disabled="btn.disabled"></u-button>
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		data() {
			return {
				...,
				//表单
				textarea: {
					nickname: '',
					placeholder: '',
				},

			}
		},
		...,
		methods: {
			...,
			//发消息
			sendMessageFun() {
				console.log('发消息的逻辑', this.me);
				const role = this.me.role; //'visitor' | 'user'
				const {sendCount,needFollow} = this.user.chatset[role];
				// 1. 检查是否需要关注
				// if(needFollow && this.me.hasFollowed){
				// 	console.log('请先关注对方才能发消息');
				// 	return; // 程序结束
				// }
				// 2. 根据对方设置的聊天权限处理
				switch (sendCount) {
					case 0:
						if (role == 'visitor') {
							console.log('游客无法发消息,要先登录');
							this.btn.clicktype = 'needLogin';
							this.btn.text = '请先登录才能发消息';
							uni.showModal({
								content: '是否去登录?',
								success: res => {
									if (res.confirm) {
										console.log('去登录页');
									}
								},
							});
						} else if (role == 'user') {
							console.log('请先添加对方为好友才能发消息',this.btn.clicktype);
							if (this.btn.clicktype == 'init') {
								this.btn.text = '加为好友';
								this.textarea.placeholder = `对方设置为:需要加为好友才能发消息,请介绍一下自己或者说明申请加对方为好友原因,选填`;
								this.btn.clicktype = 'applyFriend';

							} else {
								this.btn.loading = true;
								this.btn.loadingText = '申请提交中';
								uni.$u.http.post(requestUrl.http + `/api/chat/applyfriend`, {
									friend_id: this.user.id,
									nickname: this.textarea.nickname,
								}, {
									header: {
										token: uni.getStorageSync('chatuser_token'),
									}
								}).then(res => {
									console.log('服务器返回的结果', res);
									this.btn.loading = false;
									if(res.data.data == 'ok'){
										this.btn.text = '申请提交成功,等待对方同意,请勿重复申请';
										this.btn.clicktype = 'init';
										this.btn.disabled = true;
										this.btn.type = 'success';
									}
								}).catch(err => {
									console.log('出错', err);
									this.btn.loading = false;
									if (err.data && err.data.data) {
										uni.showToast({
											title: err.data.data,
											icon: 'none',
											duration: 5000
										});
										this.btn.text = err.data.data;
										this.btn.clicktype = 'init';
										this.btn.disabled = true;
										this.btn.type = 'error';
									}
								});
							}
						}
						break;
					case 1:
						console.log('可以发一条消息');
						this.btn.clicktype = 'sendOne';
						this.btn.text = '发消息';
						console.log('去聊天页');
						// uni.navigateTo({
						// 	url: '/pages/chat/chat',
						// });
						break;
					default:
						console.log('发消息不受限制');
						break;
				}
			}
		}
	}
</script>

# 十、查看好友申请列表(获取别人申请我为好友的列表数据)

# 1. 查看好友申请列表接口文档

搜索用户接口文档具体查看:六、查看好友申请列表(获取别人申请我为好友的列表数据)

# 2. 好友申请信息可以在初始化的时候获取

/store/modules/chatuser.js 初始化或者登录之后获取,然后显示在页面上做提醒

import {requestUrl} from '@/common/mixins/configData.js';
export default{
	// 对应的mapState,在computed中引用导入
	// 类似于data,把全局或者公共部分放在这里
	state:{
	   regloginUser:null, //注册登录后续的操作res结果存储
	   // 定义加我为好友的信息
	   goodfriendapply:{
		   alldata:[], // 所有申请加我为好友的用户信息
		   pendingCount:0, // 多少未处理
	   },
	},
	// 异步的方法,在methods引入
	actions:{
		//注册登录后续的操作
		regloginAction({commit,state,dispatch}, regloginRes){
			...
			//获取好友申请信息
			dispatch('getGoodfriendapply');
		},
		// 用户退出登录
		...
		// 初始化登录注册状态(避免刷新页面state没有数据)
		initChatuserAction({commit,state,dispatch}){
			console.log('初始化登录注册状态',state);
			// 给state赋值
			let user = uni.getStorageSync('chatuser') ?
			JSON.parse(uni.getStorageSync('chatuser')) : '';
			if(user){
				state.regloginUser = user;
				console.log('初始化登录注册状态',state);
				//获取好友申请信息
				dispatch('getGoodfriendapply');
			}
		},
		//获取好友申请信息
		getGoodfriendapply({commit,state}, page = 1, limit = 10){
			console.log('看一下我的情况',state.regloginUser);
			if(state.regloginUser && state.regloginUser.role == 'user'){
				uni.$u.http.get(requestUrl.http + `/api/chat/listapplyfriend/${page}?limit=${limit}`, {
					header: {
						token: uni.getStorageSync('chatuser_token'),
					}
				}).then(res => {
					console.log('服务器返回的好友申请结果', res);
					state.goodfriendapply = res.data.data;
				});
			}
		},
	},
}

# 3. 显示在页面上做提示

如:可以显示在 /pages/friendsList/friendsList.nvue 朋友列表页面

<template>
	<view>
		<!-- 导航栏 -->
		...
		
		<!-- 朋友列表 -->
		<u-index-list :indexList="indexList">
			<view slot="header" class="list">
				<view v-for="(item,index) in topMenus" :key="index">
					<view class="flex align-center justify-between pr-3" 
					@click="opentopMenus(item,index)">
						<view class="list__item">
							<u-avatar shape="square" size="35" 
							:icon="item.icon" fontSize="26" randomBgColor></u-avatar>
							<text class="list__item__user-name">{{item.title}}</text>
						</view>
						<!-- 提示待处理数量 -->
						<view class="flex align-center">
							<u-badge :max="99" :value="goodfriendapply.pendingCount"></u-badge>
						</view>
					</view>
					<u-line></u-line>
				</view>
			</view>
			<!-- 列表 -->
			...
		</u-index-list>
		
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	...
	export default {
		mixins: [toolJs],
		data() {
			return {
				...
				topMenus:[
					{icon:'man-add-fill',title:'新的朋友',url:''},
					// {icon:'tags-fill',title:'标签',url:''},
					// {icon:'chrome-circle-fill',title:'朋友圈',url:''},
					// {icon:'qq-fill',title:'QQ',url:''},
				],
			}
		},
		computed: {
			...mapState({
				me: state => state.Chatuser.regloginUser,
				goodfriendapply: state => state.Chatuser.goodfriendapply,
			}),
			...
		},
		onLoad() {
			console.log('我的信息',this.me);
			console.log('好友申请',this.goodfriendapply);
			if(!this.me || this.me.role == 'visitor') return this.navigateBack();
		},
		methods: {
			opentopMenus(item,index){
				console.log('点击某一项',item);
			}
		}
	}
</script>
...

# 4. 新建查看好友申请列表页面

新建页面: /pages/applyMyfriend/applyMyfriend ,在 pages.json

{
	"path" : "pages/applyMyfriend/applyMyfriend",
	"style" : 
	{
		"navigationBarTitleText" : "新的朋友",
		"navigationStyle": "custom",
		"enablePullDownRefresh": true
	}
}

# 5. 从 /pages/friendsList/friendsList 朋友列表页面进入

methods: {
	opentopMenus(item,index){
		console.log('点击某一项',item);
		uni.navigateTo({
			url: item.url,
		});
	},
}

# 6. 查看好友申请列表页面代码

在页面 /pages/applyMyfriend/applyMyfriend代码

<template>
	<view>
		<!-- 导航栏 -->
		<chat-navbar title="新的朋友" :fixed="true" :showPlus="false" 
		:showUser="false" :showBack="true"
		navbarClass="bg-light" :h5WeiXinNeedNavbar="false">
		</chat-navbar>
		<!-- 新的朋友 -->
		<view class="p-3" v-if="goodfriendapply.alldata.length > 0">
			<u-cell-group title="申请加我为好友的用户" :border="false">
				<u-cell v-for="(item,index) in goodfriendapply.alldata"
				:key="index" :customStyle="{'height':'300px'}">
				    <view slot="title" class="flex align-center">
				       <u-avatar :src="item|avatarShow" shape="square"></u-avatar>
					   <!-- <u--image mode="widthFix"
					   :src="item|avatarShow"        
					   width="40px" height="40px" radius="10rpx"></u--image> -->
					   <view class="flex flex-column justify-center ml-2 mr-1">
						   <text class="font-md">{{item.user.nickname || item.user.username}}</text>
						   <text class="font-sm text-light-muted">{{item.nickname}}</text>
					   </view>
				    </view>
				    <view slot="value">
						<view v-if="item.status == 'pending'">
							<u-button text="同意" type="success" size="small"></u-button>
						</view>
						<view v-else>
							<text class="font-sm text-light-muted">{{item | statusText}}</text>
						</view>
					</view>
				</u-cell>
			</u-cell-group>
		</view>
		<view v-else>
			<u-empty></u-empty>
		</view>
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	import {requestUrl} from '@/common/mixins/configData.js';
	export default {
		mixins:[toolJs],
		data() {
			return {
				
			}
		},
		onLoad() {
			console.log('我的信息',this.me);
			console.log('好友申请信息',this.goodfriendapply);
			if(!this.me || this.me.role == 'visitor') return this.navigateBack();
		},
		computed: {
			...mapState({
				me : state => state.Chatuser.regloginUser,
				goodfriendapply : state => state.Chatuser.goodfriendapply,
			}),
		},
		filters:{
			//头像
			avatarShow(item){
				let avatar = item  &&  item.user.avatar;
				avatar = avatar && avatar.startsWith('http') ? avatar :
				 `${requestUrl.http}${avatar}`;
				return avatar;
			},
			// 状态显示
			statusText(item){
				let status = item  &&  item.status;
				let text = {
					agree:'已同意',
					refuse:'已拒绝',
					ignore:'已忽略'
				}
				return text[status];
			}
		},
		methods: {
			
		}
	}
</script>

<style>

</style>

# 7. 上拉刷新数据及下拉加载更多数据

  1. 在页面 /pages/applyMyfriend/applyMyfriend代码
<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 新的朋友 -->
		<view ...>
			<u-cell-group ...>
				<u-cell v-for="(item,index) in goodfriendapply.alldata"
				:key="index" :customStyle="{'height':'500px'}">
				    <view slot="title" class="flex align-center">
				       ...
				    </view>
				    <view slot="value">
						...
					</view>
				</u-cell>
			</u-cell-group>
			<!-- 上拉加载更多 --><!-- 正在加载中 --><!-- 没有更多数据了 -->
			<view>
				<!-- 上拉加载更多 -->
				<view v-if="!loadingIcon.show && moreData"
				class="flex align-center justify-center py-3">
					<text class="font-sm text-light-muted">上拉加载更多数据</text>
				</view>
				<!-- 正在加载中 -->
				<u-loading-icon :text="loadingIcon.text" :textSize="loadingIcon.textSize" 
				:mode="loadingIcon.mode" :show="loadingIcon.show"></u-loading-icon>
				<!-- 没有更多数据了 -->
				<view v-if="!loadingIcon.show && !moreData"
				class="w-100">
					<u-divider text="我是有底线的" textColor="#909399" lineColor="#dcdfe6"></u-divider>
				</view>
				
			</view>
		</view>
		<view v-else>
			<u-empty></u-empty>
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		data() {
			return {
				page:1,
				loadingIcon:{
					text:'数据加载中',
					textSize:12,
					mode:'circle',
					show:false,
				},
				moreData:true, // 是否可加载更多数据
			}
		},
		// 监听用户下拉
		onPullDownRefresh() {
			this.page = 1;
			this.$store.dispatch('getGoodfriendapply',{page:this.page,limit:10})
			.then(res=>{
				uni.stopPullDownRefresh();
				uni.showToast({
					title: '刷新数据成功',
					icon: 'none'
				});
			});
		},
		// 监听触底
		onReachBottom() {
			console.log('拉到底部了');
			this.loadMore();
		},
		methods: {
			//触底加载更多
			loadMore(){
				if(this.moreData){
					this.loadingIcon.show = true;
					const limit = 2;
					this.page ++;
					this.$store.dispatch('getGoodfriendapply',{page:this.page,limit:limit})
					.then(res=>{
						console.log('页面显示是否有下一页',this.goodfriendapply.moredata);
						this.moreData = this.goodfriendapply.moredata;
						console.log('看一下此时的加载状态', this.goodfriendapply.loadingStatus);
						this.loadingIcon.show = this.goodfriendapply.loadingStatus;
						if(!this.moreData){
							this.loadingIcon.show = false;
						}
					});
				}
			},
		}
	}
</script>
  1. 在vuex中 /store/modules/chatuser.js
import {requestUrl} from '@/common/mixins/configData.js';
export default {
	// 对应的mapState,在computed中引用导入
	// 类似于data,把全局或者公共部分放在这里
	state: {
		regloginUser: null, //注册登录后续的操作res结果存储
		//定义加我为好友的信息
		goodfriendapply:{
			alldata:[], // 所有申请我为好友的用户信息
			pendingCount:0, // 多少还未处理
		},
	},
	// 异步的方法,在methods引入
	actions: {
		//注册登录后续的操作
		...,
		// 用户退出登录
		...,
		// 初始化登录注册状态(避免刷新页面state没有数据)
		...,
		//获取好友申请的信息
		getGoodfriendapply({commit,state}, payload = {}) {
			if (state.regloginUser && state.regloginUser.role == 'user') {
				let page = payload.page ? payload.page : 1;
				let limit = payload.limit ? payload.limit : 2;
				// 正在请求中
				state.goodfriendapply.loadingStatus = true; 
				// 请求服务器
				uni.$u.http.get(requestUrl.http + `/api/chat/listapplyfriend/${page}?limit=${limit}`, {
					header: {
						token: uni.getStorageSync('chatuser_token'),
					}
				}).then(res => {
					console.log('服务器返回的好友申请结果', res);
					if(page == 1){
						// 得到数据赋值
						state.goodfriendapply = res.data.data;
						// 有没有下一页数据
						state.goodfriendapply.moredata = true;
						// 请求结束
						state.goodfriendapply.loadingStatus = false;
					}else{
						// 加载更多数据:往当前数据里面添加数据
						state.goodfriendapply.alldata = [...state.goodfriendapply.alldata,
						...res.data.data.alldata];
						console.log('加载更多数据得到的条数',state.goodfriendapply.alldata.length);
						console.log('如果有下一页应该有几条',page * limit);
						// 还有没有下一页
						const moredata = page * limit > state.goodfriendapply.alldata.length ?
						false : true;
						state.goodfriendapply.moredata = moredata;
						// 请求结束
						state.goodfriendapply.loadingStatus = false;
					}
				})
			}
		},
	},
}

# 十一、处理好友申请

# 1. 查看处理好友申请接口文档

搜索用户接口文档具体查看:七、处理好友的申请(对申请加我为好友的信息进行处理)

# 2. 从好友申请列表页面进入处理

/pages/applyMyfriend/applyMyfriend 好友申请列表页面

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 新的朋友 -->
		<view class="p-3" v-if="goodfriendapply.alldata.length > 0">
			<u-cell-group ...>
				<u-cell v-for="(item,index) in goodfriendapply.alldata"
				:key="index">
					<view slot="title" class="flex align-center"
					@click="openUserInfo(item,'info')">
						...
					</view>
					<view slot="value">
						<view v-if="item.status == 'pending'"
						@click="openUserInfo(item,'doapply')">
							...
						</view>
						<view v-else>
							...
						</view>
					</view>
				</u-cell>
			</u-cell-group>
			<!-- 上拉加载更多 --><!-- 正在加载中 --><!-- 没有更多数据了 -->
			<view>
				...
			</view>
		</view>
		<view v-else>
			<u-empty></u-empty>
		</view>
		
	</view>
</template>

<script>
	...
	export default {
		...,
		// 监听用户下拉
		onPullDownRefresh() {
			this.getNewData();
		},
		onShow() {
			this.getNewData();
		},
		methods: {
			//获取最新数据
			getNewData(){
				this.page = 1;
				const limit = 20;
				this.$store.dispatch('getGoodfriendapply',{ page:this.page, limit:limit }).then(res=>{
					uni.stopPullDownRefresh();
					// uni.showToast({title: '刷新数据成功',icon: 'none'});
				});
			},
			//触底加载下一页
			...,
			// 打开用户详情
			openUserInfo(item, action){
				uni.navigateTo({
					url: `/pages/userinfo/userinfo?uuid=${item.user.uuid}&action=${action}`,
				});
			},
		}
	}
</script>

# 3. 处理好友申请

/pages/userinfo/userinfo.vue 中处理

这里面涉及到一个接口:

  1. 查看用户是否申请加我为好友(登录用户有这个权限,游客无权限)
    文档地址:十七、查看用户是否申请加我为好友(即我有没有权限处理这个申请)
<template>
	<view class="page">
		<!-- 导航栏 -->
		...
		<!-- 介绍 -->
		...
		<!-- 处理 -->
		<view v-if="btn.clicktype == 'applyFriend'" 
		class="p-3 flex align-center">
			<u-textarea :placeholder="textarea.placeholder" v-model="textarea.nickname"
			count :adjustPosition="false" :height="70"></u-textarea>
		</view>
		<!-- 发消息 -->
		<view v-if="action.show == 'sendMessage'"
		class="p-3 flex align-center">
			<u-button :text="btn.text" :type="btn.type" @click="sendMessageFun"
			:loading="btn.loading" :loadingText="btn.loadingText"
			:loadingMode="btn.loadingMode" :disabled="btn.disabled"></u-button>
		</view>
		<!-- doapply的情况 -->
		<view v-if="action.show == 'doapply'"
		class="p-3">
			<!-- 用户留言 -->
			<view v-if="action.tips1"
			class="flex flex-column justify-center mb-3">
				<text class="mb-1">用户留言备注</text>
				<text class="font-sm text-light-muted" 
				style="text-align: justify;">{{action.tips1}}</text>
			</view>
			<!-- 备注用户名 -->
			<view class="mb-3 bg-white">
				<u-input placeholder="如果同意加为好友,可以备注一下用户名,选填" 
				v-model="action.tips1Value"></u-input>
			</view>
			<!-- 处理按钮 -->
			<view class="flex align-center">
				<view class="flex flex-1 mr-1">
					<u-button text="同意加为好友" type="success" size="small"
					@click="doApply('agree')"
					:loading="btn.loading" :loadingText="btn.loadingText"
					:loadingMode="btn.loadingMode" :disabled="btn.disabled"></u-button>
				</view>
				<view class="flex flex-1">
					<u-button text="拒绝" type="warning" size="small"
					@click="doApply('refuse')"
					:loading="btn.loading" :loadingText="btn.loadingText"
					:loadingMode="btn.loadingMode" :disabled="btn.disabled"></u-button>
				</view>
				<view class="flex flex-1 ml-1">
					<u-button text="忽略" type="primary" size="small"
					@click="doApply('ignore')"
					:loading="btn.loading" :loadingText="btn.loadingText"
					:loadingMode="btn.loadingMode" :disabled="btn.disabled"></u-button>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	...
	export default {
		mixins:[toolJs],
		data() {
			return {
				...,
				// 页面处理多样化
				action:{
					show:'sendMessage',
					//显示的内容1不限字段
					tips1:'',
					tips1Value:'',
				},
			}
		},
		onLoad(e) {
			if(!e.uuid) return this.navigateBack();
			this.uuid = e.uuid;
			this.getUserInfo();
			if(e.action && e.action == 'info') this.action.show = false;
			if(e.action && e.action == 'doapply'){
				// 处理好友申请必须是登录用户了
				if(!this.me || this.me.role == 'visitor') return this.navigateBack();
				this.action.show = 'doapply';
				// 看一下当前用户是不是申请加我为好友
				uni.$u.http.post(requestUrl.http + `/api/chat/isApplyfriend/${this.uuid}`,{},{
					header:{
						token: uni.getStorageSync('chatuser_token'),
					}
				}).then(res => {
					console.log('服务器返回的结果', res);
					const applyInfo = res.data.data;
					this.action.tips1 = applyInfo.nickname;
					this.action.applyInfo = applyInfo;
				}).catch(err => {
					return this.navigateBack();
				});
				
			}
		},
		methods: {
			// 处理申请
			doApply(type){
				this.btn.loading = true;
				this.btn.disabled = true;
				uni.$u.http.post(requestUrl.http + `/api/chat/handleapply/${this.action.applyInfo.id}`,{
					nickname:this.action.tips1Value,
					status:type,
				},{
					header:{
						token: uni.getStorageSync('chatuser_token'),
					}
				}).then(res => {
					this.btn.loading = false;
					console.log('服务器返回处理申请结果', res);
					if(res.data.data == 'ok'){
						uni.showToast({
							title: '处理成功',
							icon: 'none',
							duration: 1000
						});
						setTimeout(()=>{
							return this.navigateBack();
						},1000);
					}
				}).catch(err => {
					if (err.data && err.data.data) {
						uni.showToast({
							title: err.data.data,
							icon: 'none',
							duration: 5000
						});
					}
				});
			},
			...
		}
	}
</script>

# 十二、好友列表(通讯录)展示

# 1. 获取好友列表数据

获取好友列表数据文档接口: 八、好友列表(联系人、通讯录)

在vuex中获取,在 /store/modules/chatuser.js

import {requestUrl} from '@/common/mixins/configData.js';
export default {
	// 对应的mapState,在computed中引用导入
	// 类似于data,把全局或者公共部分放在这里
	state: {
		...
		// 我的好友列表
		goodfriendlist:[],
	},
	// 异步的方法,在methods引入
	actions: {
		...,
		//获取好友列表
		getGoodfriendlist({commit,state}, payload = {}){
			if (state.regloginUser && state.regloginUser.role == 'user') {
				let page = payload.page ? payload.page : 1;
				let limit = payload.limit ? payload.limit : 200;
				// 请求服务器
				uni.$u.http.get(requestUrl.http + `/api/chat/goodfriendlist/${page}?limit=${limit}`, {
					header: {
						token: uni.getStorageSync('chatuser_token'),
					}
				}).then(res => {
					console.log('服务器返回好友列表', res);
					state.goodfriendlist = res.data.data;
				});
			}
		}
	},
}

# 2. 页面展示

在页面 /pages/friendsList/friendsList.nvue 中代码

<template>
	<view>
		<!-- 导航栏 -->
		<chat-navbar title="好友列表" :fixed="true"
		:showPlus="false" :showUser="false"
		:showBack="true"></chat-navbar>
		
		<!-- 朋友列表 -->
		<u-index-list :indexList="indexList">
			<view slot="header" class="list">
				<view v-for="(item,index) in topMenus" :key="index"
				@click="opentopMenus(item,index)">
					<view class="flex align-center justify-between pr-3">
						<view class="list__item">
							<u-avatar shape="square" size="35" 
							:icon="item.icon" fontSize="26" randomBgColor></u-avatar>
							<text class="list__item__user-name">{{item.title}}</text>
						</view>
						<!-- 提示待处理的数量 -->
						<view class="flex align-center">
							<u-badge :max="99" :value="goodfriendapply.pendingCount"></u-badge>
						</view>
					</view>
					<u-line></u-line>
				</view>
			</view>
			<!-- 列表 -->
			<template v-for="(item, index) in itemArr">
				<!-- #ifdef APP-NVUE -->
				<u-index-anchor :text="indexList[index]" :key="index"></u-index-anchor>
				<!-- #endif -->
				<u-index-item :key="index">
					<!-- #ifndef APP-NVUE -->
					<u-index-anchor :text="indexList[index]"></u-index-anchor>
					<!-- #endif -->
					<view class="list" v-for="(item1, index1) in item" :key="index1">
						<view class="list__item" @click="openUserInfo(item1,'info')">
							<image class="list__item__avatar" :src="item1.url"></image>
							<text class="list__item__user-name">{{item1.name}}</text>
						</view>
						<u-line></u-line>
					</view>
				</u-index-item>
			</template>
			<view slot="footer" class="u-safe-area-inset--bottom"
			v-if="goodfriendlist && goodfriendlist.count">
				<text class="list__footer">共{{goodfriendlist && goodfriendlist.count}}位好友</text>
			</view>
		</u-index-list>
		
	</view>
</template>

<script>
	import toolJs from '@/common/mixins/tool.js';
	import {requestUrl} from '@/common/mixins/configData.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	/*
	const indexList = () => {
		const indexList = []
		const charCodeOfA = 'A'.charCodeAt(0)
		indexList.push("↑")
		indexList.push("☆")
		for (let i = 0; i < 26; i++) {
			indexList.push(String.fromCharCode(charCodeOfA + i))
		}
		console.log('indexList的当前值',indexList);
		indexList.push('#')
		return indexList
	}
	*/
	export default {
		mixins:[toolJs],
		data() {
			return {
				//indexList: indexList(),
				urls: [
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-01.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-02.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-03.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-04.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-05.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-06.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-07.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-08.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-09.png',
					'https://docs-51yrc-com.oss-cn-hangzhou.aliyuncs.com/chat/avatar-10.png',
				],
				names: ["晓明哥", "热巴", "GIGI梁咏琪", "古巨基", "古力娜扎", "阿祖",
									"力宏哥", "华仔", "黄奕", "刘涛", "林俊杰", "涛涛", 
									"阿力", "许文强", "周杰伦", "王心凌"
				],
				topMenus:[
					{icon:'man-add-fill', title:'新的朋友', url:'/pages/applyMyfriend/applyMyfriend'},
					// {icon:'tags-fill', title:'标签', url:''},
					// {icon:'chrome-circle-fill', title:'朋友圈', url:''},
					// {icon:'qq-fill', title:'QQ', url:''},
				],
			}
		},
		onLoad() {
			console.log('我的信息',this.me);
			console.log('好友申请信息',this.goodfriendapply);
			if(!this.me || this.me.role == 'visitor') return this.navigateBack();
			
			// 获取好友列表
			this.$store.dispatch('getGoodfriendlist');
		},
		computed: {
			...mapState({
				me : state => state.Chatuser.regloginUser,
				goodfriendapply : state => state.Chatuser.goodfriendapply,
				goodfriendlist : state => state.Chatuser.goodfriendlist,
			}),
			itemArr() {
				/*
				return this.indexList && this.indexList.map(item => {
					const arr = []
					for (let i = 0; i < 10; i++) {
						arr.push({
							name: this.names[uni.$u.random(0, this.names.length - 1)],
							url: this.urls[uni.$u.random(0, this.urls.length - 1)]
						})
					}
					return arr
				})
				*/
			    let newList = (this.goodfriendlist && this.goodfriendlist.rows) && 
				this.goodfriendlist.rows.newList;
				return newList && newList.map(item => {
					const arr = [];
					for (let i = 0; i < item.list.length; i++) {
						let avatar = item.list[i].avatar.startsWith('http') ?
						item.list[i].avatar : requestUrl.http + item.list[i].avatar;
						arr.push({
							name: item.list[i].name,
							url: avatar,
							uuid: item.list[i].uuid,
						});
					}
					return arr;
				});

			},
			// 数据库获取indexList
			indexList(){
				return (this.goodfriendlist && this.goodfriendlist.rows) && 
				this.goodfriendlist.rows.indexList;
			}
		},
		methods: {
			opentopMenus(item,index){
				console.log('点击了某一项',item);
				uni.navigateTo({
					url: item.url,
				});
			},
			openUserInfo(item1,action){
				uni.navigateTo({
					url: `/pages/userinfo/userinfo?uuid=${item1.uuid}`,
				});
			}
		}
	}
</script>

<style>
    /* #ifdef H5 */
	@import '/common/css/common.nvue.vue.css';
	/* #endif */
</style>
<style lang="scss">
	.list {
		
		&__item {
			@include flex;
			padding: 6px 12px;
			align-items: center;
			
			&__avatar {
				height: 35px;
				width: 35px;
				border-radius: 3px;
			}
			
			&__user-name {
				font-size: 16px;
				margin-left: 10px;
				color: $u-main-color;
			}
		}
		
		&__footer {
			color: $u-tips-color;
			font-size: 14px;
			text-align: center;
			margin: 15px 0;
		}
	}
</style>

# 十三、用户详情设置(当前主要开发的是聊天设置)

# 1. 新建设置详情页面 /pages/setpageInfo/setpageInfo.vue

/pages.json

{
	"path" : "pages/setpageInfo/setpageInfo",
	"style" : 
	{
		"navigationBarTitleText" : "详细设置",
		"navigationStyle": "custom"
	}
}

# 2. 从设置页进入

/pages/setpage/setpage.vue 代码

<template>
	<view>
		<!-- 导航栏 -->
		...
		<!-- 内容 -->
		<view >
			<!-- 聊天相关 -->
			<u-cell-group title="聊天相关" :border="false" 
			:customStyle="{'background-color':'#eeeeee'}">
				<u-cell title="聊天设置" 
				:customStyle="{'background-color':'#ffffff'}"
				isLink titleStyle="fontSize:18px;"
				@click="setfun('chatset','可以和我聊天的设置')"></u-cell>
			</u-cell-group>
			<!-- 退出 -->
			...
		</view>
	</view>
</template>

<script>
	...
	export default {
		...
		methods: {
			// 设置
			setfun(action,title){
				uni.navigateTo({
					url: `/pages/setpageInfo/setpageInfo?action=${action}&title=${encodeURIComponent(title)}`,
				});
			},
			...
		}
	}
</script>

# 3. 设置详情页面代码

用到两个接口:

  1. 用户设置更新, 具体看文档: 十八、用户设置更新
  2. 查看用户资料信息, 具体看文档: 十六、查看用户资料

在页面 /pages/setpageInfo/setpageInfo.vue

<template>
	<view>
		<!-- 导航栏 -->
		<chat-navbar :title="title"  :fixed="true" :showPlus="false" 
		:showUser="false" :showBack="true"
		navbarClass="navbar-bgColor" :h5WeiXinNeedNavbar="false">
		</chat-navbar>
		<!-- 内容 -->
		<view >
			<!-- 聊天相关 -->
			<view v-if="setdata.action == 'chatset'">
				<!-- 游客(未登录用户) -->
				<u-cell-group title="游客(未登录用户)" :border="false" 
				:customStyle="{'background-color':'#eeeeee'}">
					<u-cell 
					:customStyle="{'background-color':'#ffffff'}"
					v-if="setdata.visitor.list.length">
						<view slot="title"
						class="flex align-center border">
							<view class="flex justify-center py-2 flex-1"
							v-for="(item,index) in setdata.visitor.list" :key="index"
							:class="[setdata.visitor.current == index ?
							'bg-success text-white':'bg-light']"
							@click="setdata.visitor.current = index">
								<text style="font-size: 24rpx;">{{item.title}}</text>
							</view>
						</view>
					</u-cell>
				</u-cell-group>
				<!-- 登录用户(非好友) -->
				<u-cell-group title="登录用户(非好友)" :border="false" 
				:customStyle="{'background-color':'#eeeeee'}">
					<u-cell 
					:customStyle="{'background-color':'#ffffff'}"
					v-if="setdata.user.list.length">
						<view slot="title"
						class="flex align-center border">
							<view class="flex justify-center py-2 flex-1"
							v-for="(item,index) in setdata.user.list" :key="index"
							:class="[setdata.user.current == index ?
							'bg-success text-white':'bg-light']"
							@click="setdata.user.current = index">
								<text style="font-size: 24rpx;">{{item.title}}</text>
							</view>
						</view>
					</u-cell>
				</u-cell-group>
				<!-- 确定 -->
				<view class="p-3">
				   <u-button type="primary" text="确 定" @click="submitSet"
				   :loading="btn.loading" :loadingText="btn.loadingText"
				   :disabled="btn.disabled"></u-button>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import {requestUrl,visitorSalt} from '@/common/mixins/configData.js';
	import toolJs from '@/common/mixins/tool.js';
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';
	export default {
		mixins: [toolJs],
		data() {
			return {
				title:'',
				setdata:{
					visitor : {},
					user : {},
				},
				btn:{
					loading:false,
					loadingText:'正在提交中',
					disabled:false,
				}
			}
		},
		onLoad(e) {
			console.log(e);
			if(!e.action || !this.me || this.me.role == 'visitor') return this.navigateBack();
			if(e.title) {
				this.title = decodeURIComponent(e.title);
				uni.setNavigationBarTitle({
					title:this.title,
				});
			};
			//动态生成数据
			if(e.action){
				this.setdata.action = e.action;
				if(this.setdata.action == 'chatset'){
					this.setdata.visitor = {
						list:[
							{ title:'禁止聊天(先登录)', value:0 },
							{ title:'可向我发一条消息', value:1},
							{ title:'可以聊天', value:2 },
						],
						current: 1,
					};
					this.setdata.user = {
						list:[
							{ title:'禁止聊天(先加好友)', value:0 },
							{ title:'可向我发一条消息', value:1},
							{ title:'可以聊天', value:2 },
						],
						current: 1,
					};
					// 获取用户的设置信息
					uni.$u.http.get(requestUrl.http + `/api/userinfo/${this.me.uuid}`).then(res => {
						console.log('获取我的信息', res);
						let userset = res.data.data.userset;
						userset = userset && JSON.parse(userset);
						this.setdata.visitor.current = userset.chatset.visitor;
						this.setdata.user.current = userset.chatset.user;
					});
				}
			}
		},
		computed:{
			...mapState({
				me : state => state.Chatuser.regloginUser,
			}),
		},
		methods: {
			submitSet(){
				let userset = {};
				//聊天设置
				if(this.setdata.action == 'chatset'){
					const chatset = {
						visitor: this.setdata.visitor.list[this.setdata.visitor.current].value,
						user: this.setdata.user.list[this.setdata.user.current].value,
					}
					console.log('提交聊天设置:', chatset);
					userset.chatset = chatset;
				}
				console.log('提交给服务器',userset);
				this.btn.loading = true;
				this.btn.disabled = true;
				uni.$u.http.post(requestUrl.http + `/api/chat/userset`, {
					userset:JSON.stringify(userset),
				}, {
					header: {
						token: this.me.token,
					},
				}).then(res => {
					console.log('服务器返回的设置结果', res);
					this.btn.loading = false;
					if(res.data.data == 'ok'){
						uni.showToast({
							title: '设置成功',
							icon: 'none',
							duration: 1000
						});
						setTimeout(()=>{
							return this.navigateBack();
						},1000);
					}
				}).catch(err => {
					this.btn.loading = false;
					if (err.data && err.data.data) {
						uni.showToast({
							title: err.data.data,
							icon: 'none',
							duration: 5000
						});
					}
				});
			},
		}
	}
</script>

<style>

</style>

# 十四. 发消息前解决几个小问题

  1. 页面 /pages/setpageInfo/setpageInfo 在小程序标题过程不好看,调整 /pages/setpage/setpage.vue 页面方法:@click="setfun('chatset','和我聊天设置')" 标题;

# 1. 聊天设置信息提交数据完善

配合页面 /pages/userinfo/userinfo.vue 发消息的逻辑,我们需要调整:

① 页面 /pages/setpageInfo/setpageInfo.vue 提交服务器的设置信息,如果登录用户还需增加一个条件才能和我聊天,如:需要关注才能发消息,因此我们提交数据的构造应该调整一下:

onLoad(e) {
	...
	// 动态生成数据
	if(e.action){
		this.setdata.action = e.action;
		if(this.setdata.action == 'chatset'){
			...
			// 获取用户的设置信息
			uni.$u.http.get(requestUrl.http + `/api/userinfo/${this.me.uuid}`).then(res => {
				...
				if(userset){
					...
					this.setdata.visitor.current = userset.chatset.visitor.sendCount;
					this.setdata.user.current = userset.chatset.user.sendCount;
				}
			})
		}
	}
},
methods: {
	submitSet(){
		let userset = {};
		// 聊天设置
		if(this.setdata.action == 'chatset'){
			const chatset = {
				visitor: {
					sendCount:this.setdata.visitor.list[this.setdata.visitor.current].value,
					needFollow:false,
				},
				user: {
					sendCount:this.setdata.user.list[this.setdata.user.current].value,
					needFollow:false,
				},
			}
			userset.chatset = chatset;
		}
		console.log('提交给服务器的设置数据',userset);
		...
	}
}

# 2. 发消息按钮的两种情况判断

  1. 从搜索页搜索用户进入,此时点击发消息,存在这个用户是否是你的好友的判断,如果不是好友,则按照用户的聊天设置进行处理;
  2. 从好友列表(通讯录)点击头像进入,此时已经是你的好友了,则直接进行聊天(除非将你拉黑了[拉黑功能后面再实现]);

    基于以上情况,在点击发消息前,我们需要:
  1. 查询一下对方是否是我的好友
  2. 根据是否是好友的情况进行处理
  3. 很多用户没有进行聊天设置,字段 userset 是空值,针对空值的情况的处理

# ① 查询一下对方是否是我的好友

# 1. 接口说明

具体查看接口说明: 十九、查询一下对方是否是我的好友

# 2. 处理发消息的逻辑

在页面 /pages/userinfo/userinfo.vue 代码

<template>
	<view class="page">
		...
	</view>
</template>

<script>
	...
	export default {
		...
		methods: {
			...,
			// 获取用户信息
			getUserInfo(){
				uni.$u.http.get(requestUrl.http + `/api/userinfo/${this.uuid}`).then(res => {
					console.log('获取用户信息结果', res);
					...
					// 是不是我的好友
					this.ismygoodfriend();
				}).catch(err => {
					...
				});
			},
			// 是不是我的好友
			ismygoodfriend(){
				uni.$u.http.post(requestUrl.http + `/api/chat/ismygoodfriend/${this.user.id}`,{},{
				    header:{
					  token:uni.getStorageSync('chatuser_token'),
				    }
				}).then(res => {
					console.log('是否是我的好友结果',res);
					if(res.data.data == 'goodfriend') this.me.ismygoodfriend = true;
				}).catch(err => {
					// 不是好友
					this.me.ismygoodfriend = false;
				});
			},
			// 发消息
			sendMessageFun(){
				console.log('发消息的逻辑',this.me);
				if(this.me.ismygoodfriend){
					console.log('是好友,可以直接聊天了');
				}else{
					const role = this.me.role; //'visitor' | 'user'
					// const { sendCount, needFollow } = this.user.chatset[role];
					let userset = this.user.userset;
					if(!userset){
						// 用户没有聊天设置之前
						userset = {
							chatset:{
								visitor: {
									sendCount:1, // 发一条
									needFollow:false, // 不需要关注
								},
								user: {
									sendCount:1,
									needFollow:false,
								},
							}
						}
					}else{
						userset = JSON.parse(userset);
					}
					const { sendCount, needFollow } = userset.chatset[role];
					// 1. 检查是否需要关注
					// if(needFollow && this.me.hasFollowed){
					// 	console.log('请先关注对方才能发消息');
					// 	return; // 程序结束
					// }
					// 2. 根据对方设置的聊天权限处理
					...
				}
			},
		}
	}
</script>

# 3. 处理完用户申请返回好友列表(通讯录)更新好友列表

在页面 /pages/friendsList/friendsList.nvue

onShow() {
	//获取好友列表
	this.$store.dispatch('getGoodfriendlist');
},
更新时间: 2025年7月29日星期二上午11点00分