心链 — 伙伴匹配系统
直接取出所有用户,依次和当前用户计算分数,取 TOP N(54 秒)
优化方法:
- 切忌不要在数据量大的时候循环输出日志(取消掉日志后 20 秒)
- Map 存了所有的分数信息,占用内存
解决:维护一个固定长度的有序集合(sortedSet),只保留分数最高的几个用户(时间换空间)
e.g.【3, 4, 5, 6, 7】取 TOP 5,id 为 1 的用户就不用放进去了- 细节:剔除自己 √
- 尽量只查需要的数据:
- 过滤掉标签为空的用户 √
- 根据部分标签取用户(前提是能区分出来哪个标签比较重要)
- 只查需要的数据(比如 id 和 tags) √(7.0s)
- 提前查?(定时任务)
- 提前把所有用户给缓存(不适用于经常更新的数据)
- 提前运算出来结果,缓存(针对一些重点用户,提前缓存)
前端
一、主页切换功能
在vant组件库里寻找switch开关,复制到主页index里面
定义一个开关切换常量,默认为关闭
我们现在不需要一次性挂载,写一个加载的方法,并且写一个监听器(当开关切换时,“更换页面”)
/**
* 加载数据
*/const loadData = async () => {let userListData;// 心动模式,根据标签匹配用户if (isMatchMode.value) {const num = 10;userListData = await myAxios.get('/user/match', {params: {num,},}).then(function (response) {console.log('/user/match succeed', response);return response?.data;}).catch(function (error) {console.error('/user/match error', error);Toast.fail('请求失败');})} else {// 普通模式,直接分页查询用户userListData = await myAxios.get('/user/recommend', {params: {pageSize: 8,pageNum: 1,},}).then(function (response) {console.log('/user/recommend succeed', response);return response?.data?.records;}).catch(function (error) {console.error('/user/recommend error', error);Toast.fail('请求失败');})}if (userListData) {userListData.forEach((user: UserType) => {if (user.tags) {user.tags = JSON.parse(user.tags);}})userList.value = userListData;}}watchEffect(() => {loadData();})
PS:别忘了
,否则运行报错 但是添加之后user.tage会爆红,可以将UserType里的tags类型从数组改为字符串形式(这里爆红也能运行,所以就不更改了)
运行,页面显示如下 点击开关
中间加载的时间较长,这是正常现象
二、todo
1.加载loading特效
我们使用骨架屏特效
把它放在UserListCard里面(包裹内容)
别忘了在js里添加这两个参数
到index的user-card-list里引用
同时别忘了引入loading常量,并在loadData方法里,在开始和结尾处分别使loading设置为true和false
2.仅加入队伍和创建队伍的人能看到队伍操作按钮
队伍操作权限控制加入队伍: 仅非队伍创建人、且未加入队伍的人可见 更新队伍:仅创建人可见 解散队伍:仅创建人可见 退出队伍:创建人不可见,仅已加入队伍的人可见
仅加入队伍和创建队伍的人能看到队伍操作按钮(listTeam 接口要能获取我加入的队伍状态) 方案 1:前端查询我加入了哪些队伍列表,然后判断每个队伍 id 是否在列表中(前端要多发一次请求) 方案 2:在后端去做上述事情(推荐) 这里我们选择方案2
1.首先为TeamUserVO太那几是否已加入队伍的字段
2.修改listTeam的接口,加入是否已经加入队伍的判断
@GetMapping("/list")public BaseResponse<List<TeamUserVO>> listTeams(TeamQuery teamQuery, HttpServletRequest request) {if (teamQuery == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}boolean isAdmin = userService.isAdmin(request);// 1、查询队伍列表List<TeamUserVO> teamList = teamService.listTeams(teamQuery, isAdmin);final List<Long> teamIdList = teamList.stream().map(TeamUserVO::getId).collect(Collectors.toList());// 2、判断当前用户是否已加入队伍QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();try {User loginUser = userService.getLoginUser(request);userTeamQueryWrapper.eq("userId", loginUser.getId());userTeamQueryWrapper.in("teamId", teamIdList);List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);// 已加入的队伍 id 集合Set<Long> hasJoinTeamIdSet = userTeamList.stream().map(UserTeam::getTeamId).collect(Collectors.toSet());teamList.forEach(team -> {boolean hasJoin = hasJoinTeamIdSet.contains(team.getId());team.setHasJoin(hasJoin);});} catch (Exception e) {}return ResultUtils.success(teamList);}
3.修改前端页面的user-card-list里4个按钮出现的判断条件
<van-button size="small" type="primary" v-if="team.userId !== currentUser?.id && !team.hasJoin" plain@click="preJoinTeam(team)">加入队伍</van-button><van-button v-if="team.userId === currentUser?.id" size="small" plain@click="doUpdateTeam(team.id)">更新队伍</van-button><!-- 仅加入队伍可见 --><van-button v-if="team.userId !== currentUser?.id && team.hasJoin" size="small" plain@click="doQuitTeam(team.id)">退出队伍</van-button><van-button v-if="team.userId === currentUser?.id" size="small" type="danger" plain@click="doDeleteTeam(team.id)">解散队伍</van-button>
4.测试
我的数据库里有14队伍和24队伍,其中4是24的创建者,550007是14的创建者,同时4也是14的队员 ps:(写完后端千万别忘了重启)
对照要求,看看是否符合 (√)
5.前端导航栏死【标题】问题
解决:使用 router.beforeEach,根据要跳转页面的 url 路径 匹配 config/routes 配置的 title 字段 1.配置路由里的title字段
在BasicLayout里增加根据路由切换标题
同时把原来用于测试的Toast响应(请求成功)删除,全局搜索删除
别忘了,把这句也删除
刷新,切换到不同页面,测试标签栏是否更换,以及请求成功是否不再出现