开发一个篮球共享计分器小程序

news/2025/1/16 16:29:27/文章来源:https://www.cnblogs.com/Vrapile/p/18675167

序言

  作为一名篮球爱好者的程序员,在使用目前市面篮球计分器时,总觉得用的不顺手,市面基本都是单机模式,广告很多,也不便于核对和多人协同记录。因此,我决定自己设计并开发一款篮球共享计分器小程序,实现多人协同记录赛事,提供多种方便快捷的计分方式和统计数据效果。

  上效果图:

      

  

  由于上篇《开发一个题库系统App和小程序的心得》已经叙述了很多资源方案,代码方案,部署方案,以及很多基础性的功能开发设计,此系统基本相同,不再赘述,直接讲解篮球共享计分器特有功能。

 

1.    功能目标

  篮球共享计分器功能目标:

  1. 实现多人实时共享记录比赛
  2. 提供个人和团队数据和表现的统计数据
  3. 提供单机版/共享版/私密版三种模式记录比赛
  4. 提供简易/精准版模式选择
  5. 保存历史比赛数据,可用于文字直播。

 

1.1     功能列表

  篮球共享计分器核心功能

  1. 实现常规简易单机版计分器
  2. 实现协同协同版计分器,协同实时切换简易版和精准版计分方式
  3. 实现团队对比数据,可视化图表展示和对比,以及完整文字记录
  4. 实现个人完整数据,以及个人完整文字记录
  5. 协同版区分公开和私密赛事,公开赛事可免登录参与,私密赛事支持多种精准权限控制记录比赛

 

1.2     功能截图

  以下是App端的部分截图

       

  以下是微信小程序端的部分截图

       

2.    实现方案

 

2.1     设计方案

 

2.1.1   数据库设计

  赛事表

   

 

  队员表

   

 

  授权表

   

 

  日志表

   

  

2.1.2   移动端开发-赛事列表和录入

        

           

  

  赛事有三种添加方式:

  1. 已有比赛,可以选择复制一份,会复制赛事的队员和用户权限
  2. 录入比赛,自行录入比赛名称等信息,保存即可
  3. (需登录)添加授权码比赛,别人创建的私密比赛,分享的授权码,可以通过授权码进行添加

 

  赛事录入细节:

  1. 长按赛事明细,可操作复制/编辑/授权/重置/取消/删除(可见操作按钮跟权限有关)
  2. 编辑赛事,可增加/修改/删除赛事双方队员:添加队员直接录入即可;搜索队员可查找有权限赛事的所有人员,因此同名队伍只需录入一次,下次直接搜索一次性添加即可;长按队员可编辑;删除按钮可删除。(赛事录入页面也可同样操作)

  

2.1.3   移动端开发-赛事授权(需登录)

  赛事列表中,对于公开赛事,所有人都可见也都是管理员角色;对于私密赛事,长按明细,可选择授权操作。

       

       

  有两种授权模式:

  1. 生成授权码,点击观众/主队管理员/客队管理员/管理员,可生成对应赛事授权码,其他人在赛事列表页面通过添加授权码比赛的方式即可获权
  2. 添加用户,点击添加用户,输入用户信息查找授权即可(为保证用户隐私,此处不支持模糊搜索)

 

  授权细节说明:

  1. 赛事创建人是超级管理员,可以直接添加/修改/删除任何已授权用户
  2. 只能添加/修改/删除比自己低的权限,不会出现操作的权限超越操作人的权限的情况
  3. 可自己删除自己的授权,删除后赛事不可见

 

2.1.4   移动端开发-记录比赛

       

  赛事记录方法:

  1. 点击【精准版】/【简易版】可以互相切换记录模式
  2. 点击【用时】,可查看实时比赛数据结果
  3. 点击【分享比赛】,可生成赛事二维码,让其他人参与
  4. 长按任意队员,可切换队员
  5. 长按日志明细,可作废或修改日志

  赛事记录说明:

  1. 公开赛事记录,所有人都是管理员权限,都可以通过分享的二维码进行赛事记录。
  2. 私密赛事记录,扫码进来的默认赋权观众,需要进一步授权才可以记录比赛,否则只能观看。
  3. 私密赛事记录,管理员可以记录双方数据,主队管理员只能记录主队数据,客队管理员只能记录客队数据,观众只能观看。
  4. 加时赛说明,默认四节比赛,如果在第四节结束,两队分数一致,自动进入加时,否则比赛结束。

 

