丰农汇——CodeArts团队实战总结
丰农汇——CodeArts团队实战总结
| 这个作业属于哪个课程 | FZU_SE_teacherW_4 |
|---|---|
| 这个作业要求在哪里 | 软工实践——CodeArts团队实战总结 |
| 团队名称 | 丰农汇 |
| 这个作业的目标 | 开发一个奥运比赛竞猜平台,实现GUI以及基础,附加功能 |
| 其他参考文献 | 构建之法 |
目录
- 丰农汇——CodeArts团队实战总结
- 1 项目地址
- 2 CodeArt 提交日志
- 3 程序运行环境
- 3.1 前端部署
- 3.2 后端部署
- 4 需求分析
- 4.1 NABCD模型
- 4.2 功能描述
- 4.2.1 用户登录界面
- 4.2.2 用户基本信息
- 4.2.2 竞猜功能
- 4.3 数据库设计
- 5 功能实现思路
- 5.1 技术栈
- 5.1.1 前端技术栈
- 5.1.2 后端技术栈
- 5.2 接口设计
- 5.3 测试方案
- 5.4 思考问题与解答
- 5.4.1 用户如何快速知道有竞猜功能并参与竞猜?
- 5.4.2 如何告知用户竞猜结果?
- 5.4.3 如何保证一人一号?
- 6 运行截图说明
- 6.1 登录注册
- 6.2 客户端
- 7 分工和贡献度说明
- 8 困难与解决方法
- 9 PSP表格
1 项目地址
截图信息(部分)
次数统计
学号 提交次数 222200302 5 222200301 6 222200303 4 222200426 7 222200417 4 222100110 4 222200427 5 222200332 3
3 程序运行环境
3.1 前端部署
我们的前端项目使用
Vue.js+Vite开发,最后使用Vite打包构建Vite构建项目命令
pnpm vite build构建好项目之后再把项目放到云服务上的
Nginx服务器中我们的前端项目最后部署在 http://8.130.92.86/
3.2 后端部署
- 首先在云服务器上安装好Mysql,并且开放3306端口
- 在SpringBoot项目中连接到云服务器上的Mysql数据库
- 把SpringBoot项目打成jar包
- 再把jar包部署到云服务器上
- 云服务上的jdk版本为jdk1.8
4 需求分析
4.1 NABCD模型
N(Need,需求)
体育迷对于参与奥运赛事的热情和兴趣日益增长,他们渴望能够通过一种互动性强、趣味性高的方式参与到奥运会中。用户需要一个平台,可以让他们预测比赛结果,增加观看比赛的参与感和紧张感。
A(Approach,做法)
开发一个在线竞猜平台,用户可以在上面选择不同的比赛进行预测和下注。
协同使用CodeArts进行团队开发。
前端使用ES6,Vue 3,Pinia,Vite,Axios,Element-Plus
后端使用Springboot、MybatisPlus、MySQL、Redis
B (Benefit,好处)
用户可以通过竞猜平台增加观看比赛的乐趣,提高参与度和兴奋感。
平台无需下载,占用内存空间小,运行速度快。
页面简洁,操作简单,对于初次接触的用户十分友好。
C (Competitors,竞争)
我们的主要竞争对手为其他小组的项目。
我方优势
模块清晰,操作简单,界面美观,用户体验好。
无需下载安装,使用方便。
我方劣势
数据主要从官方网站爬取,可能存在数据较少等问题。
我们的平台结构简单,功能较少。
D(Delivery,推广)
可以把平台介绍给身边的同学和朋友等,反馈不错的话再让他们的家人朋友分享给身边的人。
通过微博,b站等社交平台推广,同时给用户提供反馈方式,积极维护提问和评论区。
可以与体育论坛合作,吸引体育迷关注和使用我们的竞猜平台。
4.2 功能描述
功能模块图

