东吴码栈:一个苏州码农给同好搓的 2026 世界杯观赛小程序

写在前面:先说清楚这是什么东西

2026 年 FIFA 世界杯要来了——这次是加拿大、墨西哥、美国三国联合办,扩军到 48 队,总共 104 场比赛。我作为一个伪球迷,每到这种时候就会陷入一个经典困境:

今晚有比赛吗?几点?哪两支队?小组赛积分啥情况了?谁射手榜第一了?

市面上的 App 不少,但用了一圈下来,要么塞一堆短视频和社交进来(我只想看比分,不想看 30 秒的"精彩集锦"),要么数据更新慢半拍,要么界面花里胡哨找不到重点。所以干脆自己撸了一个——微信小程序「东吴码栈」(小程序名:苏式生活馆),五个 Tab 页把世界杯期间最常看的东西摁到一块儿:赛事进度、今日赛程、小组积分、淘汰赛对阵、射手榜。

先把名字解释一下:东吴,孙吴故地,苏州的旧称;码栈,码农的工具栈,也是我那台服务器上放代码的目录名。一个码农在自己的赛博栈里,给同好搓了个看球小工具——东吴码栈,名字就出来了。

后端独立服务 + MySQL 存储,部署在我自己 1Panel 管着的云服务器上,数据从 football-data.org 同步过来,比赛日基本能做到分钟级更新。下面把这玩意儿从用户视角撸一遍。

一、首页:一眼知道世界杯"打到哪儿了"

打开小程序第一个画面,是个"赛事进度卡":总场次 104 / 已完赛 / 进行中 / 未开始,四个数字加个进度环,第一眼就能告诉你这届世界杯目前到哪个阶段了。今天有几场比赛?下面就是"今日赛程"卡片,按开赛时间升序排——主客队、国家旗、比分或"未开赛"标记、阶段标签(全英文 GROUP_A 那种世界杯官方的)。

要是今天没比赛(比如某些间歇日),不会给你一个空白页尴尬地杵着,会显示"今天暂无比赛"然后引导你去看"未来 7 天"。

未来 7 天这部分是按日期分组的,默认全部展开,从今天往后数 7 天。哪天有比赛、几点开、对阵双方是谁——基本不用再翻日历或者打开搜索引擎了。

整个首页的视觉走的是深绿草坪+白色+金色点缀的路线,配上足球、奖杯、进度环这种语义图标,颜色不吵,看着舒服。设计参考方向写在了 PRD 里(深绿草坪基调),但具体到字体、圆角、卡片阴影这些,我承认有点工科直男审美——能看、好用、不打扰,比"花里胡哨"重要。

二、赛程页:完整比赛 + 筛选

首页适合"看个大概",但如果你想翻完整 104 场的清单,得进赛程页。这页支持日期 / 阶段 / 小组 / 状态四维筛选:

  • 想看"小组赛阶段 + A 组 + 未开始"——筛一下就出来。
  • 想看"16 强 + 已结束"——也行。
  • 想看"7 月 5 日那天的所有比赛"——直接按日期。

每条比赛卡片显示:比赛编号、UTC 开赛时间(接口同时返回北京时间展示字段)、主客队国家名和旗帜、比分(含点球比分,如果适用的话)、状态、阶段、比赛地点(API 有就展示,没有就拉倒)。

已开赛和已完赛的比赛点进去是详情页,能看比分进程、关键事件(进球/红黄牌/换人)、技术统计、首发阵容这些。未开始的比赛不点进去详情——这块是 PRD 里明确写过的:未开始比赛不提供详情页,只在卡片上显示个"订阅开赛提醒"的入口。

三、小组赛页:横滑切小组,积分 + 本组赛程一起看

12 个小组(A 到 L),这个页面支持横滑切小组标签。每个小组进去先看到积分榜:

排名、国家 + 旗帜、场次、胜、平、负、进球、失球、净胜球、积分——标准十大字段。前两名会有晋级标识(高亮或者小角标),数据完全来自后端数据库,前端不参与排名计算(这点 PRD 强调过,理由是数据一致性 + 以后想换计算规则不用动前端)。

积分榜下面是本组赛程,复用 GET /api/matches?group=GROUP_A 这个接口——不新增接口(这是技术方案里明确写过的设计原则,能复用就复用),靠 matches.group_name 字段过滤。

小组赛有个有意思的细节:球队名称可点击进入球队详情页。球队详情页聚合了球队基础信息、小组排名、本届比赛战况、后续赛程和队内射手——一个页面把一支球队在世界杯上的全部动态看个七七八八。

四、淘汰赛页:32 强到决赛,按阶段筛

小组赛结束之后,重点就转到这里了。淘汰赛页支持按阶段横滑筛选:32 强、16 强、8 强、半决赛、三四名决赛、决赛。

每个阶段的比赛卡片展示:阶段名称、比赛时间、对阵双方、比分(普通比分 / 加时比分 / 点球比分分开展示)、胜者或晋级队、状态。已确定球队名称可点击进入详情页;未确定的保持"待定"展示,不加可点击样式(这点 PRD 强调过——小组赛还没踢完时,对阵是空的,不能让用户点了空链接)。

首版用的是按阶段分组的列表式 bracket,PRD 里规划了"后续可升级为横向滑动淘汰赛树"——但 v1.0 阶段,我觉得列表式在手机上看更友好,滑动树在 6.7 寸以下的屏幕上信息密度容易爆炸。先稳再说。

五、射手榜:进球榜 + 兜底排序

