体育直播系统趣猜功能开发技术实现方案

news2025/4/1 19:08:52

功能概述

趣猜功能是“东莞梦幻网络科技”体育直播系统源码中的互动功能,主播可以发起竞猜题目,观众使用虚拟货币进行投注,增加直播间的互动性和趣味性。所有货币均为虚拟货币,通过系统活动获取,不可充值提现。

数据库设计 (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-picker
          v-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' }],

在这里插入图片描述在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

33.[前端开发-JavaScript基础]Day10-常见事件-鼠标事件-键盘事件-定时器-案例

1 window定时器 window定时器方法 setTimeout的使用 setInterval的使用 2 轮播消息提示 案例实战一 – 轮播消息提示 3 关闭隐藏消息 案例实战二 – 关闭隐藏消息 4 侧边栏展示 案例实战三 – 侧边栏展示 5 tab切换实现 案例实战四 – 登录框&#xff08;作业&#xff09;…

C# 多标签浏览器 谷歌内核Csharp

采用框架 &#xff1a;FBrowserCEF3lib 视频演示&#xff1a;点我直达 成品下载&#xff1a; https://wwms.lanzouo.com/iYOd42rl8vje

如何从0设计开发一款JS-SDK

一、前言 前端SDK是什么&#xff1f;前端SDK是为了帮助前端实现特定需求&#xff0c;而向开发者暴露的一些JS-API的集合&#xff0c;规范的SDK包括若干API实现、说明文档等 前端SDK其实很常见了&#xff0c;比如&#xff1a; UI组件库&#xff1a;通过封装一系列组件&#xff…

linux实现rsync+sersync实时数据备份

1.概述 rsync(Remote Sync) 是一个Unix/linux系统下的文件同步和传输工具 2.端口和运行模式 tcp/873 采用C/S模式&#xff08;客户端/服务器模式&#xff09; 3.特点 可以镜像保存整个目录和文件第一次全量备份(备份全部的文件),之后是增量备份(只备份变化的文件) 4. 数…

【计算机网络】计算机网络协议、接口与服务全面解析——结合生活化案例与图文详解

协议、接口与服务 导读一、协议1.1 定义1.2 组成 二、接口三、服务3.1 定义3.2 服务与协议的区别3.3 分类3.3.1 面向连接服务于无连接服务3.3.2 可靠服务和不可靠服务3.3.3 有应答服务和无应答服务 结语 导读 大家好&#xff0c;很高兴又和大家见面啦&#xff01;&#xff01;…

51c自动驾驶~合集26

我自己的原文哦~ https://blog.51cto.com/whaosoft/11968755 #大模型/Sora/世界模型之间是什么关系 1 什么是大模型 人工智能大模型&#xff08;Artificial Intelligence Large Model&#xff0c;简称AI大模型&#xff09;是指具有庞大的参数规模和复杂程度的机器学习模…

【NUUO 摄像头】(弱口令登录漏洞)

漏洞简介&#xff1a;NUUO 是NUUO公司的一款小型网络硬盘录像机设备。 NUUO NVRMini2 3.0.8及之前版本中存在后门调试文件。远程攻击者可通过向后门文件handle_site_config.php发送特定的请求利用该漏洞执行任意命令。 1.Fofa搜索语句&#xff1a; 在Fofa网站&#xff0c;搜索&…

【设计模式】抽象工厂模式(含与工厂方法模式的对比)

本期我们来学习一下设计模式之抽象工厂模式&#xff0c;在软件开发中&#xff0c;工厂模式 和 抽象工厂模式 都用于创建对象&#xff0c;但它们的应用场景和实现方式有所不同。本文将基于 C 代码&#xff0c;分析抽象工厂模式的实现&#xff0c;并对比其与工厂方法模式的区别。…

IDEA转战Trae AI IED配置

Trae Ai 的前身是vscode IDEA转战Trae AI IED配置 1.安装java相关的插件 2、安装spring相关的插件 3.配置maven环境 打开 Trae AI IDE -> 首选项 -> 设置 -> Editor 设置 ⚠️配置方式有两种 setting.json文件中直接编辑&#xff08;推荐&#xff09;界面设置 方案…

再学:区块链基础与合约初探 EVM与GAS机制

目录 1.区块链是什么 2.remix ​3.账户​ ​4.以太坊三种交易​ 5.EVM 6.以太坊客户端节点 ​7.Gas费用 8.区块链浏览器 1.区块链是什么 只需要检验根节点 Merkel根是否有更改&#xff0c;就不用检查每个交易是否有更改。方便很多。 2.remix 3.账户 如果交易失败的话&…

Nextjs15 - middleware的使用

nextjs 官方文档&#xff08;current branch 对应如下文档&#xff09; Middlewarepath-to-regexp 本专栏内容均可在Github&#xff1a;test_05/Middleware 找到 一、middleware 基本使用 中间件允许您在请求完成之前运行代码。然后&#xff0c;根据传入的请求&#xff0c;您…

边缘计算 vs. 云计算,谁才是工业物联网的未来?

前言 在物联网&#xff08;IoT&#xff09;飞速发展的今天&#xff0c;边缘计算正在彻底改变数据的处理、存储和分析方式。传统的IoT设备数据通常需要发送到云端进行处理&#xff0c;但随着设备数量的激增&#xff0c;这种模式在延迟、带宽和安全性方面暴露出诸多局限。边缘计…

leetcode.189.轮转数组

第一次全反转&#xff0c;第二次反转前k个&#xff0c;第三次反转后n-k个 需要注意的是向又轮转k个时&#xff0c;如果超出数组长度&#xff0c;要对其进行取模运算才是正确的向右轮转个数 class Solution { private:void rotate(vector<int>& nums,int start,int …

OCR 识别案例

OCR 识别案例 注意点&#xff1a;输入图像尺寸比例尽量和参与模型训练的数据集比例相似&#xff0c;识别效果会更好。 1、pytesseract Pytesseract是一个Python的光学字符识别&#xff08;OCR&#xff09;工具&#xff0c;它作为Tesseract OCR引擎的封装&#xff0c;允许你在…

Mybatis配置文件解析(详细)

引言 在了解Mybatis如何帮助客户进行数据的存取后&#xff0c;便对Mybatis的配置文件起了兴趣&#xff0c;在查阅官方文档后&#xff0c;总结了平时能用到的配置&#xff0c;希望能对大家有帮助 1.核心配置文件 主要是指Mybatis-config.xml中 其包含了会深深影响Mybatis行为…

【BFS】《单源、多源 BFS:图搜索算法的双生力量》

文章目录 前言单源BFS例题一、迷宫中离入口最近的出口二、 最小基因变化三、单词接龙四、为高尔夫比赛砍树 多源BFS例题一、 01 矩阵二、飞地的数量三、地图中的最高点四、地图分析 结语 前言 什么是单源、多源BFS算法问题呢&#xff1f; BFS&#xff08;Breadth - First Sear…

【2025】基于springboot+vue的医院在线问诊系统设计与实现(源码、万字文档、图文修改、调试答疑)

基于Spring Boot Vue的医院在线问诊系统设计与实现功能结构图如下&#xff1a; 课题背景 随着互联网技术的飞速发展和人们生活水平的不断提高&#xff0c;传统医疗模式面临着诸多挑战&#xff0c;如患者就医排队时间长、医疗资源分配不均、医生工作压力大等。同时&#xff0c;…

STM32基础教程——PWM驱动舵机

目录 前言 技术实现 原理图 接线图 代码实现 内容要点 PWM基本结构 开启外设时钟 配置GPIO端口 配置时基单元 初始化输出比较单元 调整PWM占空比 输出比较通道重映射 舵机角度设置 实验结果 问题记录 前言 舵机&#xff08;Servo&#xff09;是一种位置&#xff…

odata 搜索帮助

参考如下链接&#xff1a; FIORI ELement list report 细节开发&#xff0c;设置过滤器&#xff0c;搜索帮助object page跳转等_fiori element label 变量-CSDN博客 注&#xff1a;odata搜索帮助可以直接将值带出来&#xff0c;而不需要进行任何的重定义 搜索帮助metedata配置…

Docker基本命令VS Code远程连接

Docker基本命令 创建自己的docker容器&#xff1a;docker run --net host --name Container_name --gpus all --shm-size 1t -it -v Your_Path:Your_Dir mllm:mac /bin/bashdocker run&#xff1a;用于创建并启动一个新容器-name&#xff1a;为当前新建的容器命名-gpus&#x…