2.1.5   移动端开发-查看结果

      

       

  

  查看结果有三种方式:

  1. 列表已经结束的比赛,点击查看即可查看比赛结果
  2. 记录比赛中,点击用时可以查看比赛结果
  3. 通过其他人分享的比赛结果二维码可以查看比赛结果

 

  查看结果操作说明:

  1. 进入结果页面,可点击上方【*** 数据】切换页签,也可以左右滑动切换页签
  2. 在【**队 数据】页签,柱状图的“其他”表示整队的数据,也就是比赛记录时,选择了队伍,未选择具体人员
  3. 小程序图表可能出现空白,点一下图表内部,即可正常显示,图表组件在小程序上的层级Bug问题,暂时未修复

 

2.1.6   移动端开发-单机版计分器

    

 

  操作说明:

  1. 点击【单机版】可清空重置数据
  2. 长按【犯规】或【队伍暂停】可减少次数
  3. 打开页面后可离线操作,离开页面或应用,数据缓存在本地,并不会消失,只能记录一个赛事,清空重置后,数据清除不可找回

 

2.2     开发方案

 

2.2.1   后端开发-框架Springboot

  基于若依plus,在其基础上增加ruoyi-race模块,单独存放赛事相关功能,其中四个controller分别是:

    

  Race:赛事功能

  Log:日志功能

  Member:成员功能

  User:授权用户功能

  Message:SSE发送消息功能(已弃用)

  SSE:SSE连续功能(已弃用)

  WxToken:获取小程序Token和生成小程序带参数二维码功能

  

  SSE在使用时,微信小程序和APP不能很好的支持EventSource前端组件,长连接也存在兼容问题,效果都不好,所以弃用,使用WebSocket

    

        在整合的框架中,使用的是Tio引擎的Websocket,增加两种赛事的消息类型,初始化消息和常规消息:

        初始化消息:读取并回执当前某一赛事最新完整赛事数据

        常规消息:发送记录赛事时的各种指令,更新赛事,记录日志,并回执更新后的完整赛事数据


 

2.2.2   移动端开发-框架Uniapp

核心在记录赛事使用websocket上,这里我们使用具体页面直连的方式,离开页面则关闭websocket,相关代码如下

    onUnload() {this.timeClear()this.socket.close(true)},onShow() {this.diyApiGet('/race/race/getMoreByRaceId/' + this.setData.id).then(res => {this.setData = res.data;if(!this.userInfo || !this.userInfo.userId){// 公开赛事,无用户,随机生成一个this.userId = this.getRandom(2, 16);}else{this.userId = this.userInfo.userId;}// websocket非通讯状态,则重连// #ifdef APP-PLUSif(!this.socket){this.getMemberFirstList();this.getMemberSecondList();this.connectWebsocket(this.userId, this.setData.id);}// #endif// #ifndef APP-PLUSif(!this.socket || this.socket.getReadyState() != 1){this.getMemberFirstList();this.getMemberSecondList();this.connectWebsocket(this.userId, this.setData.id);}// #endif
        })},


连接websocket方法,未登录传入随机用户ID

    connectWebsocket(userId, raceId){let url = globalData.wssUrl;let heartbeatTimeout = 50000; // 心跳超时时间,单位:毫秒let reconnInterval = 5000; // 重连间隔时间,单位:毫秒let binaryType = 'blob'; // 'blob' or 'arraybuffer';//arraybuffer是字节let paramStr = "app=urace&userId=" + userId + "&sessionId=" + raceIdlet param = "";this.socket = new TioSocket(url, paramStr, param, heartbeatTimeout, reconnInterval, binaryType);let ws = this.socket.connect(false);ws.onOpen((e) => {// 读取赛事初始信息
                uni.sendSocketMessage({data: JSON.stringify({code:6, message: {raceId: raceId, userId: userId}})})this.socket.reset();})ws.onMessage((e) => {let message = JSONbig.parse(e.data);if(message.code == 2){let data = JSONbig.parse(message.message.content)if(data.msg){this.msg(data.msg);return;}if(data.data){this.setData = data.data;this.usedTime = data.data.usedTime || 0;if(data.data.status == 1){this.timeInterval();}else{this.timeClear();}if(data.data.status < 0){this.logList = []}this.showTitle();}if(data.log){if(data.log.logType == 99){this.getMemberFirstList();this.getMemberSecondList();this.invalidMessageLog(data.log)}else if(data.log.logType == 61){this.moveMessageLog(data.log)}else{if(data.log.logType == 34 || data.log.logType == 41 || data.log.logType == 42 || data.log.logType == 43 || data.log.logType == 81 || data.log.logType == 82 || data.log.logType == 83){if(data.log.teamIndex == 1){this.getMemberFirstList();}if(data.log.teamIndex == 2){this.getMemberSecondList();}}this.addMessageLog(data.log, true)}}}this.socket.reset();})},


赛事记录命令转译函数

