# 2026 秋季社区羽毛球联赛 · 积分榜

> 活页公开模板 `sample-league-table` · 场景: 报名 · 投票 · 接龙 · 行业: 个人家庭 / 企业内部
> 任何人、任何 Agent 都可以读、照着改，不需要账号。示例内容均为虚构。
> 真页面: https://space.24haowan.com/s/PM4WOerUlJtX · 详情: https://space.24haowan.com/examples/sample-league-table

## 这是什么

联赛积分榜 · 社区、公司、校园联赛每轮更新

## 什么时候用

办一个多轮次的联赛 / 循环赛、每轮赛后要把积分和名次更新到同一个链接发到参赛群的，选它：社区羽毛球、公司篮球联赛、校园足球、棋牌群赛、电竞内战。核心是积分榜（胜平负、积分、近 5 场、名次升降）加赛程和个人榜，顺带收下一届报名。只是一次性的评选、让大家投票排名的，选 sample-vote-rank；只收一场活动的报名、没有赛程积分的，选 sample-event-signup；实时播报某一场比赛或销售战况的，选 sample-sales-live。

## 用户对助手说的原话

帮我做一个联赛积分榜的网页，每轮比赛结束后更新同一个链接，发到参赛群：我们社区办秋季羽毛球联赛，8 支队单循环 7 轮，现在打完第 5 轮。页头是组委会标志、联赛名、「第 5 轮战罢」和更新时间、下一轮时间。首屏就是积分榜：名次、名次升降箭头、队徽（每队一个简单的矢量图标）和队名、已赛、胜平负、净胜盘、近 5 场的胜平负圆点、积分，前 4 名下面画一条季后赛虚线；页面打开时先摆上一轮的名次，再滑到本轮名次，名次变了的行要有位移动画，还能切换「第 4 轮后 / 第 5 轮后」。积分和名次都由每轮的比分算出来（胜 3 平 1 负 0，同分先比相互战绩、再比净胜盘、总胜盘、抽签），比分和积分要前后对得上。接着是赛程，按轮次左右滑，上面一排轮次圆点，已赛的显示比分、没赛的显示时间和场地；本轮 MVP 一张卡（姓名、队、三局比分、一句话）；个人胜场榜前 6 名；积分规则写清楚并举一个榜上同分怎么排的实例；最后是报名下一届 / 报名当志愿者的表单，写进数据表 signups（列 name / team / role），页面显示已报名人数。电脑上积分榜和赛程左右两栏，手机一栏，颜色干净像体育数据看板，支持暗色。

如果你还没有活页连接器（MCP），先读 https://space.24haowan.com/for-agents.md ，照里面的说明接入，或不登录直接发布。

## 照着做一份

1. 读入口文件 https://space.24haowan.com/examples/sample-league-table/source/index.html（它引用的其他文件见下方列表）。
2. 保留结构、版式和交互，把内容**全部**换成用户自己的；模板里的公司、人名、数字都是虚构的，一样都别留。
3. 交付一个自包含的单文件 HTML：样式写在页面里，不引外部字体 / 脚本 / CDN；手机 375 宽和电脑 1440 宽都要好看，模板有暗色就保留暗色。
4. 要发成微信里能打开、改了链接不变的网页：接入活页（https://space.24haowan.com/for-agents.md）后发布；没有账号也可以让用户在 https://space.24haowan.com/quick 上传这个文件。
5. 没有活页工具、但能发 HTTPS 请求：把做好的 HTML 以 Content-Type: text/html POST 到 https://space.24haowan.com/api/quick?client=template-sample-league-table ，返回预览链接、7 天分享与认领链接（登录后保留、链接不变）。

## 页面结构

- 积分榜
- 赛程
- 本轮 MVP
- 个人胜场榜
- 积分规则
- 报名

## 文件（公开，纯文本）

- https://space.24haowan.com/examples/sample-league-table/source/index.html（入口）

## 发成活页之后还能做的

- 同一链接每轮更新：改脚本里的每轮盘分，积分、胜平负、净胜盘、近 5 场、名次和升降箭头全部按积分规则现算，参赛群里转发的永远是最新一轮
- 首屏积分榜打开时从上一轮名次滑到本轮名次（FLIP 位移动画），名次变化的行高亮一下，可切回「第 4 轮后」再看一遍
- 报名下一届 / 当志愿者写回数据表 signups（原生表单 POST ./_data/signups 打底，脚本在时页内提交），页面读回人数
- 电脑上积分榜与赛程两栏，手机一栏；赛程按轮次横滑
- 阅读回执看哪几节被看了；微信卡片（share.title / share.desc）

## 发之前要备好

- 数据表 signups（列 name / team / role，append_open=true）：「报名下一届 / 当志愿者」表单写进这里，页面读回人数加到页面里写的基础人数上；发布前先用 set_data 建好，报名截止后把 append_open 关掉

## 模板说明（README）

模板市场第三轮补齐空缺的模板之一（总览见 `core/space/examples/README.md`，品质标准见 `core/space/examples/QUALITY.md`）。虚构的「梧桐里社区体育协会」办 2026 秋季社区羽毛球联赛，8 队单循环 7 轮，组委会每轮赛后更新同一个链接，发到参赛群（每轮都被转发）。示例内容均为虚构。

## 演示哪个特色

**同一个链接每轮更新，积分榜自己动起来 —— 名次怎么变的，读者一打开就看见。**

