街机超人由四个可独立开发的仓库组成,同时存在 Yii 2 旧主系统与 ThinkPHP 6 新业务系统。架构整理需要区分“源码中已经存在的运行单元”和“迁移后希望形成的边界”,不能把两个后端简单合并成一套逻辑。
物理项目与交付物
| 代码库 | 主要技术 | 源码职责 | 运行方式 |
|---|---|---|---|
jieji |
Yii 2、PHP 7、Redis、微信 SDK、phpMQTT | 平台和代理 API、用户 H5、支付通知、设备与订单、MQTT 订阅回执、收益和提现 | PHP Web 服务、MQTT 接收进程、Vue 2 静态后台 |
new_jieji |
ThinkPHP 6、多应用、Redis、微信 SDK | 游戏中心、游戏后台、抽奖、小程序、公众号、第三方授权、设备事件 Webhook 和兼容接口 | PHP-FPM、命令任务及小程序/后台构建产物 |
jjcr_mqtt_cmd |
ThinkPHP 6、phpMQTT | 接收内部投币请求并向指定设备 Topic 发布命令 | 独立轻量 HTTP 发布服务 |
eh-web-ow |
Express、Handlebars、静态资源 | 官网、产品介绍、招商加盟、新闻和关于页面 | 独立 Node.js Web 服务 |
官网不依赖交易数据库和 MQTT,不应与核心 API 共用发布目录或故障域。jjcr_mqtt_cmd 也不是完整设备平台,它只是命令发布桥;命令事实、业务订单和设备回执仍由主系统管理。
总体拓扑
flowchart TB Admin[Vue 2 平台后台] --> YiiAdmin[Yii admin API] Agent[代理端] --> YiiAgent[Yii agent API] H5[微信 H5] --> YiiHtml[Yii html] Mini[抽奖小程序] --> Lottery[ThinkPHP lottery] Game[游戏中心] --> GameAPI[game_center] GameAdmin[游戏管理端] --> GMS[game_center_admin] Wechat[公众号 / 微信开放平台] --> Third[third / AppServer] YiiAdmin --> Domain[设备 / 代理 / 订单 / 收益] YiiAgent --> Domain YiiHtml --> Domain Lottery --> Activity[游戏 / 抽奖 / 幸运币 / 积分] GameAPI --> Activity Domain --> DB[(MySQL)] Activity --> DB Domain --> Cmd[MQTT 命令记录] Cmd --> Bridge[jjcr_mqtt_cmd / Publisher] Bridge --> Broker[MQTT Broker] Broker --> Device[街机 / 纸巾设备] Device --> Hook[MQTT 回执 / Broker Webhook] Hook --> Domain Site[Express 官网] --> Visitor[公开访客]
旧 Yii 主系统
jieji 是当前目录中业务覆盖最完整的系统,模块划分体现了不同调用方的信任边界。
| 模块 | 调用方 | 主要能力 |
|---|---|---|
admin/api |
平台运营后台 | 管理员、权限、代理、渠道、设备、订单、统计、公众号和提现 |
agent/api |
代理商 | 登录、设备、渠道、场所、收益和提现 |
html |
微信 H5 用户 | 设备页面、微信登录、购买游戏币、订单和钱包 |
notify |
支付平台与内部设备服务 | 支付结果、设备查询、价格查询和远程出币 |
mqtt |
MQTT 订阅进程 | 设备状态、命令回执、在线时长和收益确认 |
Vue 2 管理端页面覆盖设备和纸巾机、在线时长、用户、公众号、游戏订单、纸巾订单、代理商、虚拟代理、提现、权限与统计。后台只负责提交操作,设备归属、订单金额和收益规则必须由 API 再次校验。
新 ThinkPHP 多应用
new_jieji 并不是对旧系统所有功能的一次性重写,而是新业务、设备接收入口和部分兼容接口的组合。
| 应用 | 主要职责 | 数据边界 |
|---|---|---|
game_center |
游戏列表、分类、轮播、详情、截图和礼包分类 | 对用户提供只读游戏内容和礼包入口 |
game_center_admin |
游戏、截图、礼包分类和兑换码管理 | 仅允许后台管理员操作 |
lottery |
抽奖活动、幸运币、积分、红包、礼物领取、积分商城、公众号与小程序 | 所有余额变化都需要流水和幂等业务号 |
third |
微信开放平台授权、回调、Ticket 和子菜单 | 验签、重放保护并隔离平台凭据 |
mqtt |
接收 Broker Webhook,更新在线状态、设备异常和命令回执 | 只信任合法 Broker 来源与设备身份 |
jieji_admin / backup |
通知、代理和设备等兼容或辅助接口 | 应限制为内部网络并明确停用计划 |
command |
抽奖等计划任务 | 带锁运行并允许安全重试 |
新系统仍直接访问不少旧表命名空间,说明它处于共享数据库迁移阶段。维护时需要建立数据所有权清单:每张订单、设备、用户、活动和资金表只能指定一套主写逻辑。
核心领域模型
| 领域 | 主要对象 | 关键规则 |
|---|---|---|
| 身份与权限 | 平台管理员、权限组、规则、代理、微信用户、应用绑定用户 | 平台、代理、用户和第三方应用使用不同会话 |
| 渠道与场所 | 渠道、公众号、代理层级、设备位置 | 设备归属变更保留历史,收益按下单时快照计算 |
| 设备 | IMEI、设备类型、激活、在线状态、纸巾状态、在线日志 | IMEI 唯一;实时状态与设备档案分开 |
| 交易 | 订单、订单明细、币价、用户游戏币、出币订单 | 支付成功不等于设备已经出币 |
| 设备命令 | MQTT 命令、业务类型、业务 ID、请求和回执时间 | 每条命令有平台 ID,设备回执只处理一次 |
| 财务 | 代理收益流水、可提现金额、银行卡/微信、提现申请 | 余额由流水解释,不能只更新汇总字段 |
| 游戏内容 | 游戏、分类、截图、礼包分类和兑换码 | 兑换码领取必须原子占用并记录用户 |
| 活动增长 | 抽奖专区、参与记录、幸运币、积分、红包和礼物领取 | 参加、开奖、领取和退回分别建模 |
设备身份与状态
设备以 IMEI 作为协议侧身份,并记录代理、渠道、场所、类型、经纬度、激活状态和在线状态。源码同时支持游戏机与纸巾机:游戏机接收币数命令,纸巾机接收出纸命令并报告正常、卡纸或缺纸。
设备在线状态来自 MQTT 连接事件、遗嘱消息或业务心跳,是随时间变化的运行投影;设备归属和激活属于持久业务事实。在线日志记录开始和结束时间,可以汇总在线时长,但不能仅凭一个布尔字段生成历史报表。
Broker Webhook 入口需要校验来源签名、Topic、clientid 与设备 IMEI 的一致性。设备首次连接时可以进入待注册状态,但不能因为连接成功就自动获得业务权限或绑定代理商。
MQTT 命令模型
发送设备命令前,系统先写 MQTT 命令记录,包含 IMEI、请求内容、请求时间、关联业务类型和业务 ID,然后把命令 ID 与指令发布到设备 Topic。源码中的关联类型区分测试、游戏币订单、充电订单、独立出币订单和出纸订单。
设备回执带回命令 ID 和执行结果。接收端根据命令 ID 找到原记录,校验回执设备与原 IMEI 一致,并只在 response_time 尚未写入时处理成功结果。这样重复消息不会再次完成订单或重复结算。
当前发布逻辑在多个仓库中出现,且连接配置曾直接写入源码。维护时应把 Broker 地址和凭据移入密钥配置,轮换旧凭据,并用一个设备网关统一发布协议、Topic 规则、超时和重试。
游戏币购买与余额投币
系统存在两条相邻但不同的出币路径:
购买后直接出币
用户在设备页面选择币价,系统创建待支付订单并调用微信支付。支付回调确认金额和设备后,按价格快照得到币数,创建命令并向该设备发布。设备成功回执后,订单才能进入已完成状态并触发收益结算。
账户余额投币
用户也可以先购买或获得代理体系下的游戏币余额,再在现场选择设备投出一枚。服务端校验用户、代理归属、设备在线与激活状态,原子扣减余额并创建独立出币订单,然后发布 MQTT 命令。
余额投币如果设备最终失败,需要有明确的退币或人工补偿流程。仅在 HTTP 发布成功后提交扣币事务仍不等于设备已经执行,应以设备回执或超时状态完成最终确认。
代理收益与提现
订单记录代理、设备、场所和渠道,成功后按代理层级与分成比例写 ArcAgentIncomeLog。汇总收益字段用于快速展示,收益流水才是审计依据。二级代理与上级代理的收益应基于下单时的分成快照,避免修改当前比例后无法解释历史订单。
提现需要经历申请、审核、打款、失败或撤销等状态。提交申请时冻结可提现金额,打款成功后确认扣减;失败则解冻。银行卡和微信收款信息属于敏感数据,页面和日志只显示脱敏值。
游戏中心与抽奖活动
游戏中心维护游戏基础信息、截图、分类、礼包类别和兑换码。抽奖模块通过公众号或小程序用户身份建立活动账户,并维护幸运币、积分和余额。
活动参与流程包含以下事实:活动及开奖时间、用户参与记录、幸运币扣减、开奖状态、中奖礼物、领取资料和领取状态。每日登录、分享等行为增加幸运币时,需要按“用户 + 日期 + 任务”保持幂等;未中奖补偿的积分或红包也应使用活动和用户组成的唯一业务键。
礼物领取资料可能包含游戏账号、角色和联系方式,必须限制运营访问范围并设置保留期限。抽奖结果生成、奖品库存占用和用户状态更新应在事务中完成,定时开奖任务使用分布式锁防止并发开奖。
微信与多应用身份
系统同时存在公众号、小程序和微信开放平台授权。OpenID 只在单一 AppID 下稳定,跨公众号与小程序关联应使用 UnionID 或显式绑定表。用户表、应用授权表和旧街机用户之间需要保存来源和绑定关系,不能把不同应用的 OpenID 直接视为同一用户。
微信回调需要验证签名并限制重放;Access Token、授权信息、商户号和支付密钥只在服务端保存。素材同步、自动回复和小程序跳转属于渠道能力,不应直接修改抽奖余额或设备订单。
数据、缓存与外部服务
| 设施 | 保存或承担的内容 | 设计注意点 |
|---|---|---|
| MySQL | 用户、代理、设备、订单、命令、收益、游戏和活动事实 | 旧新系统共库时明确表所有权和迁移版本 |
| Redis | 会话、微信临时凭据、短期状态和任务锁 | Key 加应用与业务命名空间,并设置 TTL |
| MQTT Broker | 设备命令、执行回执、在线和异常消息 | Topic ACL 按设备身份授权,不允许全量订阅 |
| 微信与支付 | 登录授权、公众号、小程序和支付 | 回调验签、金额校验、幂等和对账 |
| 对象存储 | 游戏截图、活动素材和官网图片 | 数据库保存对象 Key 与归属,不保存固定签名 URL |
部署与故障域
| 运行单元 | 扩缩容与运行方式 | 主要故障影响 |
|---|---|---|
| Vue 后台与小程序 | 静态资源或渠道构建 | 管理或活动页面不可用,不应中断设备本地状态 |
| Yii 主 API | PHP Web 服务 | 旧后台、代理和交易主链路不可用 |
| ThinkPHP 新 API | PHP-FPM 与命令任务 | 游戏中心、抽奖、微信新入口不可用 |
| MQTT 发布桥 | 无状态 HTTP 服务 | 新命令无法发布,已发布命令不受影响 |
| MQTT 接收与 Webhook | 常驻订阅或 Broker 回调 | 回执和在线状态延迟,需要重放或查询补偿 |
| Express 官网 | 独立 Node.js 服务 | 仅公开展示受影响 |
| MySQL / Redis | 事实库与临时状态 | MySQL 故障停止交易;Redis 故障限制登录和任务 |
| MQTT Broker | 按连接数和消息吞吐独立规划 | 设备命令和状态中断,订单保持待确认 |
当前架构债务与改进顺序
- 凭据轮换:移除源码中的 Broker、微信、支付和数据库固定配置,使用环境变量或密钥服务并轮换历史凭据;
- 交易状态机:拆分待支付、已支付、待发布、已发布、设备成功、失败、超时和已退款状态;
- 结算唯一入口:支付回调只确认收款,设备成功后通过统一服务结算收益,禁止不同版本重复结算;
- 命令幂等:命令 ID、业务 ID、设备 IMEI 与回执建立唯一约束,提供超时扫描和人工补偿;
- 设备网关:合并分散的发布与接收协议,统一 Topic、ACL、日志、重试和设备认证;
- 旧新系统主写边界:为设备、订单、用户、收益和活动表建立所有权清单,停止无计划双写;
- 活动账本:幸运币、积分和红包使用不可变流水,余额只作为汇总投影;
- 版本升级:Yii 2 旧依赖、Vue 2、旧 Axios 和 PHP 运行基线分阶段升级,不与数据迁移同时进行;
- 可观测性:用订单号、命令 ID、设备 IMEI 和请求 ID 串联支付、API、MQTT、设备与结算日志。
一笔订单如何经过支付、MQTT 和设备回执完成,可继续阅读支付投币与设备回传流程。