首页 > 应用开发 > IT综合 > 体育直赛事播系统开发:趣猜功能技术实现方案
功能概述
趣猜功能是“东莞梦幻网络科技”体育直播系统源码中的互动功能,主播可以发起竞猜题目,观众使用虚拟货币进行下注,增加直播间的互动性和趣味性。所有货币均为虚拟货币,通过系统活动获取,不可充值提现。
数据库设计 (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
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)
{
// 广播开奖消息
}
}
<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' }],
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70044681/viewspace-3078975/ ,如需转载,请注明出处,否则将追究法律责任。