体育直播系统趣猜功能开发技术实现方案
功能概述
趣猜功能是“东莞梦幻网络科技”体育直播系统源码中的互动功能,主播可以发起竞猜题目,观众使用虚拟货币进行投注,增加直播间的互动性和趣味性。所有货币均为虚拟货币,通过系统活动获取,不可充值提现。
数据库设计 (MySQL)
-- 趣猜表
CREATE TABLE `live_quiz` (`id` int(11) NOT NULL AUTO_INCREMENT,`live_id` int(11) NOT NULL COMMENT '直播间ID',`anchor_id` int(11) NOT NULL COMMENT '主播ID',`title` varchar(255) NOT NULL COMMENT '趣猜主题',`option_a` varchar(100) NOT NULL COMMENT '选项A',`option_b` varchar(100) NOT NULL COMMENT '选项B',`odds_a` decimal(5,2) NOT NULL DEFAULT '1.00' COMMENT 'A选项赔率',`odds_b` decimal(5,2) NOT NULL DEFAULT '1.00' COMMENT 'B选项赔率',`end_time` int(11) NOT NULL COMMENT '截止时间',`result` tinyint(1) DEFAULT NULL COMMENT '结果:0-A赢,1-B赢,NULL-未开奖',`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态:0-进行中,1-已结束,2-已开奖',`create_time` int(11) NOT NULL,`update_time` int(11) NOT NULL,PRIMARY KEY (`id`),KEY `live_id` (`live_id`),KEY `anchor_id` (`anchor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='直播间趣猜表';-- 用户投注表
CREATE TABLE `live_quiz_bet` (`id` int(11) NOT NULL AUTO_INCREMENT,`quiz_id` int(11) NOT NULL COMMENT '趣猜ID',`user_id` int(11) NOT NULL COMMENT '用户ID',`option` tinyint(1) NOT NULL COMMENT '投注选项:0-A,1-B',`amount` int(11) NOT NULL COMMENT '投注金额',`potential_win` int(11) NOT NULL COMMENT '潜在收益',`is_win` tinyint(1) DEFAULT NULL COMMENT '是否赢:0-输,1-赢,NULL-未开奖',`win_amount` int(11) DEFAULT NULL COMMENT '实际赢取金额',`create_time` int(11) NOT NULL,`update_time` int(11) NOT NULL,PRIMARY KEY (`id`),KEY `quiz_id` (`quiz_id`),KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户投注表';-- 用户虚拟货币表
CREATE TABLE `user_virtual_currency` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL,`balance` int(11) NOT NULL DEFAULT '0' COMMENT '余额',`total_earn` int(11) NOT NULL DEFAULT '0' COMMENT '累计获得',`total_spend` int(11) NOT NULL DEFAULT '0' COMMENT '累计消费',`create_time` int(11) NOT NULL,`update_time` int(11) NOT NULL,PRIMARY KEY (`id`),UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户虚拟货币表';
PHP后端实现 (ThinkPHP)
控制器 LiveQuizController.php
<?php
namespace app\api\controller;use think\Controller;
use think\Request;
use app\common\model\LiveQuiz;
use app\common\model\LiveQuizBet;
use app\common\model\UserVirtualCurrency;class LiveQuizController extends Controller
{// 主播发起趣猜public function create(Request $request){$user = $request->user;$data = $request->only(['live_id', 'title', 'option_a', 'option_b', 'odds_a', 'odds_b', 'end_time']);// 验证数据$validate = new \think\Validate(['live_id' => 'require|number','title' => 'require|max:255','option_a' => 'require|max:100','option_b' => 'require|max:100','odds_a' => 'require|float|>:0','odds_b' => 'require|float|>:0','end_time' => 'require|number|>:time']);if (!$validate->check($data)) {return json(['code' => 400, 'msg' => $validate->getError()]);}$data['anchor_id'] = $user->id;$data['create_time'] = time();$data['update_time'] = time();$quiz = LiveQuiz::create($data);// 广播消息到直播间$this->broadcastQuizCreate($quiz);return json(['code' => 200, 'msg' => '趣猜创建成功', 'data' => $quiz]);}// 用户投注public function bet(Request $request){$user = $request->user;$data = $request->only(['quiz_id', 'option', 'amount']);// 验证数据$validate = new \think\Validate(['quiz_id' => 'require|number','option' => 'require|in:0,1','amount' => 'require|number|>:0']);if (!$validate->check($data)) {return json(['code' => 400, 'msg' => $validate->getError()]);}// 检查趣猜是否存在且可投注$quiz = LiveQuiz::where('id', $data['quiz_id'])->where('status', 0)->where('end_time', '>', time())->find();if (!$quiz) {return json(['code' => 400, 'msg' => '该趣猜已结束或不存在']);}// 检查用户余额$currency = UserVirtualCurrency::where('user_id', $user->id)->find();if (!$currency || $currency->balance < $data['amount']) {return json(['code' => 400, 'msg' => '虚拟货币不足']);}// 计算潜在收益$odds = $data['option'] == 0 ? $quiz->odds_a : $quiz->odds_b;$potential_win = floor($data['amount'] * $odds);// 开始事务Db::startTrans();try {// 扣除用户余额UserVirtualCurrency::where('user_id', $user->id)->update(['balance' => Db::raw('balance-'.$data['amount']),'total_spend' => Db::raw('total_spend+'.$data['amount']),'update_time' => time()]);// 创建投注记录$bet = LiveQuizBet::create(['quiz_id' => $data['quiz_id'],'user_id' => $user->id,'option' => $data['option'],'amount' => $data['amount'],'potential_win' => $potential_win,'create_time' => time(),'update_time' => time()]);// 广播投注消息到直播间$this->broadcastBet($quiz->live_id, ['user_id' => $user->id,'nickname' => $user->nickname,'option' => $data['option'],'amount' => $data['amount']]);Db::commit();return json(['code' => 200, 'msg' => '投注成功', 'data' => $bet]);} catch (\Exception $e) {Db::rollback();return json(['code' => 500, 'msg' => '投注失败:'.$e->getMessage()]);}}// 主播开奖public function settle(Request $request){$user = $request->user;$quiz_id = $request->param('quiz_id');$result = $request->param('result');// 验证数据if (!in_array($result, [0, 1])) {return json(['code' => 400, 'msg' => '无效的结果']);}// 检查趣猜是否存在且可开奖$quiz = LiveQuiz::where('id', $quiz_id)->where('anchor_id', $user->id)->where('status', 0)->where('end_time', '<', time())->find();if (!$quiz) {return json(['code' => 400, 'msg' => '该趣猜不能开奖']);}// 开始事务Db::startTrans();try {// 更新趣猜结果$quiz->result = $result;$quiz->status = 2;$quiz->update_time = time();$quiz->save();// 获取所有赢的投注$winBets = LiveQuizBet::where('quiz_id', $quiz_id)->where('option', $result)->select();// 发放奖励foreach ($winBets as $bet) {$winAmount = $bet->potential_win;// 更新投注记录$bet->is_win = 1;$bet->win_amount = $winAmount;$bet->update_time = time();$bet->save();// 增加用户余额UserVirtualCurrency::where('user_id', $bet->user_id)->update(['balance' => Db::raw('balance+'.$winAmount),'total_earn' => Db::raw('total_earn+'.$winAmount),'update_time' => time()]);}// 更新输的投注LiveQuizBet::where('quiz_id', $quiz_id)->where('option', $result == 0 ? 1 : 0)->update(['is_win' => 0,'win_amount' => 0,'update_time' => time()]);// 广播开奖消息到直播间$this->broadcastSettle($quiz->live_id, ['quiz_id' => $quiz->id,'result' => $result,'option_a' => $quiz->option_a,'option_b' => $quiz->option_b]);Db::commit();return json(['code' => 200, 'msg' => '开奖成功']);} catch (\Exception $e) {Db::rollback();return json(['code' => 500, 'msg' => '开奖失败:'.$e->getMessage()]);}}// 获取趣猜列表public function list(Request $request){$live_id = $request->param('live_id');$status = $request->param('status', 0);$list = LiveQuiz::where('live_id', $live_id)->where('status', $status)->order('create_time', 'desc')->select();return json(['code' => 200, 'msg' => 'success', 'data' => $list]);}// 获取趣猜详情public function detail(Request $request){$quiz_id = $request->param('quiz_id');$user_id = $request->user->id;$quiz = LiveQuiz::find($quiz_id);if (!$quiz) {return json(['code' => 404, 'msg' => '趣猜不存在']);}// 获取投注统计$betStats = LiveQuizBet::where('quiz_id', $quiz_id)->field('option, count(*) as bet_count, sum(amount) as total_amount')->group('option')->select();$stats = ['option_a' => ['bet_count' => 0, 'total_amount' => 0],'option_b' => ['bet_count' => 0, 'total_amount' => 0]];foreach ($betStats as $stat) {if ($stat['option'] == 0) {$stats['option_a'] = ['bet_count' => $stat['bet_count'],'total_amount' => $stat['total_amount']];} else {$stats['option_b'] = ['bet_count' => $stat['bet_count'],'total_amount' => $stat['total_amount']];}}// 获取用户投注$userBet = LiveQuizBet::where('quiz_id', $quiz_id)->where('user_id', $user_id)->find();$quiz->stats = $stats;$quiz->user_bet = $userBet;return json(['code' => 200, 'msg' => 'success', 'data' => $quiz]);}// 广播消息方法private function broadcastQuizCreate($quiz){// 这里实现WebSocket或其它方式的消息广播// 实际项目中可以使用Swoole、Workerman或第三方推送服务}private function broadcastBet($live_id, $data){// 广播投注消息}private function broadcastSettle($live_id, $data){// 广播开奖消息}
}
前端Vue.js实现
主播端组件 AnchorQuizPanel.vue
<template><div class="quiz-panel"><h3>发起趣猜</h3><el-form :model="quizForm" :rules="rules" ref="quizForm" label-width="100px"><el-form-item label="趣猜主题" prop="title"><el-input v-model="quizForm.title" placeholder="例如:本场比赛哪队会获胜?"></el-input></el-form-item><el-form-item label="选项A" prop="option_a"><el-input v-model="quizForm.option_a" placeholder="例如:主队"></el-input></el-form-item><el-form-item label="选项B" prop="option_b"><el-input v-model="quizForm.option_b" placeholder="例如:客队"></el-input></el-form-item><el-form-item label="赔率A" prop="odds_a"><el-input-number v-model="quizForm.odds_a" :min="1" :step="0.1" :precision="2"></el-input-number></el-form-item><el-form-item label="赔率B" prop="odds_b"><el-input-number v-model="quizForm.odds_b" :min="1" :step="0.1" :precision="2"></el-input-number></el-form-item><el-form-item label="截止时间" prop="end_time"><el-date-pickerv-model="quizForm.end_time"type="datetime"placeholder="选择截止时间":picker-options="pickerOptions"></el-date-picker></el-form-item><el-form-item><el-button type="primary" @click="submitQuiz">发起趣猜</el-button></el-form-item></el-form><div class="active-quiz-list" v-if="activeQuizzes.length > 0"><h3>进行中的趣猜</h3><div class="quiz-item" v-for="quiz in activeQuizzes" :key="quiz.id"><div class="quiz-title">{{ quiz.title }}</div><div class="quiz-options"><span class="option-a">{{ quiz.option_a }} (赔率:{{ quiz.odds_a }})</span><span class="vs">VS</span><span class="option-b">{{ quiz.option_b }} (赔率:{{ quiz.odds_b }})</span></div><div class="quiz-endtime">截止时间: {{ formatTime(quiz.end_time) }}</div><div class="quiz-stats"><span>A: {{ quiz.stats.option_a.bet_count }}人投注, {{ quiz.stats.option_a.total_amount }}币</span><span>B: {{ quiz.stats.option_b.bet_count }}人投注, {{ quiz.stats.option_b.total_amount }}币</span></div><el-button type="success" size="small" @click="settleQuiz(quiz.id, 0)":disabled="quiz.end_time > (Date.now()/1000)">开奖: {{ quiz.option_a }}</el-button><el-button type="danger" size="small" @click="settleQuiz(quiz.id, 1)":disabled="quiz.end_time > (Date.now()/1000)">开奖: {{ quiz.option_b }}</el-button></div></div></div>
</template><script>
import { createQuiz, settleQuiz, getActiveQuizzes } from '@/api/liveQuiz';export default {props: {liveId: {type: Number,required: true}},data() {return {quizForm: {live_id: this.liveId,title: '',option_a: '',option_b: '',odds_a: 1.8,odds_b: 1.8,end_time: new Date(Date.now() + 30 * 60 * 1000) // 默认30分钟后截止},rules: {title: [{ required: true, message: '请输入趣猜主题', trigger: 'blur' }],option_a: [{ required: true, message: '请输入选项A', trigger: 'blur' }],


相关文章:
体育直播系统趣猜功能开发技术实现方案
功能概述 趣猜功能是“东莞梦幻网络科技”体育直播系统源码中的互动功能,主播可以发起竞猜题目,观众使用虚拟货币进行投注,增加直播间的互动性和趣味性。所有货币均为虚拟货币,通过系统活动获取,不可充值提现。 数据…...
33.[前端开发-JavaScript基础]Day10-常见事件-鼠标事件-键盘事件-定时器-案例
1 window定时器 window定时器方法 setTimeout的使用 setInterval的使用 2 轮播消息提示 案例实战一 – 轮播消息提示 3 关闭隐藏消息 案例实战二 – 关闭隐藏消息 4 侧边栏展示 案例实战三 – 侧边栏展示 5 tab切换实现 案例实战四 – 登录框(作业)…...
C# 多标签浏览器 谷歌内核Csharp
采用框架 :FBrowserCEF3lib 视频演示:点我直达 成品下载: https://wwms.lanzouo.com/iYOd42rl8vje...
如何同步fork的更新
当你fork了一个代码仓库后,要将其与原始源码保持同步,可以按照以下步骤进行操作: 1. 添加原始仓库作为远程源 在本地命令行中,进入到你fork后的代码仓库目录,然后使用以下命令添加原始仓库(通常称为upstr…...
如何从0设计开发一款JS-SDK
一、前言 前端SDK是什么?前端SDK是为了帮助前端实现特定需求,而向开发者暴露的一些JS-API的集合,规范的SDK包括若干API实现、说明文档等 前端SDK其实很常见了,比如: UI组件库:通过封装一系列组件ÿ…...
linux实现rsync+sersync实时数据备份
1.概述 rsync(Remote Sync) 是一个Unix/linux系统下的文件同步和传输工具 2.端口和运行模式 tcp/873 采用C/S模式(客户端/服务器模式) 3.特点 可以镜像保存整个目录和文件第一次全量备份(备份全部的文件),之后是增量备份(只备份变化的文件) 4. 数…...
【计算机网络】计算机网络协议、接口与服务全面解析——结合生活化案例与图文详解
协议、接口与服务 导读一、协议1.1 定义1.2 组成 二、接口三、服务3.1 定义3.2 服务与协议的区别3.3 分类3.3.1 面向连接服务于无连接服务3.3.2 可靠服务和不可靠服务3.3.3 有应答服务和无应答服务 结语 导读 大家好,很高兴又和大家见面啦!!…...
51c自动驾驶~合集26
我自己的原文哦~ https://blog.51cto.com/whaosoft/11968755 #大模型/Sora/世界模型之间是什么关系 1 什么是大模型 人工智能大模型(Artificial Intelligence Large Model,简称AI大模型)是指具有庞大的参数规模和复杂程度的机器学习模…...
【汽车传感系统架构:借助传感获取安全】
为了将车辆自动化提升到一个新的水平,设计人员研究了 LiDAR 等传感器选项的权衡,并着眼于传感系统架构。 本文引用地址:https://www.eepw.com.cn/article/202503/468584.htm 每年,约有 120 万人死于道路交通事故,还有…...
【NUUO 摄像头】(弱口令登录漏洞)
漏洞简介:NUUO 是NUUO公司的一款小型网络硬盘录像机设备。 NUUO NVRMini2 3.0.8及之前版本中存在后门调试文件。远程攻击者可通过向后门文件handle_site_config.php发送特定的请求利用该漏洞执行任意命令。 1.Fofa搜索语句: 在Fofa网站,搜索&…...
论文阅读笔记:Denoising Diffusion Probabilistic Models (3)
论文阅读笔记:Denoising Diffusion Probabilistic Models (1) 论文阅读笔记:Denoising Diffusion Probabilistic Models (2) 论文阅读笔记:Denoising Diffusion Probabilistic Models (3) 4、损失函数逐项分析 可以看出 L L L总共分为了3项…...
【设计模式】抽象工厂模式(含与工厂方法模式的对比)
本期我们来学习一下设计模式之抽象工厂模式,在软件开发中,工厂模式 和 抽象工厂模式 都用于创建对象,但它们的应用场景和实现方式有所不同。本文将基于 C 代码,分析抽象工厂模式的实现,并对比其与工厂方法模式的区别。…...
消息队列保证最终一致性的优势
消息队列保证最终一致性的优势 使用消息队列(如Kafka、RabbitMQ等)来实现MySQL和Redis之间的最终一致性,具有以下几个显著优势: 1. 解耦系统组件 降低系统耦合度:生产者(MySQL更新)和消费者&…...
IDEA转战Trae AI IED配置
Trae Ai 的前身是vscode IDEA转战Trae AI IED配置 1.安装java相关的插件 2、安装spring相关的插件 3.配置maven环境 打开 Trae AI IDE -> 首选项 -> 设置 -> Editor 设置 ⚠️配置方式有两种 setting.json文件中直接编辑(推荐)界面设置 方案…...
再学:区块链基础与合约初探 EVM与GAS机制
目录 1.区块链是什么 2.remix 3.账户 4.以太坊三种交易 5.EVM 6.以太坊客户端节点 7.Gas费用 8.区块链浏览器 1.区块链是什么 只需要检验根节点 Merkel根是否有更改,就不用检查每个交易是否有更改。方便很多。 2.remix 3.账户 如果交易失败的话&…...
Nextjs15 - middleware的使用
nextjs 官方文档(current branch 对应如下文档) Middlewarepath-to-regexp 本专栏内容均可在Github:test_05/Middleware 找到 一、middleware 基本使用 中间件允许您在请求完成之前运行代码。然后,根据传入的请求,您…...
PHP If...Else 语句详解
PHP If...Else 语句详解 引言 PHP 是一种流行的服务器端脚本语言,常用于开发动态网站和应用程序。在 PHP 编程中,条件语句是编程逻辑的基础,其中 if...else 语句是最基本且最常用的条件语句之一。本文将详细介绍 PHP 的 if...else 语句&…...
Django之旅:第六节--mysql数据库操作增删改查(二)
前提条件(models.py已经设置好): from django.db import mmodelsclass UserInfo(models.Model):namemodels.CharFIeld(max_length32)passwordmodels.CharFIeld(max_length64)#agemodels.IntegerFIeld()操作数据语法(在views.py文件࿰…...
【SUNO】【AI作词】【提示词】
仿写歌词提示词模板(升级版) 一、仿写目标 风格定位 音乐风格: [填写目标风格,如:民谣/流行/古风/电子/爵士等]参考案例:如《成都》的叙事民谣,《孤勇者》的励志流行。 情感基调: […...
边缘计算 vs. 云计算,谁才是工业物联网的未来?
前言 在物联网(IoT)飞速发展的今天,边缘计算正在彻底改变数据的处理、存储和分析方式。传统的IoT设备数据通常需要发送到云端进行处理,但随着设备数量的激增,这种模式在延迟、带宽和安全性方面暴露出诸多局限。边缘计…...
【Qt】QByteArray详解
QByteArray 是 Qt 框架中用于处理原始字节数据的核心类,其实质可以概括为以下几点: 1. 底层数据结构 • 连续内存块:存储一段连续的字节数据(char*),类似 std::vector<char>,但针对 Qt 框…...
leetcode.189.轮转数组
第一次全反转,第二次反转前k个,第三次反转后n-k个 需要注意的是向又轮转k个时,如果超出数组长度,要对其进行取模运算才是正确的向右轮转个数 class Solution { private:void rotate(vector<int>& nums,int start,int …...
OCR 识别案例
OCR 识别案例 注意点:输入图像尺寸比例尽量和参与模型训练的数据集比例相似,识别效果会更好。 1、pytesseract Pytesseract是一个Python的光学字符识别(OCR)工具,它作为Tesseract OCR引擎的封装,允许你在…...
微信 MMTLS 协议详解(五):加密实现
常用的解密算法,对称非对称 加密,密钥协商, 带消息认证的加解密 #生成RSA 密钥对 void GenerateRsaKeypair(std::string& public_key,std::string& private_key) {RSA* rsa RSA_new();BIGNUM* bn BN_new();// 生成 RSA 密钥对BN_s…...
Mybatis配置文件解析(详细)
引言 在了解Mybatis如何帮助客户进行数据的存取后,便对Mybatis的配置文件起了兴趣,在查阅官方文档后,总结了平时能用到的配置,希望能对大家有帮助 1.核心配置文件 主要是指Mybatis-config.xml中 其包含了会深深影响Mybatis行为…...
有额外限制的 bellman_ford 算法
题目链接 1.有限制的 B e l l m a n _ F o r d Bellman\_Ford Bellman_Ford 时间复杂度: O ( N ∗ M ) O(N*M) O(N∗M) 在传统的 B e l l m a n _ F o r d Bellman\_Ford Bellman_Ford 中,可以处理边数不大于 K K K 条边的最短距离 但我们只要加一条限制(实际…...
深度剖析 Spring 源码 性能优化:核心原理与最佳实践
深度剖析 Spring 源码 & 性能优化:核心原理与最佳实践 🚀 Spring 框架 作为 Java 生态的核心技术,广泛应用于企业级开发。但很多开发者只会“用”Spring,而不深入其内部原理,导致无法高效排查问题 & 进行性能优…...
【BFS】《单源、多源 BFS:图搜索算法的双生力量》
文章目录 前言单源BFS例题一、迷宫中离入口最近的出口二、 最小基因变化三、单词接龙四、为高尔夫比赛砍树 多源BFS例题一、 01 矩阵二、飞地的数量三、地图中的最高点四、地图分析 结语 前言 什么是单源、多源BFS算法问题呢? BFS(Breadth - First Sear…...
【2025】基于springboot+vue的医院在线问诊系统设计与实现(源码、万字文档、图文修改、调试答疑)
基于Spring Boot Vue的医院在线问诊系统设计与实现功能结构图如下: 课题背景 随着互联网技术的飞速发展和人们生活水平的不断提高,传统医疗模式面临着诸多挑战,如患者就医排队时间长、医疗资源分配不均、医生工作压力大等。同时,…...
【前端】原生项目与框架项目区别
不定期更新,建议关注收藏点赞。 使用 HTML CSS JS 和 Vue 或 React 开发的项目各有其优势与不足,适用于不同的场景。目前基本上都采用框架, 总结 何时选择 HTML CSS JS: 适用于 小型项目、简单静态页面、不需要复杂交互 或 …...
