当前位置: 首页 > news >正文

柚见十三期(优化)

前端优化

加载匹配功能与加载骨架特效

骨架屏 : 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:在后端去做上述事情(推荐)

加密队伍与公开队伍的展示

前端修改

Tab 标签页 - Vant 4 (gitee.io)

<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;

相关文章:

柚见十三期(优化)

前端优化 加载匹配功能与加载骨架特效 骨架屏 : vant-skeleton index.vue中 /** * 加载数据 */ const loadData async () > { let userListData; loading.value true; //心动模式 if (isMatchMode.value){ const num 10;//推荐人数 userListData await myA…...

Node.js常用命令:了解Node.js的核心命令和用法

学习目标&#xff1a; 理解Node.js和npm的概念及其在开发中的作用&#xff1b;掌握Node.js的核心命令&#xff0c;包括node、npm、npx等&#xff1b;学会使用node命令来执行JavaScript文件和模块&#xff1b;熟悉npm命令&#xff0c;包括安装、更新、卸载依赖包等操作&#xf…...

QT 驾校系统界面布局编写

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->resize(ui->label_img->width(),ui->label_img->height());//图片自适应窗口大小ui->label_img->setScaledContents(true);//图片置…...

【Auth Proxy】为你的 Web 服务上把锁

Auth Proxy 一个极简的用于 Web 服务鉴权的反向代理服务 极其简约的 UI对你的真实服务无任何侵入性支持容器部署&#xff0c;Docker Image 优化到不能再小&#xff08;不到 9MB&#xff09;GitHub&#xff1a;https://github.com/wengchaoxi/auth-proxy 效果 我在 http://lo…...

Docker 从0安装 nacos集群

前提条件 Docker支持一下的CentOs版本 Centos7(64-bit)&#xff0c;系统内核版本为 3.10 以上Centos6.5(64-bit) 或者更高版本&#xff0c;系统内核版本为 2.6.32-431 或者更高版本 安装步骤 使用 yum 安装&#xff08;CentOS 7下&#xff09; 通过 uname -r 命令查看你当…...

keithley2612A数字源表

181/2461/8938产品概述&#xff1a; Keithley 2612A源表既可用作台式I-V表征工具&#xff0c;也可用作多通道I-V测试系统的构建模块组件。对于台式使用&#xff0c;吉时利2612ASourceMeter具有嵌入式TSP Express软件工具&#xff0c;允许用户快速轻松地执行常见的I-V测试&…...

AI助手 - 月之暗面 Kimi.ai

前言 这是 AI工具专栏 下的第四篇&#xff0c;这一篇所介绍的AI&#xff0c;也许是截至今天&#xff08;204-03-19&#xff09;国内可访问的实用性最强的一款。 今年年初&#xff0c;一直看到有人推荐 Kimi&#xff0c;不过面对雨后春笋般的各类品质的AI&#xff0c;说实话也有…...

《计算机考研精炼1000题》为你考研之路保驾护航

创作背景 在这个充满挑战与竞争的时代&#xff0c;每一位考生在备战研究生考试的过程中&#xff0c;都希望通过更多符合考纲要求的练习题来提高自己的知识和技能。为了满足这一需求&#xff0c;我们精心策划和编辑了这本《计算机考研精炼1000题》。在考研政治和考研数学领域&a…...

el-input添加keyup事件无响应

<el-input type"password" v-model"formData.password" keyup.enter"onSubmit"></el-input>使用 .native修饰符 有时&#xff0c;Vue 组件内部可能会处理某些事件&#xff0c;导致你不能直接在组件上监听这些事件。 在这种情况下&am…...

错误1075:依存服务不存在, 或已标记为删除的解决方法

错误1075&#xff1a;依存服务不存在&#xff0c; 或已标记为删除的解决方法 运行 sc config spooler depend rpcss 注意"depend “而不是"depend”。...

【Python】使用selenium对Poe批量模拟注册脚本

配置好接码api即可实现自动化注册登录试用一体。 运行后会注册账号并绑定邮箱与手机号进行登录试用。 测试结果30秒一个号 import re import time import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.options imp…...

【Linux】编译器-gcc/g++的使用(预处理、编译、汇编、连接)

目录 01.预处理&#xff08;宏替换&#xff09; 02.编译&#xff08;生成汇编&#xff09; 03.汇编&#xff08;生成机器可识别码&#xff09; 04.连接&#xff08;生成可执行文件或库文件&#xff09; 05.选项 编译器在编译代码时包含以下四个步骤&#xff1a;1.预处理 2…...

【Linux】Linux安装软件---软件包管理器 yum

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;Linux_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.Linux中安装软件 1.1 源代码安装 1.2 rpm包安装 1.3 yum安装 1.3.1 举例 1.3.2 图示yum下载安装 2.Linux系统的生态 如何选…...

QT网络编程之获取本机网络信息

一.概述 查询一个主机的MAC地址或者IP地址是网络应用中常用到的功能&#xff0c;Qt提供了QHostInfo和QNetworkInterface 类可以用于此类信息的查询 1.QHostInfo 类&#xff08;显示和查找本地的信息&#xff09; 2.QNetworkInterface 类&#xff08;获得应用程序上所在主机的…...

离线安装docker、docker-compose、Mysql镜像

离线安装docker docker-compose mysql镜像 一、下载docker docker-compose mysql 镜像文件 1、首先下载docker镜像 博主所用文件版本号&#xff1a; docker-23.0.6.tgz 下载docker 地址 &#xff1a;https://blog.csdn.net/xiaohanshasha/article/details/135489623?spm1001…...

Redis系列学习文章分享---第九篇(Redis快速入门之好友关注--关注和取关 -共同关注 -Feed流实现方案分析 -推送到粉丝收件箱 -滚动分页查询)

Redis的实战篇-好友关注 目录 好友关注-关注和取关好友关注-共同关注好友关注-Feed流实现方案分析好友关注-推送到粉丝收件箱好友关注-滚动分页查询收件箱的思路好友关注-实现滚动分页查询 1. 好友关注-关注和取关 1.1 概述 在好友关注系统中&#xff0c;用户可以关注其他用…...

数据库基本介绍及编译安装mysql

目录 数据库介绍 数据库类型 数据库管理系统&#xff08;DBMS&#xff09; 数据库系统 DBMS的工作模式 关系型数据库的优缺点 编译安装mysql 数据库介绍 数据&#xff1a;描述事物的的符号纪录称为数据&#xff08;Data&#xff09; 表&#xff1a;以行和列的形式组成…...

代码随想录算法训练营第55天 | 583. 两个字符串的删除操作, 72. 编辑距离

动态规划章节理论基础&#xff1a; https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 583. 两个字符串的删除操作 题目链接&#xff1a;https://leetcode.cn/problems/delete-operation-for-two-strings/descrip…...

Guava之EventBus源码分析

简介 事件总线。 有助于深入理解代码的功能和实现细节。 可以了解代码背后的逻辑、算法、数据结构和设计模式等方面&#xff0c;从而更好地理解代码的作用和功能。 可以学习到业界的最佳实践和设计模式。 这有助于提高自己的编程水平&#xff0c;使你能够编写更高质量、可…...

Spark on Yarn安装配置

目录 前言 初了解spark Standalone模式 Yarn模式 前言 今天我们讲解Spark的安装配置&#xff0c;spark的部署分为两种&#xff0c;一种是Standalone模式&#xff0c;另一种就是on yarn 模式&#xff0c;我们这一节着重讲解on yarn 模式&#xff0c;因为符合生产活动&#…...

hehehe

...

LightOnOCR-2-1B与VSCode开发环境配置指南

LightOnOCR-2-1B与VSCode开发环境配置指南 1. 开发环境准备 在开始使用LightOnOCR-2-1B进行文档识别开发之前&#xff0c;我们需要先配置一个高效的VSCode开发环境。这个模型是一个10亿参数的端到端视觉语言模型&#xff0c;专门用于将PDF、扫描件和图像转换为结构化的文本内…...

MSP/PSP

定义MSP 是 Main Stack Pointer&#xff0c;中文通常叫&#xff1a;主栈指针或者 主栈在 Cortex-M 内核里&#xff0c;CPU 有 两个栈指针&#xff1a;MSP&#xff1a;Main Stack PointerPSP&#xff1a;Process Stack Pointer直观理解你可以把它理解成&#xff1a;PSP&#xff…...

从浏览器到服务器:图解HttpServletResponse如何操控文件流(原理+实践)

HTTP文件流传输的底层机制与高效实践 当你在浏览器中点击一个下载链接时&#xff0c;看似简单的操作背后隐藏着一系列精妙的协议交互和数据流动过程。作为开发者&#xff0c;理解HttpServletResponse如何操控文件流不仅能够优化文件传输性能&#xff0c;还能解决实际开发中的各…...

扫频正弦啁啾信号在音频测量中的优势与应用

1. 扫频正弦啁啾信号在音频测量中的核心价值作为一名从事音频测量工作多年的工程师&#xff0c;我深刻理解精确测量音频设备频率响应和脉冲响应的重要性。在众多测试信号中&#xff0c;扫频正弦啁啾信号&#xff08;Swept Sine Chirps&#xff09;因其独特的优势已成为行业标准…...

(claude code)最强skill everything-claude-code 技能完整指南

everything-claude-code 技能完整指南 本文档介绍 everything-claude-code 插件提供的所有技能&#xff08;skills&#xff09;及其用途。 一、核心开发流程 技能用途plan创建实施计划 - 新功能开发前先规划&#xff0c;分阶段拆解任务tdd测试驱动开发 - 先写测试再实现代码&…...

Anthropic新品频发致传统软件股暴跌,AI与SaaS融合能否成未来趋势?

Anthropic新品频发引发行业震荡&#xff1a;传统软件股暴跌&#xff0c;AI与SaaS融合成未来趋势&#xff1f;又一家明星公司&#xff0c;被Anthropic无情“斩杀”。4月18日&#xff0c;Anthropic发布新产品Claude Design。用户能通过它创建网页或App设计方案&#xff0c;涵盖交…...

别再乱改Serial参数了!深入解读ArduPilot地面站里Serial1到Serial7每个串口的预设功能

深入解析ArduPilot串口配置&#xff1a;从Serial1到Serial7的功能定位与避坑指南 当你第一次打开ArduPilot地面站的"全部参数表"&#xff0c;看到Serial1到Serial7那一排神秘的参数时&#xff0c;是否感到困惑&#xff1f;特别是当某个串口显示为-1时&#xff0c;你是…...

从理论到实践:深入解析AGPCNet在红外小目标检测中的核心模块与代码实现

1. 红外小目标检测的挑战与AGPCNet的创新价值 红外小目标检测在军事侦察、安防监控等领域具有重要应用&#xff0c;但传统方法面临三大核心难题&#xff1a;首先是目标尺寸过小&#xff08;通常仅占图像的33到99像素&#xff09;&#xff0c;在复杂背景中容易漏检&#xff1b;其…...

MTK Camera调试实战:Dump Buffer定位花屏与竖线问题

1. 初识MTK Camera Dump Buffer调试技巧 第一次遇到手机摄像头预览画面出现彩色条纹时&#xff0c;我盯着屏幕愣了半天。作为刚入行的Camera调试工程师&#xff0c;这种花屏问题简直就像天书。直到同事教我用了MTK平台的Dump Buffer功能&#xff0c;才发现原来这些看似复杂的图…...