- **记忆点**是首屏的积分榜：打开时先摆出第 4 轮后的名次，0.3 秒后换成第 5 轮后 —— 名次变了的行用 FLIP 动画滑到新位置并高亮一下，积分跳到新值，升降箭头出现。右上角可切回「第 4 轮后」再看一遍。前 4 名下面一条季后赛虚线。
- **单一数据源**：脚本里的 `LEAGUE.rounds`（每轮 4 场，`[主队, 客队, 主队盘分, 客队盘分]`），已赛、胜平负、净胜盘、近 5 场、积分、名次与升降全部按「积分规则」一节现算（胜 3 平 1 负 0；同分依次比相互战绩 → 净胜盘 → 总胜盘 → 抽签）。榜上就有一例：火山、星河同 4 分，星河净胜盘更多，但火山第 5 轮 3-1 赢了星河，排在前面。
- **数字自洽**：5 轮 20 场共 80 盘，各队胜盘合计 = 负盘合计 = 80；15 场分出胜负、5 场 2-2，胜场合计 = 负场合计 = 15。个人胜场榜与各队盘分对得上（周屿、陆川 5 战全胜、还没交手；林晓棠唯一一负就是 MVP 沈一禾赢的那盘）。
- 赛程按轮次横滑（scroll-snap），上面一排轮次圆点跟着走，打开时停在最近一轮；已赛显示盘分，未赛显示时间与场地。
- **报名写回**：报名下一届 / 当志愿者写进数据表 `signups`（列 `name` / `team` / `role`），页面读回人数加到基础人数上。
- 两端：电脑上积分榜 | 赛程两栏，下面个人榜 | MVP、规则 | 报名；手机一栏，积分榜收掉「赛」「净胜盘」两列。
- 降级：脚本不跑时积分榜是本轮的静态版本（与脚本算出来的一致），赛程从第 1 轮起可横滑，报名走原生表单 `<form method="post" action="./_data/signups">`；`prefers-reduced-motion` 时不播位移，直接停在本轮。

## 改哪里变成我的

| 位置 | 改什么 |
|---|---|
| 页头 `.org` / `h1` / `.meta` | 主办方、联赛名、第几轮战罢、更新时间、下一轮时间 |
| 顶部 `<symbol id="b-…">` | 队徽，32×32 内联 SVG，一队一个；`id` 后缀就是队伍 key |
| 脚本 `LEAGUE.teams` / `LEAGUE.rounds` | 队伍 key 与每轮比分 —— **每轮更新只改这里**，再把新一轮追加进去 |
| `.rows` 里的静态行 | 不跑脚本时显示的积分榜，按 `LEAGUE` 算出的结果写（脚本会按数据重排重写数字；`data-team` 与队伍 key 一致、队名写在 `.c-tm b`） |
| `.cut` 的 `top` | 季后赛线画在第几名下面（`var(--rh) * 4` 的 4） |
| `.track` 里的 `article.rd` | 每轮一张：日期、四场对阵；已赛写盘分（`.sc`），未赛写时间场地（`.tv`），`.rn` 一句话；`.chips` 圆点数量同步 |
| `#mvp` | 本轮 MVP：姓名、队徽、三局比分、一句话、本季数据 |
| `#players` | 个人胜场榜（胜场、胜-负、局分），和各队盘分对得上 |
| `#rules` | 赛制、积分、同分规则（与脚本 `standings` 的比较顺序一致）、季后赛 |
| `#signup` | 下一届信息、`data-base` 基础人数（群里接龙已登记的）、队伍选项 |
| 页脚 | 平台标志与名称（与 `core/space/src/theme.ts` 的 `MARK_SVG` / `PUBLIC_NAME` 逐字一致，测试咬着）+ 一句适用场景；发自己的联赛时整段删掉 |
| `manifest.json` | `title` / `share.title` / `share.desc`（每轮改 desc，群里转发的卡片就是本轮结论） |

## 数据表

报名写进数据表 `signups`（列 `name` / `team` / `role`，`role` 为「参赛」或「志愿者」，`append_open=true`）。发之前先建表：

```
set_data  proposal_id: <id>  table: "signups"  columns: ["name","team","role"]  rows: []  append_open: true  revision: 0
```

用 `list_data_rows table=signups` 读回名单。报名截止后用 `set_data` 传 `append_open: false`（页面会提示「报名已经截止了」）。本地 `space-cli serve` 会把提交写进包里的 `_data/signups.json`，试完记得改回 `[]`。

## 怎么发出去

```bash
export SPACE_TOKEN=sk-space-…            # MCP create_cli_token
node core/space/cli/space-cli.mjs push core/space/examples/sample-league-table \
  --proposal <proposal_id> --manifest core/space/examples/sample-league-table/manifest.json --hold
```

没有终端时也可以 MCP `publish_file`（`filename: "index.html"`、`content` 为全文、`manifest` 为 manifest.json 去掉 entry、`hold: true`），再按上面建表。
要发到参赛群：确认后 `set_visibility` 设成 `public`（或 `passcode` 只给参赛队员）。之后每轮赛后改 `LEAGUE.rounds`、静态行、赛程卡、MVP 和 `share.desc`，作为新版本发到**同一页**，链接不变。

## 素材

- 没有位图：队徽、联赛标志、MVP 的球路都是内联 SVG；社区、队伍、人名与比分均为虚构。页面里没有外部公共数据（室内赛事，不接天气）。
- `thumb.webp` / `phone.webp`：画廊缩略图与手机首屏图，由 `examples/verify-shots.mjs --write-thumb --write-phone` 从成品截出，不进发布包。
