最近好像有个奇葩说相关的话题上了热搜。不过,那些话题并不是我们这次的主题,我们更想聊聊辩论赛的“未来”。
说是“未来”,或许现在也同样适用。在疫情还未解除的情况下,很多线下活动都无法进行,辩论就是其中之一。不过已经有人将这个场景从线下搬到了线上。
我们 2019 年 RTC 创新编程挑战赛的三强之一,“辩之竹”团队实现了一套功能完整的辩论系统,能计时、在线辩论、裁判视频点评,还能统计票数等。而且,它已经应用于很多辩论比赛中。于是我们让“辩之竹”撰写分享了一下作品的初衷,还有核心功能的实现:
项目介绍
为解决传统辩论赛UI丑、各系统相互割裂、线下举办各类成本等问题,特开发此系统。该套系统完全体包括:
-
可定制的赛事计时器 -
赛程、评委和辩手 管理后台 -
赛程查看和无纸化提交分数的小程序 -
赛后即时点对点反馈个人表现的辩力提升系统 -
远程裁决的视频会议部分

项目初心
-
日程查看不直观 -
计时器简陋不美观 -
统计票数麻烦且不环保 -
复盘数据获取困难 -
优质裁判资源稀少
解决日程观看不直观
[打开QQ->进入赛事群->点开群文件->打开PDF->人工寻找对应日期的日程]。
就算完成了上述步骤,日程文件往往也是一个字号小、信息繁复、不直观的 PDF 文件。寻找一个日程很麻烦且不适。为了让参赛人员和观赛人员更直观的看到日程,特在小程序内设置此页面。

图:日程展示
//./web/admin-battle-add.php//这里调用了我自己写的微信云开发简易SDK,可以在源码中./web部分/lib/WeChat.php找到。具体信息可以在本文后部分具体介绍中找到。else if($motion=="addBattle"){$title = $_POST["title"];$loc = $_POST["loc"];$time = $_POST["time"];$teamClaimId = $_POST["teamClaimId"];$teamCounterClaimId = $_POST["teamCounterClaimId"];$res = $wx->databaseAdd("db.collection(\"battle\").add({data:{env:\"{$GLOBALS["env"]}\",title:\"{$title}\",status:\"0\",loc:\"{$loc}\",time:\"{$time}\",data:{teamClaim:{Id:\"{$teamClaimId}\",point:\"\"},teamCounterClaim:{Id:\"{$teamCounterClaimId}\",point:\"\"}}}})");redirect("./admin-battle-query.php?id=".$res["id_list"][0]);}
//./小程序部分/Bam1/client/src/pages/schedule/schedule.jscomponentWillMount () {let {env} = this.$router.params;Taro.setNavigationBarTitle({title:this.$router.params.cName});Taro.setStorageSync("env",env);let p = this;let skpD = 0;Taro.cloud.database({env:"factory-1"}).collection("other").where({env: Taro.getStorageSync("env"),isSkpD : true}).get({success: res1 => {skpD = res1.data[0].skpD;Taro.cloud.database({env:"factory-1"}).collection("battle").where({env: Taro.getStorageSync("env")}).skip(skpD).limit(12).get({success:function (res) {let idL = p.state.idList;res.data.map((item,index)=>{idL.push(item._id);});p.setState({idList: idL})...}
备注:
小程序部分,./Wechat Mini Program/Bam1/client/src/pages/schedule/schedule.js这部分代码主要是调用微信云开发的相关函数获取比赛 ID 列表。
在这个文件外,./Wechat Mini Program/Bam1/client/src/components/battle/battle.js 是每一个日程 card 的组件。通过 schedule 文件向内传入 ID 参数,在 battle component 内获取数据。
这里存在一个并不合理的获取数据方式。我后来思考,在主界面一次性获取所有数据后,将数据交由 battle component 渲染应该可以得到更高的性能。但是当时时间有限,就没有修改。
解决计时器简陋不美观

