赞
踩
骨架屏 : vant-skeleton
index.vue中
/** * 加载数据 */ const loadData = async () => { let userListData; loading.value = true; //心动模式 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.log('/user/match error',error); showFailToast('请求失败'); }); } else { //不开启推荐模式,默认全部查询 //普通用户使用分页查询todo 并没有实现 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.log('/user/recommends error',error); showFailToast('请求失败'); }); } if (userListData){ userListData.forEach((user: userType) =>{ if (user.tags){ user.tags = JSON.parse(user.tags); } }) userList.value = userListData; } loading.value = false; } //`watchEffect`函数用于在响应式数据发生变化时执行副作用(side effect)操作。在这个例子中,当数据发生变化时,会调用`loadData()`函数来加载数据。 watchEffect(() =>{ loadData(); })
router :控制路由跳转
route: 获取路由信息
解决:使用 router.beforeEach,根据要跳转页面的 url 路径 匹配 config/routes 配置的 title 字段
//标题
const DEFAULT_TITLE='柚见'
const title=ref(DEFAULT_TITLE);
/**
* 根据路由切换标题
*/
router.beforeEach((to,from)=>{
const toPath=to.path;
const route=routes.find((r)=>{
return toPath==r.path;
})
title.value=route.title ?? DEFAULT_TITLE;
})
根据后端返回的未登录的错误码,重定向
全局响应拦截器中修改
发现页面一直不能正常跳转
切换hash模式
不同的历史模式 | Vue Router (vuejs.org)
登录成功后自动跳转回之前页面
添加样式
引入样式
换成vant库中的+
<!-- 创建队伍按钮-->
<van-button type="primary" @click="doJoinTeam" class="add-button" icon="plus">
</van-button>
更新队伍:仅创建人可见
v-if="team.userId === currentUser?.id"
解散队伍:仅创建人可见
v-if="team.userId === currentUser?.id"
加入队伍: 仅非队伍创建人、且未加入队伍的人可见
退出队伍:创建人不可见,仅已加入队伍的人可见
后端修改
仅加入队伍和创建队伍的人能看到队伍操作按钮(listTeam 接口要能获取我加入的队伍状态) ✔
方案 1:前端查询我加入了哪些队伍列表,然后判断每个队伍 id 是否在列表中(前端要多发一次请求)
方案 2:在后端去做上述事情(推荐)
前端修改
<van-tabs v-model:active="activeName">
<van-tab title="公开队伍" name="public"></van-tab>
<van-tab title="加密队伍" name="secret"></van-tab>
</van-tabs>
const onTabChange=(name)=>{
if(name==='public')
{
//查询公开队伍
listTeam()
}else if(name === 'secret'){
//查询加密队伍
listTeam(' ',2);
}
console.log(name)
}
//只有管理员和本人才能查看非私有的房间
if (!isManager && !statusEnum.equals(TeamStatusEnum.PUBLIC) && !statusEnum.equals(TeamStatusEnum.SECRET)) {
throw new BusinessException(ErrorCode.NO_AUTH);
}
<script setup lang="ts"> import {TeamType} from "../models/team"; import {teamStatusEnum} from "../constants/team.ts"; import myAxios from "../plungins/myAxios.js"; import {showFailToast, showSuccessToast} from "vant"; import {onMounted, ref} from "vue"; import {getCurrentUser} from "../services/user.ts"; import {useRouter} from "vue-router"; const router=useRouter(); const password=ref(''); //加入该队伍的id const joinId=ref(0) const showPwd=ref(false) interface TeamCardListProps{ teamList: TeamType[]; } const props= withDefaults(defineProps<TeamCardListProps>(),{ //@ts-ignore teamList: [] as TeamType[] }); //获得当前用户 const currentUser=ref() onMounted(async ()=>{ const res=await getCurrentUser() currentUser.value=res }) //加入队伍之前--------------------------------------------------------------------- const preJoinTeam=(team : TeamType)=>{ joinId.value=team.id; if(team.status === 2) { //打开加密弹窗 showPwd.value=true; } else if(team.status === 0) { doJoinTeam(); } } const doJoinCancel = () => { joinId.value = 0; password.value = ''; } //点击公开队伍,加入队伍------------------------------------------------------------ const doJoinTeam=async()=>{ if(!joinId.value) { return ; } const res=await myAxios.post('/team/join',{ teamId:joinId.value, password:password.value }) if(res?.code===0){ showSuccessToast("加入成功") doJoinCancel(); }else{ showFailToast("加入失败\n"+(res.description ? `${res.description}`: '')) } } //跳转到更新页--------------------------------------------------------------------- const doUpdateTeam=({id}: { id: any })=>{ router.push({ path:'/team/update', query:{ id } }) } //点击退出队伍------------------------------------------------------------------- const doQuitTeam=async (id)=>{ const res=await myAxios.post('/team/quit',{ teamId:id }) if(res?.code===0){ showSuccessToast("操作成功") }else{ showFailToast("操作失败\n"+(res.description ? `${res.description}`: '')) } } //点击解散队伍------------------------------------------------------------------------- const doDeleteTeam=async ({id}: { id: any })=>{ const res=await myAxios.post('/team/delete',{ id }) if(res?.code===0){ showSuccessToast("操作成功") }else{ showFailToast("操作失败\n"+(res.description ? `${res.description}`: '')) } } </script>
<div>
{{ `已加入人数 : ${team.hasJoinNum} / ` + team.maxNum }}
</div>
@GetMapping("/list") public BaseResponse<List<TeamUserVO>> listTeams(TeamQuery teamQuery,HttpServletRequest request) { if (teamQuery == null) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } boolean isManager = userService.isManager(request); User loginUser = userService.getLoginUser(request); // 1、查询队伍列表 List<TeamUserVO> teamList = teamService.listTeams(teamQuery, isManager); final List<Integer> teamIdList = teamList.stream().map(TeamUserVO::getId).collect(Collectors.toList()); // 2、判断当前用户是否已加入队伍 QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>(); try { userTeamQueryWrapper.eq("userId", loginUser.getId()); userTeamQueryWrapper.in("teamId", teamIdList); List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper); // 已加入的队伍 id 集合 Set<Integer> 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.查询已加入队伍数
QueryWrapper<UserTeam> userTeamQueryWrapper2 = new QueryWrapper<>();
userTeamQueryWrapper.in("teamId", teamIdList);
List<UserTeam> userTeamList2 = userTeamService.list(userTeamQueryWrapper2);
//队伍id => userId集合
Map<Integer, List<UserTeam>> teamIdUserTeamList = userTeamList2.stream().collect(Collectors.groupingBy(UserTeam::getTeamId));
teamList.forEach(team ->
team.setHasJoinNum(teamIdUserTeamList.getOrDefault(team.getId(), new ArrayList<>()).size())
);
只要我们点的足够快,就可以在同一时间内往数据库插入多条同样的数据,所以这里我们使用分布式锁(推荐)使用两把锁,一把锁锁队伍,一把锁锁用户(实现较难,不推荐)
之前的代码
//该用户已加入的队伍数量不能超过5个 int userId = loginUser.getId(); // 只有一个线程能获取到锁 RLock lock = redissonClient.getLock("youjian:join_team"); QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>(); userTeamQueryWrapper.eq("userId",userId); int hasJoinNum = (int) userTeamService.count(userTeamQueryWrapper); if (hasJoinNum >= 5){ throw new BusinessException(ErrorCode.PARAMS_ERROR,"最多创建和加入5个队伍"); } //不能重复加入已加入的队伍 userTeamQueryWrapper = new QueryWrapper<>(); userTeamQueryWrapper.eq("userId",userId); userTeamQueryWrapper.eq("teamId",teamId); int hasUserJoinTeam = (int) userTeamService.count(userTeamQueryWrapper); if (hasUserJoinTeam > 0){ throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户已加入该队伍"); } //不能加入已满队伍 userTeamQueryWrapper = new QueryWrapper<>(); userTeamQueryWrapper.eq("teamId",teamId); int teamHasJoinNum = (int) userTeamService.count(userTeamQueryWrapper); if (teamHasJoinNum >= team.getMaxNum()){ throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已满"); } //3.加入,修改队伍信息 UserTeam userTeam = new UserTeam(); userTeam.setUserId(userId); userTeam.setTeamId(teamId); userTeam.setJoinTime(new Date()); return userTeamService.save(userTeam);
修改后
@Resource
private RedissonClient redissonClient;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。