简介熊猫电竞赏金电竞系统源码是一套面向电竞平台运营方的完整双端解决方案涵盖APP与H5端支持进行运营级平台搭建。系统围绕赏金赛模式设计用户报名参赛、获胜后获得奖金平台可通过比赛抽水、会员充值、手续费等方式盈利。内置金币赛、赏金赛、VIP赛等赛事可开王者荣耀、和平精英比赛支持1v1、单排、双排组、战队排及QQ区、微信区既能满足玩家娱乐赚钱需求也适合开发者研究赛事系统架构。资源包共2000个文件约269.4MB以PHP、Vue、JavaScript、HTML为主要代码类型其中PHP处理后端业务与支付配置Vue与JS实现前端交互和页面渲染SQL文件包含数据库结构此外还附带APK安装包、图标资源、字体样式等覆盖前后端完整代码及部署要素。目前已有363人学习浏览适合具备一定开发基础的运营者或开发者快速搭建或二开此类电竞赏金赛平台。1. 电竞赏金赛系统为什么自建比外包撮合更划算电竞赏金赛的商业模型表面是“打比赛赢奖金”实际赚的是资金流报名费沉淀、比赛抽水、手续费每一环都依赖系统精准结算。用第三方撮合最怕的就是结算延迟——奖金到不了账用户下一场就流失。熊猫电竞把赛事引擎、钱包、支付宝支付放在同一个 ThinkPHP 后端APP 与 H5 共用接口结算能到分钟级。适合三类人想快速跑通赛事 MVP 的创业者有服务器和域名、准备做垂直电竞平台的团队需要在竞品源码上做二开的外包开发者。前提是熟悉 PHP 与 uni-app并且清楚抽水盈利模式必须配合合规资质。下面从代码结构开始拆逐层讲搭建步骤和支付链路中最容易翻车的地方。2. ThinkPHP 后端与 uni-app 双端的代码结构解析2.1 application 目录赛事模块与支付模块的分层拿到源码先看根目录/application是标准 ThinkPHP 应用目录controller、model、service 三层基本齐全。对比同类系统会发现这个项目把赛事逻辑单独拆到application/api/controller后台管理端放在application/admin说明作者设计时就把用户端接口和管理端权限隔离开了。这个隔离对运营级部署很关键——赛事接口被人刷请求时后台不会跟着暴露。常见做法是把金币赛、赏金赛、VIP 赛做成独立控制器再抽一个公共的MatchService处理“报名→匹配→结算”的公共流程。例如用户报名接口通常长这样// application/api/controller/Match.php 中典型的动作分发写法 public function join() { $type $this-request-post(type/d, 1); // 1 金币赛 2 赏金赛 3 VIP赛 $mode $this-request-post(mode/d, 1); // 1v1 单排 双排组 战队排 $money $this-request-post(money/f, 0); if ($type 2 $money 0) { $this-error(赏金赛必须填写参赛金额); } $service new MatchService($type, $mode); $res $service-join($this-uid, $money); $res ? $this-success(报名成功, $res) : $this-error($service-getError()); }$this-request-post(type/d, 1)里的/d是强转整型/f转浮点这是 ThinkPHP 的自动类型转换写法。入口处做类型约束能挡住“金额传字符串绕过比较”这类低级注入二开时不要图省事换成input()裸取参。MatchService内部建议按赛事类型查对应配置而不是堆if else否则加一种赛事要改三处。2.2 前端双端复用uni-app 编译 H5 与 App资源包里的__UNI__9086CB1_20210322215454.apk和__UNI__9086CB1_cm.apk两个安装包__UNI__前缀是 HBuilderX 云打包产物的典型标识_cm.apk一般是自定义调试基座用于带原生插件联调。源码层面前端是 uni-app 工程pages下按业务拆页面pages/ index/index # 首页赛事列表 match/detail # 赛事详情与报名 match/room # 房间对战与战绩上传 user/wallet # 余额、充值、提现为什么要双端复用H5 负责拉新微信里点开链接就能报名App 负责留存推送、拉起支付宝、悬浮窗提醒都比 H5 稳定。两套端共用一套后端接口H5 改版可以随时上线App 才走应用商店审核。拿到源码后先改manifest.json里的 appid替换成你自己在 DCloud 后台创建的应用标识否则直接云打包会报 appid 冲突utils/request.js里的 baseURL 也要一并进行替换。2.3 数据表与奖池的资金流设计资金流转比赛事状态更值得先看。核心表大致如下表名作用关键字段matchs赛事场次match_type / entry_fee / prize_pool / commission_ratematch_apply报名记录uid / match_id / status / pay_order_nomatch_room房间与对战分组room_no / mode / game_zone / statususer_wallet用户钱包balance / freeze_balance / total_incomemoney_log资金流水uid / amount / type / biz_no / create_timepay_orders支付订单order_no / out_trade_no / trade_status / notify_data这个设计里最值得抄的一点是user_wallet把balance可用余额和freeze_balance冻结金额拆开了。用户报名赏金赛时先从 balance 把参赛费划到 freeze_balance比赛结束仲裁通过后才解冻并发放奖金。这样“扣钱”和“加钱”之间始终保持一个中间态不会因为推荐流程中断出现负余额。另一个容易被忽视的是money_log的biz_no关联字段。任何一次余额变动都要绑定业务单据号排查对账问题时直接按单据号拉全链路SELECT * FROM money_log WHERE uid 10001 AND biz_no MATCH20250615001 ORDER BY id ASC;如果同一个人同一笔biz_no出现了两次扣款基本可以断定是缺少幂等约束。运营级系统里这个约束建议直接做成唯一索引UNIQUE KEY uniq_biz (uid, biz_no, type)比在代码里判断有没有记录更可靠。3. 从服务器到上线熊猫电竞源码的完整搭建流程3.1 环境选型为什么 LNMP 是快速起跑最优解设备需求只有“服务器域名”对于 ThinkPHP 5 系项目我一般用 Nginx 1.18 PHP 7.4 MySQL 5.7。PHP 7.4 在兼容性和性能之间最平衡别一上来就装 PHP 8部分第三方支付 SDK 会在 PHP 8 下直接抛 deprecated 警告虽然能跑但日志里全是噪声。用户集中在晚上打比赛起步买 2 核 4G 云主机就够MySQL 和 PHP-FPM 同机部署日活过千再考虑拆库。域名规划上主域名给后端 API再备一个二级域名部署 H5 前端。App 直接请求 API 域名。支付宝异步通知回调地址必须是外网能访问的域名不能用 IP也不能挂未备案端口这一点在绑定域名时就要确认清楚。3.2 伪静态与运行目录配置ThinkPHP 5 的入口文件在/public/index.phpNginx 的 root 要指向 public 目录否则后端路径会直接暴露。伪静态配置如下server { listen 80; server_name api.example.com; root /var/www/pandaelec/public; index index.php index.html; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~ \.(js|css|png|jpg)$ { expires 7d; access_log off; } }rewrite ^(.*)$ /index.php?s$1 last;是 ThinkPHP 5 的经典 URL 重写把所有非真实文件请求交给入口分发。静态资源缓存 7 天是为 H5 首屏考虑否则每次打开都重新拉bootstrap.min.css和main.css弱网环境首屏会明显变慢。后端如果配置了 HTTPS还要把fastcgi_param HTTPS on;加上否则生成支付链接时协议判断会出错。3.3 数据库初始化与配置调整把资源包里的 sql 文件导入 MySQL再修改/application/database.phpreturn [ type mysql, hostname 127.0.0.1, database panda_esport, username panda_user, password 你的强密码, hostport 3306, prefix panda_, ];这里要注意prefix表前缀必须跟 sql 文件里实际一致。如果导入后发现原库表名是tp_matchs这种带前缀的就把配置改成tp_不要照抄网上文章写panda_。导入后逐表确认引擎统一用 InnoDBmatch_apply和pay_orders这种高频写入表必须支持事务MyISAM 在并发结算时会锁表多人同时领奖直接卡死。3.4 H5 编译与 App 包的处理顺序H5 端用 HBuilderX 导入 uni-app 工程改完utils/request.js的接口地址后发行到 H5把生成的静态目录部署到二级域名。这里有个顺序问题先改接口地址再发行不要发行后再替换打包产物里的字符串后者容易漏掉多处拼接地址。App 端如果只是功能验证可以直接装__UNI__9086CB1_20210322215454.apk正式发布建议重新云打包。旧包里内置的是作者的 appid、签名证书和包名应用市场上架前必须换成自己的否则会被判定为侵权或审核拒绝。apkurl这个文件一般是前端读取最新安装包下载地址的配置很多同类系统把版本号、下载链接写在这里后端需要更新 App 时只改文件内容前端检测到新版本就引导下载比每次发版走应用市场灵活也方便内测分发。提示certdata文件大多是客户端证书或支付敏感数据不要放进 Web 根目录更不能提交到 Git 仓库。很多二开翻车案例都是因为把证书目录当静态资源公开导致私钥泄露。4. 赏金赛机制与支付宝支付对接的落地细节4.1 赛事状态机模式参数与状态流转系统支持的赛事类型包括金币赛、赏金赛、VIP 赛项目类型覆盖王者荣耀、和平精英模式有 1v1、单排、双排组、战队排区服区分 QQ 区和微信区。这些参数建议以配置表或常量的方式集中管理// application/common/const.php 中的赛事配置示例 const MATCH_TYPES [ 1 [name 金币赛, commission_rate 5, need_money 0], 2 [name 赏金赛, commission_rate 10, need_money 1], 3 [name VIP赛, commission_rate 15, need_money 1], ]; const MATCH_MODES [ 1 1v1, 2 单排, 3 双排组, 4 战队排, ]; const GAME_ZONES [ qq QQ区, wechat 微信区, ];每一场比赛的状态建议用整数字段流转1 报名待支付→2 已支付待匹配→3 已匹配待开赛→4 对战中→5 待仲裁→6 已结算另有7 已取消处理超时未支付的单子。match_apply.status用整数而不是字符串存状态查询快之外索引也更省空间。仲裁环节是最容易被忽略的用户上传战绩截图后如果直接按一方上传结果发钱刷单会非常严重。靠谱的流程是等双方都能提交设置一个倒计时窗口超时后由后台裁判账号复核或按双方证据自动判定。这个窗口时长建议做成后台可配和平精英结算慢通常比王者荣耀多 2 分钟。4.2 抽水与结算逻辑实现平台盈利来自比赛抽水、会员充值和手续费。抽水比例放在matchs.commission_rate字段按场次配置不要写死在代码里。结算时必须走单事务同时更新钱包、流水和订单状态try { Db::startTrans(); $match Db::name(matchs)-lock(true)-find($matchId); $winner Db::name(match_apply) -where(match_id, $matchId) -where(is_winner, 1) -find(); $commission round($match[prize_pool] * $match[commission_rate] / 100, 2); $winAmount $match[prize_pool] - $commission; // 参赛费已经在前一阶段从 balance 冻结这里只做解冻和入账 Db::name(user_wallet)-where(uid, $winner[uid]) -inc(balance, $winAmount)-update(); Db::name(money_log)-insert([ uid $winner[uid], amount $winAmount, type match_win, biz_no date(Ymd) . $matchId, create_time time(), ]); Db::name(match_apply)-where(id, $winner[id])-update([status 6]); Db::commit(); } catch (\Exception $e) { Db::rollback(); $this-error(结算失败: . $e-getMessage()); }lock(true)是 ThinkPHP 的悲观锁这里必须加。不加锁时两个并发请求同时读同一场次奖池可能把奖金重复发放给不同的人。biz_no用日期加赛事 ID 生成能天然保证同一场次只有一个结算流水配合唯一索引重复执行也不会发两次钱。结算后再判断是否需要短信或 App 推送通知到账这一步建议异步处理不要放在事务里。4.3 支付宝支付对接config.php 第 304 行实战支付配置集中在/application/config.php第 304 行附近打开后是一个 alipay 配置数组。把它替换成你自己的支付宝开放平台参数// application/config.php 304 行左右 alipay [ app_id 你的支付宝APPID, merchant_private_key 应用私钥用支付宝密钥工具生成的原始内容, alipay_public_key 支付宝公钥不是应用公钥, notify_url https://api.example.com/pay/notify, return_url https://h5.example.com/pages/user/wallet, sign_type RSA2, gateway https://openapi.alipay.com/gateway.do, ],最容易翻车的点是私钥填成了支付宝公钥或者填了应用公钥。打开支付宝开放平台的密钥管理merchant_private_key是你在本地用工具生成的那串原始私钥文件内容不要往里面加-----BEGIN RSA PRIVATE KEY-----之外的空行alipay_public_key是平台展示的支付宝公钥两者完全不是一个东西。配置改完后用支付宝官方验签工具先验一次能验过再继续。4.4 下单与异步通知的业务闭环发起充值支付的下单逻辑一般是这样public function createRecharge() { $userId $this-uid; $amount $this-request-post(amount/f); if ($amount 1) { $this-error(充值金额至少1元); } $orderNo $this-createOrderNo($userId); // 生成支付请求参数调用支付宝统一下单 $result $this-alipayService-createWapPay([ out_trade_no $orderNo, total_amount $amount, subject 电竞奖金充值, notify_url config(alipay.notify_url), ]); $this-success(ok, [pay_url $result, order_no $orderNo]); }支付成功与否绝不能以前端跳转的return_url为准。return_url用户可以伪造notify_url的异步通知才是支付宝服务器发来的权威数据。异步通知处理里必须校验签名、校验app_id、校验out_trade_no是本站订单、校验total_amount与订单金额一致其中任何一项不通过都要返回fail让支付宝继续重试。notify接口要保证幂等同一笔out_trade_no可能会收到多次通知处理完订单后先查订单状态如果已经是已支付就直接返回success不要再次累加用户余额。资金流水这里同样要落到money_log充值类型记为recharge和比赛奖金区分开。5. 运营级优化并发分配、回调幂等与常见排错5.1 并发匹配先锁单再进房间用户量上来后同时点击“开始匹配”的请求可能上百并发。如果直接查库里未匹配场次会出现多人同时抢到最后一个名额导致超员开赛。我常用的处理方式是 Redis 加分布式锁# 用 Redis SETNX 实现匹配锁 redis-cli SET lock:match:1v1_qq 1 NX EX 3拿到锁的请求查询空闲名额并占用没拿到锁的直接返回“匹配中请稍候”前端的按钮做 3 秒防抖。底层逻辑是“先锁后查”而不是先查再锁否则临界区永远补不上。如果不想引入 RedisMySQL 的SELECT ... FOR UPDATE也行但高峰期锁等待时间会拉长建议日活过千就换成 Redis。5.2 回调验签的常见错误对照现象原因处理方式支付成功但余额没变notify_url 填了 http 地址支付宝回调被拦截换成 https 外网地址并确认 nginx 放行 POST提示“签名验证失败”商户私钥里有多余换行或转义符检查配置从密钥工具原文拷贝并去除首尾空白部分用户反馈 H5 充值无反应微信内打开支付宝链接被拦截检测 UA引导用户右上角浏览器打开H5 页面给出提示同一订单被加了两次余额notify 接口没有做幂等先查 pay_orders 状态已支付直接返回 successH5 端在微信浏览器里拉起支付宝是个老问题支付宝 H5 支付需要调起外部 App微信内置浏览器会拦截。常见做法是检测到微信 UA 时提示用户“请点击右上角在浏览器中打开”或者引导用户使用支付宝 App 扫码。App 端则要看云打包时是否勾选了支付宝支付模块manifest.json 里没勾选真机运行时拉起支付宝会直接报未配置。5.3 排错时的两条实用命令后端日志在/runtime/log目录按日期生成出问题先看当天日志里有没有 PHP 异常# 实时跟踪支付宝回调日志 tail -f /var/www/pandaelec/runtime/log/$(date %Y%m)/$(date %d).log | grep -i notify数据库锁等待排查用这条SELECT * FROM information_schema.INNODB_TRX \G;看到长时间未提交的事务直接KILL对应的线程 ID。多数搭建失败都能归到三类目录权限不是 www 用户、数据库前缀不匹配、伪静态规则没生效。按这三条逐一排查十分钟内基本能定位到问题所在。本文还有配套的精品资源点击获取