最后是射手榜页:排名、球员、所属国家队 + 旗帜、进球数、助攻、点球、出场数。

football-data.org 的免费 API 套餐对射手榜扩展字段支持不一定全(这是 PRD 里列出的已确认风险),所以我加了个本地兜底排序:

1. 优先按进球数降序;

2. 进球数相同,API 返回了排名就按 API 排;

3. API 没排,本地按助攻数 → 出场数 → 球员名称依次兜底。

这样即使 API 给的数据少点,至少榜单是稳定的,不会出现"两个人并列第一但顺序随机刷新"这种尴尬。


六、杀手级功能:开赛前 5 分钟微信订阅消息

这个功能 PRD 单独用了大段文字写,开发完我自己用了几天,真香。

用户场景:你点进一场"今晚 20:00 开赛"但还没开始的比赛,卡片上有个"订阅"按钮。点一下,等于告诉后端:"我对这场比赛感兴趣,开赛前提醒我一下。"

后端逻辑:同步任务每 1 分钟跑一次,扫描所有"已订阅但未发送"的开赛提醒记录,在比赛开赛前的 5 分钟,通过微信订阅消息模板推送一条到用户微信。

取消订阅也支持——订阅后这场比赛还没开赛的话,可以点"取消订阅"撤回。已经推送过的不能再撤(这不废话嘛)。

为什么是订阅消息而不是服务通知?因为服务通知(小程序主动弹的那种)需要用户在小程序里做出某种动作触发,订阅消息是用户主动点过"订阅"按钮确认过的,触达率更高、不打扰用户。

为什么是 5 分钟而不是整点提醒?因为我自己的看球习惯是 5 分钟缓冲——够我去倒杯水、开个电视、找个舒服的姿势坐下来。如果你想 10 分钟也行,但 5 分钟这个值是测过几次最舒服的。


七、为什么是"独立后端 + MySQL"而不是直接调 API

如果你看过 football-data.org 的文档,第一反应可能是:直接调它不就行了?为啥还要搞个后端 + 数据库这么重?

理由有三个,PRD 和技术方案里都写过:

1. 频控。football-data.org 免费等级是每分钟 10 次请求。世界杯期间如果有几百个用户同时打开小程序,每个人都想"刷一下最新比分"——分分钟打爆额度。有后端 + 缓存之后,60 秒内同一份数据只需要调一次 API,剩下的全读数据库或缓存。

2. 稳定性。第三方 API 挂了或者限流的时候,小程序不能也跟着挂。有后端 + 旧数据兜底——同步失败时不清空数据库,前端继续展示最近一次成功的数据,并标"数据更新可能延迟"。

3. 安全。football-data.org 的 API Token 不能暴露在前端——所以小程序只请求自有后端,Token 只在服务端环境变量里。这个是硬性合规要求,没得商量。

至于为啥选 Node.js + TypeScript + Express + MySQL 这个组合——后端是我最熟的技术栈,MySQL 在我的 1Panel 上跑得很稳,没必要换。所谓"技术选型",最熟的就是最好的。

八、怎么部署:1Panel + 全套文档

整个项目放在 GitHub 上:itsVicOC/mini2026wc。目录分三块:

  • backend/:独立后端服务
  • miniprogram/:微信原生小程序
  • docs/:PRD、技术方案、小白部署配置手册

docs/DEPLOYMENT.md 那份部署手册我专门写得比较细,目标读者是"没部署过 Node.js 后端但会用 1Panel 的人"。推荐顺序贴在 README 上面了——从申请 API Token,到 1Panel 创建 MySQL,到初始化 schema,到配环境变量,到手动触发一次同步测试,全流程 10 步走完。

后端生产环境推荐 Node.js 20 LTS(写技术方案那会儿最新的 LTS 版本)。本地开发就 npm install && npm run dev,三分钟跑起来。

数据库表结构写在了 backend/database/schema.sql,建表的时候踩过一个小但烦人的坑:MySQL 有一些字段名是保留字或者容易和系统字段冲突——group、status、minute、order 这些。standings.group_name 我特意没用裸 group,matches.status 改成了 display_status。看起来是小事,但等到查询时 WHERE group = 'A' 直接报语法错误的时候再回头改,就很影响心情了。

九、写在最后:欢迎 Star 和二次开发

整个项目从 PRD 到 v1.0 MVP 上线,几乎是我一个人在 1 周内赶出来的。PRD 写完发现 5 个页面 + 1 套同步 + 1 套订阅消息,技术方案也写得比较细——因为我自己最怕的,是"代码写完了,过了仨月回来看不懂"。

所以这次特意把所有设计决策都留在了仓库里:为什么用独立后端、为什么用订阅消息而不是服务通知、为什么字段命名避开关键字、射手榜为什么要有兜底排序逻辑——全在 PRD 和技术方案文档里。

开源到这个程度,欢迎你:

  • 直接扫码用(小程序分享码见文章配图)——2026 年 6 月开赛期间服务会一直跑着
  • Star 一下——给我这周的肝一个交代
  • 提 Issue——发现 bug 或者数据不对劲,直接 GitHub 上吼
  • Fork 二次开发——换数据源、加新功能、改 UI 全都欢迎,文档齐全照着抄就行

最后一句:东吴码栈——苏州码农的代码栈,码给同好看的小工具。世界杯四年一回,能用自己写的小程序看球,这件事本身就很快乐。


项目地址:github.com/itsVicOC/mini2026wc

小程序入口:见下图(小程序名:苏式生活馆,扫码即可进入)

东吴码栈小程序分享码(小程序名:苏式生活馆)