图:传统计时器
显然,这种计时器与任何现代的设计思维都背道而驰,完全无美感可言。我找朋友为我设计了计时器的页面,并利用 HTML + JavaScript 实现其功能。计时器展示如图:

图:计时器展示

./web/admin-battle-add.php
-
辩手姓名、图片展示 -
键盘操控 -
自定义环节
解决统计票数问题
文件在:./Wechat Mini Program/Bam1/client/src/pages/user/judge.js

图:小程序裁判入口

图:裁判界面
Taro.setStorageSync(),在每一次写完数据后,将数据存入临时数据。同样,当全部写入完毕,再使用微信云开发提交到服务器。

图:分数实时回传
$obj = $wx->databaseQuery("db.collection(\"battle-judge-point-conclude\").where({env:\"{$GLOBALS["env"]}\",battleId:\"{$bid}\",judgeId:\"{$r["judgeId"]}\"}).get()");
复盘数据获取更容易
个人辩力提升系统也是本系统的另一个亮点。在传统赛事中,辩手对自己的表现只能以输赢来衡量,很难量化出一个标准,往往会拖慢对个人的提升。

图:个人辩力提升系统
裁判远程视频

图:远程视频裁决系统
文字直播:
$("#send").click(function () {if(channel === null) {showOnP("未加入频道,请登录。")return;}channel.sendMessage({ text: $("#text").val() }).then(() => {showOnP("直播发送:"+$("#text").val());/* 频道消息发送成功的处理逻辑 */}).catch(error => {showOnP("直播发送失败:"+$("#text").val());showOnP(error)/* 频道消息发送失败的处理逻辑 */});})client.on('ChannelMessage', ({ text }, senderId) => { // text 为收到的频道消息文本,senderId 为发送方的 User IDconsole.log(text);/* 收到频道消息的处理逻辑 */showOnP("直播服务器收到信息:"+text+",直播员:"+senderId);});
rtc.client.init(option.appID, function () {console.log("init success");rtc.client.join(option.token ? option.token : null, option.channel, option.uid ? +option.uid : null, function (uid) {Toast.notice("join channel: " + option.channel + " success, uid: " + uid);console.log("join channel: " + option.channel + " success, uid: " + uid);rtc.joined = true;rtc.params.uid = uid;// create local streamrtc.localStream = AgoraRTC.createStream({streamID: rtc.params.uid,audio: true,video: true,screen: false,microphoneId: option.microphoneId,cameraId: option.cameraId})// init local streamrtc.localStream.init(function () {console.log("init local stream success");// play stream with html element id "local_stream"rtc.localStream.play("local_stream")// publish local streampublish(rtc);}, function (err) {Toast.error("stream init failed, please open console see more detail")console.error("init local stream failed ", err);})}, function(err) {Toast.error("client join failed, please open console see more detail")console.error("client join failed", err)})}, (err) => {Toast.error("client init failed, please open console see more detail")console.error(err);});}
此外,在上述展示出来的部分外,该系统还有完备的数据录入(指赛事信息录入),辩手信息和裁判信息录入系统。在这里不多展示。目前该系统已应用到实际环境多次,支撑多次辩论赛事的开展,欢迎大家使用,也欢迎大家可以一起参与到该项目的开发维护。
涉及技术
小程序: Taro, 微信云开发
网页端: Material Pro(样式), PHP, Agora SDK
开源与更多
作者于卓浩:重庆大学在读大一学生,喜欢学习新技术,兴致来了就写些自己喜欢的小项目。希望能在有限的时间多学习一些有用的知识~
RTC 2020 编程挑战赛春季赛已经开启报名了!本次大赛从 3月10日 ~ 4月21日 进行报名、组队与开发,4 月 22 日至 4 月 24 日提交作品,4 月 25 日评奖,全程在线上进行。本次大赛准备了丰厚的大奖,获奖者更有机会进入声网 Agora 应聘快速通道,快拉上小伙伴报名吧!

点击「阅读原文」,报名参赛!