4.2.1 用户登录界面
用户首先进行注册,设置账号和密码,账号为手机号码。
4.2.2 用户基本信息
- 显示用户的基本信息(姓名,手机号,地址)
- 对密码进行修改
4.2.2 竞猜功能
用户可以通过筛选器,选择比赛日期,包括单场的比赛项目、开始时间、截止时间、选手A、选手B的信息
点击竞猜按键可以选择选手进行投票
当竞猜项目结束的时候,会弹窗提示用户已经完成的竞猜项目
4.3 数据库设计
我们设计了4张数据库表,分别是用户表user、竞猜表guess、竞猜投票记录表vote_record、队伍表team,并且我们将数据库部署在服务器上
竞猜表guess:
队伍表team:
用户表user:
竞猜投票记录表vote_record:
5 功能实现思路
5.1 技术栈
5.1.1 前端技术栈
Vue.js
Element Plus
pnpm包管理
Pinia持久化存储
Eslint + prettier 代码规范校验
husky git提交验证
5.1.2 后端技术栈
SpringBoot框架
mysql数据库
mybatis持久层框架
Jwt 生成和校验Token
5.2 接口设计
共同讨论了接口设计,通过Apifox进行共同设计接口和调试(接口设计地址)
登录接口:
为了保证网站资源的安全性,我们需要进行一个简单的认证处理,如果登录成功,后端会返回一串jwt的token串,要求前端每次在请求头携带上token串,后端利用进行拦截器进行请求拦截,解析令牌
JwtUtil (Jwt token生成和解析类)
public class JwtUtil { /** * 生成jwt * 使用Hs256算法, 私匙使用固定秘钥 * * @param secretKey jwt秘钥 * @param ttlMillis jwt过期时间(毫秒) * @param claims 设置的信息 * @return */ public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) { // 指定签名的时候使用的签名算法,也就是header那部分 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 生成JWT的时间 long expMillis = System.currentTimeMillis() + ttlMillis; Date exp = new Date(expMillis); // 设置jwt的body JwtBuilder builder = Jwts.builder() // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 .setClaims(claims) // 设置签名使用的签名算法和签名使用的秘钥 .signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8)) // 设置过期时间 .setExpiration(exp); return builder.compact(); } /** * Token解密 * * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个 * @param token 加密后的token * @return */ public static Claims parseJWT(String secretKey, String token) { // 得到DefaultJwtParser Claims claims = Jwts.parser() // 设置签名的秘钥 .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)) // 设置需要解析的jwt .parseClaimsJws(token).getBody(); return claims; } }拦截器方法实现
/** * 校验jwt * * @param request * @param response * @param handler * @return * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断当前拦截到的是Controller的方法还是其他资源 if (!(handler instanceof HandlerMethod)) { //当前拦截到的不是动态方法,直接放行 return true; } //1、从请求头中获取令牌 String token = request.getHeader(userTokenName); //2、校验令牌 try { log.info("jwt校验:{}", token); Claims claims = JwtUtil.parseJWT(userSecretKey, token); Long userId = Long.valueOf(claims.get("userId").toString()); UserHolder.saveUserId(userId); log.info("当前用户id:", userId); //3、通过,放行 return true; } catch (Exception ex) { //4、不通过,响应401状态码 response.setStatus(401); return false; } }业务层代码(service),我们会在jwt中存放用户id,但我们不会存放敏感信息如密码、电话等(安全性考虑)
@Override public Result<UserLoginVo> login(UserParamsDto userParamsDto) { User user = userMapper.getUser(userParamsDto); if(user == null) { return Result.error("用户名或密码输入错误"); } //登录成功后,生成jwt令牌 Map<String, Object> claims = new HashMap<>(); claims.put("userId", user.getId()); String token = JwtUtil.createJWT( userSecretKey, userTtl, claims); UserLoginVo userLoginVo = UserLoginVo.builder() .token(token) .build(); return Result.success(userLoginVo); }注册接口:
前端发送请求到后端,后端获取密码、手机号码。接着后端判断手机号码是否唯一,如果唯一,那么成功注册,否则注册失败,并提示用户相应的信息
业务层代码
/** * 用户注册 * @param userParamsDto * @return */ @Override public Result register(UserParamsDto userParamsDto) { User userByPhone = userMapper.getUserByPhone(userParamsDto); if(userByPhone != null) { return Result.error("用户已经存在,无需注册"); } User user = new User(); BeanUtil.copyProperties(userParamsDto, user); user.setCreateTime(LocalDateTime.now()); user.setUpdateTime(LocalDateTime.now()); userMapper.insert(user); return Result.success("注册成功"); }
修改用户信息接口:(略:不展示)
修改用户密码接口:(略:不展示)
投票接口:
前端传入竞猜比赛id和队伍id,后端接收后写入竞猜记录表,前端为啥不需要传入用户id呢,因为登录后我们将用户id存入token中传回前端,前端每次请求后端接口都会携带token,我们通过拦截器拦截请求,并从请求中获取token解析出用户id存入UserHolder中,UserHolder是我们自己编写的一个工具类,底层是ThreadLocal,所以当业务层需要用户id时直接从UserHolder中获取即可
UserHolder工具类
public class UserHolder { private static final ThreadLocal<Long> tl = new ThreadLocal<>(); public static void saveUserId(Long id){ tl.set(id); } public static Long getUserId(){ return tl.get(); } public static void removeUserId(){ tl.remove(); } }接口层
@PostMapping("/vote") public Result vote(@RequestBody Map map) { return guessService.vote(map); }业务层(service)
@Override public Result vote(Map map) { Long guessId = Long.valueOf(map.get("guessId").toString()); Long userId = UserHolder.getUserId(); VoteRecord voteRecord = voteRecordMapper.selectByGuessIdAndUserId(guessId, userId); if(voteRecord != null) { return Result.error("你已经在本次比赛提交过竞猜,不能重复提交"); } voteRecord = new VoteRecord(); voteRecord.setGuessId(guessId); voteRecord.setTeamId(Long.valueOf(map.get("teamId").toString())); voteRecord.setUserId(userId); voteRecordMapper.insert(voteRecord); return Result.success("投票成功"); }
获取竞猜列表接口:
接口层:
@GetMapping("/list/{date}") public Result<List<GuessVo>> getGuessList(@PathVariable("date") String date) { return guessService.guessList(date); }业务层:将前端通过路径传入的日期参数(如,”0724“)解析出来查询数据库对应的竞猜列表,还需返回每支队伍的名字和已获得的票数
/** * 获取竞猜列表 * @param date 0727 */ @Override public Result<List<GuessVo>> guessList(String date) { //处理日期 String month = date.substring(0, 2); String day = date.substring(2); LocalDate localDate = LocalDate.of(2024, Integer.parseInt(month), Integer.parseInt(day)); LocalDateTime beginOfDay = LocalDateTime.of(localDate, LocalTime.MIN); LocalDateTime endOfDay = LocalDateTime.of(localDate, LocalTime.MAX); //查询 List<GuessVo> guessList = guessMapper.selectList(beginOfDay, endOfDay); List<Long> teamAIds = CollUtil.getFieldValues(guessList, "teamaId", Long.class); List<Long> teamBIds = CollUtil.getFieldValues(guessList, "teambId", Long.class); List<Team> teamAList = teamMapper.selectByIds(teamAIds); List<Team> teamBList = teamMapper.selectByIds(teamBIds); Map<Long, Team> mapA = CollUtil.fieldValueMap(teamAList, "id"); Map<Long, Team> mapB = CollUtil.fieldValueMap(teamBList, "id"); guessList.forEach( item -> { item.setTeamaName(mapA.get(item.getTeamaId()).getRegion()); item.setTeambName(mapB.get(item.getTeambId()).getRegion()); item.setWinnerTeamName(mapA.get(item.getTeamaId()).getRegion()); Integer voteA = voteRecordMapper.selectCountByTeamId(item.getTeamaId(), item.getId()); Integer voteB = voteRecordMapper.selectCountByTeamId(item.getTeambId(), item.getId()); item.setTeamaVotes(voteA); item.setTeambVotes(voteB); } ); return Result.success(guessList); }
获取我参与过的竞猜列表接口:
接口层
@GetMapping("/myList") public Result<List<MyGuessVo>> getMyVoteList() { return guessService.getMyVoteList(); }业务层:先从竞猜记录表中获取该用户投过的记录,利用获取的竞猜id返回竞猜赛事基本信息,并且通过判断比赛结束决定是否返回胜者消息和用户是否猜对的信息,至于为何前端不需要传入userId在前面投票接口已经解释过
@Override public Result<List<MyGuessVo>> getMyVoteList() { Long userId = UserHolder.getUserId(); List<VoteRecord> list = voteRecordMapper.selectByUserId(userId); List<MyGuessVo> ans = new ArrayList<>(list.size()); for(int i = 0; i < list.size(); ++i) { MyGuessVo myGuessVo = new MyGuessVo(); VoteRecord voteRecord = list.get(i); Long guessId = voteRecord.getGuessId(); GuessVo guessVo = guessMapper.selectById(guessId); Long teamId = voteRecord.getTeamId(); Team team = teamMapper.selectById(teamId); myGuessVo.setVoteTeamName(team.getRegion()); myGuessVo.setEndTime(guessVo.getEndTime()); myGuessVo.setGameName(guessVo.getGameName()); if(myGuessVo.getEndTime().isBefore(LocalDateTime.now())) { myGuessVo.setIsCorrect(guessVo.getWinnerTeam().equals(teamId)); myGuessVo.setWinnerTeamName(teamMapper.selectById(guessVo.getWinnerTeam()).getRegion()); } ans.add(myGuessVo); } return Result.success(ans); }
5.3 测试方案
后端人员在编写接口时,运用http client(idea中下载的插件,下载可以直接在idea中完成接口的测试)
以用户测试登录接口为例 展现测试代码和测试结果


该方法十分方便可以直接在idea进行接口测试,对比postman是个更佳选择
5.4 思考问题与解答
5.4.1 用户如何快速知道有竞猜功能并参与竞猜?
用户登录进去后首页就是竞猜功能,直白明了。
5.4.2 如何告知用户竞猜结果?
在竞猜结束后会在,用户界面登录后弹窗通知竞赛结果。
5.4.3 如何保证一人一号?
使用手机号进行登录,确保一人一号
6 运行截图说明
6.1 登录注册
登录,通过账号密码登录
注册,通过手机号(用户名)注册,确保一人一号
6.2 客户端
竞猜页面,可以看到待竞猜的各种比赛
竞猜过程,点击投票按钮可以选择竞猜的队伍,竞猜结束切换到“我的竞猜结果”会有弹窗提示竞猜结果
个人页面,可以修改姓名地址等个人信息,还可以修改密码
7 分工和贡献度说明
| 学号 | 分工 | 贡献比例 |
|---|---|---|
| 222200302 | 解决小组内出现的小问题,提供接口设计和数据库设计,搭建项目结构(包括依赖、配置)完成本项目业务类编写和配置类编写 | 18.5 |
| 222200301 | 完成部分后端数据持久层接口编写 | 9.5 |
| 222200303 | 完成部分后端数据持久层接口编写和部分VO类的设计 | 10 |
| 222200426 | 完成实体类和VO类的设计,编写博客 | 11.5 |
| 222200417 | 完成DTO类的设计和工具类的编写 | 9.5 |
| 222100110 | 解决小组内出现的小问题,参与接口设计和数据库设计,搭建前端项目结构,完成前端项目页面渲染,前后端的对接,接口封装 | 18 |
| 222200427 | 实现了竞猜界面,对小组进行分工,编写博客 | 12.5 |
| 222200332 | 实现了登陆界面和页面弹窗 | 10.5 |
分为前端和后端小组,分别有110和302同学担任组长,他们两位对此次作业贡献度较大,解决了组员的很多问题
8 困难与解决方法
| 学号 | 遇到的困难 | 解决方法 |
|---|---|---|
| 222200427郭翔宇 | 1. 使用 git push 时,出现了报错无法提交 2.时间紧迫,且是第一次经历一天时间做个小项目,组内同学掌握的技术水平差别较大,很慌 | 1. 发现是ESLint 被集成到了 Git 钩子(hooks)中,在提交时候会判断js的语法正确性,查看错误日志,重新修改不符合规范代码,使得符合规范 2.幸好两个小组长开发经验比较丰富,且善于指导组内编程较不熟练的同学,还是能及时完成任务 |
| 222100110吴宇航 | 1.我在前端项目中向后端发送请求时出现了跨域问题 2.后端的多个接口在一些输入下都会返回500状态码(服务器内部异常),导致前端无法正确获取数据。 3.使用vite构建项目之后再部署到Nginx服务上之后有一个问题,刷新页面,会提示404(页面没有找到),这种情况应该是页面刷新没有找到根路径导致的,或者当前的路径确实不存在(由于这是vue的路由,实际并没有这个路径) | 1.与后端及时沟通,让后端运行请求的跨域访问 2.及时联系后端,并且对这些接口进行联调 3.vite打包项目时base路径要设置为 / ,不要设置为 ./ (相对路径),同时Nginx服务器的配置也要加上一行 try_files $uri $uri/ /index.html; (没有找到文件或目录时再尝试访问index.html),通过这两个配置就解决了刷新页面提示404的问题了。 |
| 222200302方金田 | 1.如何保证系统安全性(认证安全) 2.后端传给前端的日期格式前端无法正常解析 | 1.利用Jwt生成令牌,用户访问需要携带令牌访问(JWT使用数字签名或加密算法对数据进行验证和防篡改,确保信息在传输过程中的安全性和完整性,并且使用JSON格式,易于解析和使用,这使得其在网络传输中更加高效) 2. @JsonFormat注解:在传入前端实体类的时间字段上加上注解@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") |
| 222200417林宇涛 | 对java语言不熟悉 | 使用AI辅助工具,用gpt生成代码 |
| 222200303石江强 | 使用 git clone和push时提示没有权限 | 直接在华为云代码仓库上传文件 |
| 222200426徐俊杰 | 要准确理解每个类的功能和它们之间的关系比较困难,特别是在没有详细需求文档的情况下。 | 与其他人尤其的设计者交流,理解设计 |
| 222200301王珺琨 | 项目使用的技术栈与之前接触的不同,完成较为吃力 | 通过阅读官方文档、教程和示例代码,向团队成员请教,进行实际编码练习慢慢的渐入佳境 |
| 222200332康思梦 | 登录页面背景图片无法显示 | 调整图像大小 |
9 PSP表格
222200427郭翔宇
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 60 40 • Estimate • 估计这个任务需要多少时间 60 40 Development 开发 405 490 • Analysis • 需求分析 (包括学习新技术) 90 85 • Design Spec • 生成设计文档 45 30 • Design Review • 设计复审 30 45 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 15 20 • Design • 具体设计 30 45 • Coding • 具体编码 180 200 • Code Review • 代码复审 15 20 • Test • 测试(自我测试,修改代码,提交修改) 30 45 Reporting 报告 90 70 • Test Repor • 测试报告 30 30 • Size Measurement • 计算工作量 15 10 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 45 30 合计 555 600 222100110吴宇航
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 60 70 • Estimate • 估计这个任务需要多少时间 60 70 Development 开发 750 800 • Analysis • 需求分析 (包括学习新技术) 150 160 • Design Spec • 生成设计文档 50 55 • Design Review • 设计复审 50 55 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 20 20 • Design • 具体设计 80 85 • Coding • 具体编码 250 270 • Code Review • 代码复审 50 60 • Test • 测试(自我测试,修改代码,提交修改) 100 95 Reporting 报告 90 96 • Test Report • 测试报告 30 35 • Size Measurement • 计算工作量 30 32 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 30 29 合计 900 966 222200302方金田
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 50 60 • Estimate • 估计这个任务需要多少时间 50 60 Development 开发 810 885 • Analysis • 需求分析 (包括学习新技术) 140 150 • Design Spec • 生成设计文档 60 70 • Design Review • 设计复审 40 45 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 30 30 • Design • 具体设计 80 85 • Coding • 具体编码 300 330 • Code Review • 代码复审 60 70 • Test • 测试(自我测试,修改代码,提交修改) 100 105 Reporting 报告 80 85 • Test Report • 测试报告 30 35 • Size Measurement • 计算工作量 20 20 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 30 30 合计 1000 966 222200417林宇涛
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 30 35 • Estimate • 估计这个任务需要多少时间 30 35 Development 开发 370 405 • Analysis • 需求分析 (包括学习新技术) 60 65 • Design Spec • 生成设计文档 30 35 • Design Review • 设计复审 20 25 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 15 10 • Design • 具体设计 50 55 • Coding • 具体编码 120 140 • Code Review • 代码复审 30 25 • Test • 测试(自我测试,修改代码,提交修改) 45 50 Reporting 报告 25 30 • Test Report • 测试报告 10 15 • Size Measurement • 计算工作量 5 5 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 10 10 合计 425 470
222200426徐俊杰
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 30 30 • Estimate • 估计这个任务需要多少时间 30 30 Development 开发 400 440 • Analysis • 需求分析 (包括学习新技术) 60 70 • Design Spec • 生成设计文档 20 20 • Design Review • 设计复审 30 30 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 20 20 • Design • 具体设计 30 40 • Coding • 具体编码 200 230 • Code Review • 代码复审 20 20 • Test • 测试(自我测试,修改代码,提交修改) 10 10 Reporting 报告 30 30 • Test Repor • 测试报告 10 10 • Size Measurement • 计算工作量 10 10 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 10 10 合计 460 500 222200301王珺琨
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 30 30 • Estimate • 估计这个任务需要多少时间 30 30 Development 开发 450 485 • Analysis • 需求分析 (包括学习新技术) 90 120 • Design Spec • 生成设计文档 30 30 • Design Review • 设计复审 30 35 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 10 10 • Design • 具体设计 60 60 • Coding • 具体编码 140 150 • Code Review • 代码复审 30 20 • Test • 测试(自我测试,修改代码,提交修改) 60 60 Reporting 报告 25 30 • Test Report • 测试报告 10 15 • Size Measurement • 计算工作量 5 5 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 10 10 合计 505 545 222200332康思梦
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 30 40 • Estimate • 估计这个任务需要多少时间 30 40 Development 开发 375 403 • Analysis • 需求分析 (包括学习新技术) 50 55 • Design Spec • 生成设计文档 5 5 • Design Review • 设计复审 10 8 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 10 12 • Design • 具体设计 200 210 • Coding • 具体编码 50 60 • Code Review • 代码复审 25 28 • Test • 测试(自我测试,修改代码,提交修改) 25 25 Reporting 报告 15 20 • Test Repor • 测试报告 5 8 • Size Measurement • 计算工作量 5 5 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 5 7 合计 420 463 222200303石江强
PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 20 20 • Estimate • 估计这个任务需要多少时间 20 20 Development 开发 650 630 • Analysis • 需求分析 (包括学习新技术) 120 100 • Design Spec • 生成设计文档 20 20 • Design Review • 设计复审 20 20 • Coding Standard • 代码规范 (为目前的开发制定合适的规范) 30 20 • Design • 具体设计 60 50 • Coding • 具体编码 350 370 • Code Review • 代码复审 20 20 • Test • 测试(自我测试,修改代码,提交修改) 30 30 Reporting 报告 60 70 • Test Repor • 测试报告 30 30 • Size Measurement • 计算工作量 10 20 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 20 20 合计 730 720
相关推荐
TC8测试TCP-UNACCEPTABLE-04/006
TC8测试TCP-UNACCEPTABLE-04/006
PSIM-串联谐振半桥LLC开关电源+PFM变频闭环控制【仿真+计算书+参考文献】
内容概要:本文档系统性地整合了电力电子与控制系统仿真领域的丰富资源,聚焦于基于PSIM和Simulink平台的串联谐振半桥LLC开关电源建模与仿真,深入探讨PFM变频闭环控制策略的设计与实现。内容涵盖LLC谐振变换器的工作原理、关键参数设计、开环与闭环仿真模型构建、软开关技术(ZVS/ZCS)、恒压恒流双竞争控制机制以及调频控制等核心技术,配套提供完整的仿真文件、计算书和参考文献,有助于深入理解高频开关电源系统的动态响应特性与稳定性分析方法。此外,文档还汇集了大量拓展性仿真资源,涉及双向DC-DC变换器、PWM整流器、PFC电路、储能系统、微电网优化、DAB变换器、并网逆变器等多个方向,构成一套完整的科研与工程实践参考资料体系。; 适合人群:适用于电力电子、电气工程及其自动化等相关专业的高校本科生、研究生,以及从事开关电源设计、新能源系统开发、电力变换器研发等工作的工程技术人员。; 使用场景及目标:①深入学习LLC谐振变换器的拓扑结构与闭环控制原理;②掌握PSIM/Simulink在电力电子系统中的高精度建模与仿真技能;③为科研项目、学位论文或产品开发提供可复用的技术方案与代码基础;④深化对PFM控制、软启动过程、ZVS/ZCS实现机制及系统稳定性的理解; 阅读建议:建议结合文档中提供的仿真模型与计算书进行同步操作,优先剖析主电路拓扑与控制逻辑架构,再逐步开展参数调节与仿真验证实验,同时可参考所列相关资源拓展技术视野,提升综合设计能力。
【MATLAB例程,无人机避障7】基于RRT*与人工势场法(RRT*+APF)的多无人机二维动态路径规划与避障
程序采用快速扩展随机树星算法(RRT*)与人工势场法(APF),实现四架无人机在二维动态障碍环境中的路径规划与协同避碰。通过RRT*的邻域选父和节点重连优化全局参考路径,利用APF进行局部动态避障,绘制全局路径、实际轨迹、安全净间隙、速度与加速度及航程等图像,对比RRT+APF与RRT*+APF的规划效果。无人机起终点、障碍物分布、采样次数及运动约束均可自行调整。
Windows开发工具环境管理:Git、Node.js、Python多版本与PATH冲突排查 - 配套实验资源
本资源是《Windows开发工具环境管理:Git、Node.js、Python多版本与PATH冲突排查》的配套实验工具,适用于 Windows PowerShell 5.1 和 PowerShell 7,帮助开发者排查 Git、Node.js、Python、Codex 等工具的多版本共存、PATH 配置异常及命令优先级冲突问题。 **资源包含两个 PowerShell 脚本:** 1. **Get-ToolchainInventory.ps1**:只读环境诊断工具,可列出开发工具的命令候选路径,检查 PATH 目录、重复条目及无效路径。不执行开发工具,也不修改系统配置。 2. **Invoke-PathPrecedenceLab.ps1**:PATH 优先级演示工具,在系统临时目录中生成测试命令,通过临时调整当前进程的 PATH,直观展示 Windows 命令查找与优先级规则。实验结束后自动恢复 PATH 并清理自身创建的临时文件。 **资源特点:** - 兼容 Windows PowerShell 5.1 和 PowerShell 7。 - 支持开发工具路径盘点与 PATH 冲突分析。 - 提供可重复的命令优先级实验。 - 不修改注册表、系统级或用户级环境变量。 - 不卸载软件、不安装依赖、不执行包管理器。 - 适合 Windows 开发环境排查、PowerShell 学习与技术教学。 **使用说明:** 下载后建议先审查脚本,再按照配套文章中的 PowerShell 命令运行。脚本已完成静态检查与打包,尚未经过 Windows 实机执行验证。 **安全提示:** 诊断结果可能包含个人或组织目录信息,公开分享前请脱敏。若受到 PowerShell 执行策略限制,应采用符合环境安全要求的授权方式运行,不建议全局关闭安全限制。
【机械故障诊断】基于VMD分解与故障频率匹配的复合故障分离方法:MATLAB实现与智能运维应用 MATLAB 轴承复合故障分离|VMD分解与故障频率匹配
内容概要:通过结合变分模态分解(VMD)与理论故障频率匹配技术,实现对滚动轴承复合故障的自适应分离与精准诊断。该方法首先对振动信号进行稳健预处理,再通过参数寻优的VMD实现频带自适应分解,随后利用包络解调提取各模态的冲击周期,并基于轴承几何参数和转速计算理论故障频率。通过基频、倍频与边带的多证据匹配策略,将模态与外圈、内圈、滚动体、保持架等具体故障类型关联,支持共享模态的复合故障重构,最终输出各故障类型的独立分量与诊断结果。该方案提升了复杂工况下弱故障的识别能力与诊断的可解释性。; 适合人群:具备一定信号处理与机械故障诊断基础知识,从事工业设备状态监测、智能运维系统开发或相关算法研究的研发人员。; 使用场景及目标:①应用于电机、泵组、风电、轨道交通等领域的轴承复合故障诊断;②解决强弱故障共存、频率重叠导致的掩蔽问题,实现多故障的分离与识别;③为设备的智能运维、健康管理和剩余寿命预测提供可靠的故障分量数据与诊断依据; 阅读建议:此资源以MATLAB R2025b为实现平台,提供了完整的算法流程、代码示例与GUI界面。建议使用者在实践中重点关注参数搜索策略、多证据匹配的实现细节以及共享模态重构的逻辑,并结合实际工程数据进行验证和调优。