export function getLogText(log, firstTeamName, secondTeamName, status){let text = "";if(log.teamIndex == 1){text += " " + firstTeamName}if(log.teamIndex == 2){text += " " + secondTeamName}if(log.memberName){text += " " + log.memberName}switch(log.logType){case -10:text += "比赛尚未开始";break;case -1:text += "比赛进行中";break;case -2:text += "比赛暂停中";break;case -3:if(log.period == 2){text += "第一节已结束";}else if(log.period == 3){text += "第二节已结束";}else if(log.period == 4){text += "第三节已结束";}else if(log.period >= 5 && log.firstTeamScore != log.secondTeamScore){text += "比赛已结束";}else if(log.period == 5){text += "第四节已结束";}else if(log.period == 6){text += "加时赛1已结束";}else if(log.period == 7){text += "加时赛2已结束";}else if(log.period == 8){text += "加时赛3已结束";}else if(log.period == 9){text += "加时赛4已结束";}else if(log.period == 10){text += "加时赛5已结束";}else{text += "加时赛已结束";}break;case -9:text += "比赛已取消";break;case 1:text += "比赛开始";break;case 2:text += "裁判暂停";break;case 3:if(log.period == 1){text += "第一节比赛继续";}else if(log.period == 2){text += "第二节比赛继续";}else if(log.period == 3){text += "第三节比赛继续";}else if(log.period == 4){text += "第四节比赛继续";}else if(log.period == 5){text += "加时赛1继续";}else if(log.period == 6){text += "加时赛2继续";}else if(log.period == 7){text += "加时赛3继续";}else if(log.period == 8){text += "加时赛4继续";}else if(log.period == 9){text += "加时赛5继续";}else if(log.period == 10){text += "加时赛6继续";}else{text += "加时赛继续";}break;case 4:if(log.period == 2){text += "第一节结束";}else if(log.period == 3){text += "第二节结束";}else if(log.period == 4){text += "第三节结束";}else if(log.period >= 5 && log.firstTeamScore == log.secondTeamScore){text += "比赛结束";}else if(log.period == 5){text += "第四节结束";}else if(log.period == 6){text += "加时赛1结束";}else if(log.period == 7){text += "加时赛2结束";}else if(log.period == 8){text += "加时赛3结束";}else if(log.period == 9){text += "加时赛4结束";}else if(log.period == 10){text += "加时赛5结束";}else{text += "加时赛结束";}break;case 5:text += "比赛取消";break;case 6:text += " 请求暂停";break;case 11:text += " 罚篮命中,得1分"break;case 12:text += " 投篮命中,得2分"break;case 13:text += " 投篮命中,得2分,加罚1次"break;case 14:text += " 突破上篮,得2分"break;case 15:text += " 突破上篮,得2分,加罚1次"break;case 16:text += " 投篮命中,得3分"break;case 17:text += " 投篮命中,得3分,加罚1次"break;case 18:text += " 扣篮成功,得2分"break;case 19:text += " 扣篮成功,得2分,加罚1次"break;case 20:text += " 扣1分"break;case 21:text += " 罚篮不中"break;case 22:text += " 2分不中"break;case 23:text += " 2分不中,被犯规,罚球2次"break;case 24:text += " 3分不中"break;case 25:text += " 3分不中,被犯规,罚球3次"break;case 26:text += " 上篮失败"break;case 27:text += " 上篮失败,被犯规,罚球2次"break;case 28:text += " 扣篮失败"break;case 29:text += " 扣篮失败,被犯规,罚球2次"break;case 31:text += " 助攻一次"break;case 32:text += " 失误,丢失球权"break;case 33:text += " 抢断,获得球权"break;case 34:text += " 普通犯规"break;case 35:text += " 被普通犯规"break;case 36:text += " 投篮被犯规,开始罚球"break;case 37:text += " 盖帽"break;case 38:text += " 被盖帽"break;case 39:text += " 获得前场篮板"break;case 40:text += " 获得后场篮板"break;case 41:text += " 犯规,对手罚球"break;case 42:text += " 违体犯规"break;case 43:text += " 技术犯规"break;case 81:text += " 上场"break;case 82:text += " 下场," + log.nextMemberName + " 上场"break;case 83:text += " 下场休息"break;default:text += log.logType}return " " + text
}

 

3.    总结一下

  篮球共享计分器,主要实现的是一个协同处理能力,此次小程序开发,不仅实现了App、小程序、H5的三端兼容,也实现了赛事数据的实时同步,经过测试,任意时间进入赛事的用户,都能保证比赛用时显示的同步,互相操作都能及时收到消息。

 

  不足之处,图表使用的uchart工具,兼容性还有待研究,篮球规则懂的不全面,以及更多形式的赛事记录支持等。

 

  以上分享心得只能描述个大概,个人文档和开发水平都有限,文档或有错误和不妥之处,欢迎指定!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/870181.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

飞机电气系统技术分析:数字样机技术引领创新

现代飞机正向着更安全、环保和经济的方向发展,飞机系统的设计日益复杂,对各子系统的性能和可靠性也提出了更高要求。作为飞机的重要组成部分,电气系统(Electrical System,ES)不仅负责为各类机载设备提供稳定的电力支持,还在飞行控制、导航、通讯以及乘客舒适性等方面发挥…

Go操作MongoDB

NoSQL泛指非关系型数据库,如mongo,redis,HBase。 mongo使用高效的二进制数据存储,文件存储格式为 BSON ( 一种json的扩展,比json性能更好,功能更强大)。 MySQL中表的概念在mongo里叫集合(collection), MySQL中行的概念在mongo中叫文档(document),一个文档看上去像一个j…

2025年实战技巧!如何通过项目管理助力产品经理实现产品目标?

在当今竞争激烈的商业环境中,产品经理不仅要负责产品的整体规划和设计,还需要确保项目能够按时、按质、按预算完成。这就需要产品经理具备出色的项目管理能力。本文将深入探讨如何通过项目管理助力产品经理实现产品目标,并提供2025年的实战技巧。引言 随着市场的不断变化和技…

Polygon-funky

E. Polygon 给定一个数 n,生成一个 nn 的一个全为 0 的初始矩阵,矩阵上方和左方均有一排炮台,矩阵的下边和右边是边界 炮台可以发射子弹,子弹只能直线行走,且遇到边界后会停止,遇到一个停止的子弹也会停止,子弹停止后的坐标里面的值记为 1 在任何时候,都不会有超过一门…

2025四款简单好用的电脑便签提醒软件推荐

进入2025年,越来越多的打工人需要在电脑上使用一款桌面便签或日程提醒软件,随时记录和管理工作事项,能够帮助我们高效整理思绪,确保重要事务不被遗漏。 今天给大家介绍四款简单又好用的电脑便签或日程提醒软件,总有一款是适合你的! 一、Win系统便笺 Windows操作系统自带的…

本次小论文minor revision中的知识积累

可以发邮件向编辑申请延期返修截止日期 https://cn.service.elsevier.com/app/answers/detail/a_id/29653/c/10595/supporthub/publishing/role/作者/ https://zhuanlan.zhihu.com/p/577324425申请邮件模板:如何在Editorial Manager系统中提交修改稿?【爱思唯尔Editorial Man…

多通道传感器接入集中控制频率温度 传感器集线器带来更多方便

多通道传感器接入集中控制频率温度 传感器集线器带来更多方便现场传感器太多,编号容易混乱?传感器集线器可以将多路传感器轮流切换到单一接口,为现场提供更多方便。操作简便直观,使用一个百位拨动开关和两个旋转开关(十位和个位)自由切换到任意传感器。 传感器通道多,最…

实战指南:优化采购流程,实现高效采购管理

优化采购流程需要从多个方面入手,包括明确采购需求、加强供商管理、优化采购谈判与合同签订、加强采购执行与跟踪、提高质量控制与验收水平、进行成本分析与优化、加强人员培训与发展以及注重合规与风险管理。通过这些措施的实施,可以显著提高采购效率和质量,降低采购成本,…

Lableview 标签软件 | LABELVIEW 条形码标签软件

Lableview 标签软件 | LABELVIEW 条形码标签软件Lableview 专业顾问 手机|微信:13928851814值得您信赖的条形码标签软件稳健可靠的条形码标签创建与集成简单的数据库连接易于使用的界面和提供便利的向导100 多种条形码符号体系可自定义的打印界面变量选用表增加了灵活性LABE…

原生JS实现一个日期选择器(DatePicker)组件

这是通过原生HTML/CSS/JavaScript完成一个日期选择器(datepicker)组件,一个纯手搓的组件的开发。主要包括datepicker静态结构的编写、日历数据的计划获取、组件的渲染以及组件事件的处理。 根据调用时的时间格式参数,可以控制短日期格式或长日期格式。实现效果(短日期格式…

LabelMatrix 标签软件 | LABEL MATRIX 条形码标签软件

LabelMatrix 标签软件 | LABEL MATRIX 条形码标签软件LabelMatrix 专业顾问 手机|微信:13928851814LABEL MATRIX 条形码标签软件 借助功能丰富的条形码标签软件,为将来的发展奠定坚实的基础适用于简单标签需求的条形码标签软件提供帮助的内置向导熟悉的 Windows 用户界面10…

《操作系统真相还原》实验记录2.5——线程实现

本文章实现内容如下: 1. 实现单线程的创建功能 2. 实现多线程调度的基本功能,包含:时钟中断处理函数;任务调度器;任务切换函数;零、项目说明本项目仓库现已公开,地址:GitHub:-HC-OS-操作系统设计项目 本项目当前进度:已完成多线程调度基础功能;一、前置知识点 1.1 …