用途:每次工作前读本手册恢复状态;严格按流程执行;用户可随时拿本文档让 AI 接续工作。
为什么必须读手册(甲方诊断,2026-09-08):早期错误多、反复改,根因就两条——①规矩太松,手册写得不够清楚;②有手册长期不读,凭印象干活。为此已建成防错机制:执行前必读对应章节、新教训立即写回手册、检查经验库盖楼式防漏、发布门禁、命名规范定死。手册不是摆设:没读对应章节就不许开工。
项目名:足记(足球追踪网页)
在线地址:https://bxgj2030.top/(COS/CDN,2026-09-07起;surge.sh已废弃)
当前版本:v10.09
最后更新:2026-09-07(逐字逐句校订:统一积分榜数据源口径、场均高级数据主源改为StatMuse、球队数/部署平台/联赛数全部按现状更正)
足记是什么:手机端看的静态足球网页。首页看赛程/积分榜/射手榜;31支俱乐部队+9支国家队专属球员页,看球员能力雷达、29项游戏能力、赛季真实数据。核心价值是"快速看懂、公正对比球员",基础数据准确是生命线。
8支重点关注球队:阿森纳、曼城、利物浦、切尔西、皇马、巴萨、巴黎圣日耳曼、拜仁慕尼黑。DESC(比赛前瞻后顾)重点写这8支球队。
扩展球队:英超其余16队+欧冠一档二档其余球队+意甲/德甲/法甲/葡超代表球队,共31支俱乐部,维护名单+OVR+六维+场均数据。
9支国家队页:巴西、英格兰、西班牙、法国、德国、意大利、葡萄牙、荷兰、阿根廷(brazil/england/spain/france/germany/italy/portugal/netherlands/argentina)。国家队大名单未正式公布前只搭框架,公布后按名单做,与俱乐部数据相互独立。
项目架构(2026-09-07现状:数据与视图分离 + 公共模块抽取):
index.html — 首页(赛程+积分榜+射手榜,数据从data/*.js加载)*_players.html(40个=31俱乐部+9国家队)— 球员页,只负责渲染,不内嵌数据。通过<script src="data/players/xxx.js">加载对应球队数据。data/players/*.js(40个)— 球员数据源文件,每队一个文件,包含window.PLAYERS = [...]。改球员数据只改这里,不需要改HTML。data/css/common.css + data/js/ 下 9 个模块(utils/data_loader/render/render_detail/render_detail2/events/render_leagues/render_leagues2/main,F-01-06 20261009 拆分)— 公共样式和逻辑,球队页面共用manual.html — 本手册changelog.html — 更新日志deploy_site.sh — COS/CDN 部署脚本(--cos-only,硬门禁 HEAD==master + 版本/变更/内容/制品指纹留痕,2026-09-07 起主用;README 44 行有完整通道说明)backups/ — 部署自动备份目录(保留最近10个版本).git — git版本控制(每次修改commit,出问题可回滚)三条铁律:
data/players/对应球队.js,HTML不动./scripts_ops/deploy_site.sh --cos-only(硬门禁:本地 HEAD 必须=master,防旧工作区覆盖线上),自动上传+设置缓存头+制品指纹留痕(deployment_log.md),部署后浏览器抽验;新目录文件(如 data/js/i18n/zh.js)deploy 不传,需手动 put_object(ContentType=text/javascript + no-cache)git版本控制:项目已初始化git,每次修改后commit,出问题可git reset --hard回滚。这是最基础的工程纪律,必须遵守。
分级原则:按更新频率分层。锁定原则:低频数据确认后锁定,日常更新只能动第一级。重要变更:原A级/B级/C级/D级球员四级分级体系已于2026-09-07取消,所有球员一视同仁,详见1.5节。
| 层级 | 包含内容 | 更新频率 | 当前状态 | 解锁条件 |
|---|---|---|---|---|
| 第一级 | 1A首页比分/进球轴/desc 1B积分榜/射手榜 1C球员出场/进球/助攻/零封 | 每场比赛后 | 🔓 不锁 | 每场更新 |
| 第二级 | 名单/号码/位置/国籍/伤停 | 转会窗 | 🔒 已锁定(2026-09-07,31支俱乐部778人+9支国家队) | 用户明确说"解锁名单" |
| 第三级 | FC评分(ovr)/六维(fc/abilities)/29项detailed | 赛季初/用户指定 | 🔒 已锁定 | 用户说"更新FC数据" |
核心原则:取消A级/B级/C级/D级四级分级体系,所有球员一视同仁。per90统一=25-26上赛季基准(per90Season=2025-26);26-27本赛季场均数据冬窗后统一更新(用户拍板,2026-09-08第22章定案,禁止赛季初小样本提前补),26-27只存seasonStats基础数(apps/goals/assists/cleanSheets)。关键认知:StatMuse数据源无反爬,球队级别页面一次返回整队数据,27队524人次约9分钟抓完,抓取成本极低,不需要通过分级来减轻维护工作量。
| 数据类型 | 字段 | 维护频率 | 说明 |
|---|---|---|---|
| 基础信息 | id/name/number/position/nationality/age/height/weight/club | 转会窗更新 | 所有球员必须有 |
| FC评分 | fc(OVR总评分) | 赛季初更新 | 参考FC27官方数据 |
| 六维数据 | advanced(PAC/SHO/PAS/DRI/DEF/PHY) | 赛季初更新 | FC27官方六维或估算值 |
| 29项详细能力值 | detailed | 逐步补全 | 优先补OVR≥80的核心球员 |
| 场均数据(per90) | per90(26项非门将+门将综合页) | 26-27已上线,后续低频刷新 | StatMuse主源;详情页26-27(per90)与25-26(per90_2526)同格双值,列表页只显示26-27(见13.1b) |
核心原则:用户只说"更新",AI自己判断该更什么、怎么更、验证完再部署。日常更新只动第一级。
第1步:读手册 + 看锁定状态(30秒)
第1.5步:变更检测(必须第一步执行)
node zuji_tools/change_detect.js(自动检测最近3天已赛、未来3天未赛、desc质量,输出更新建议)第2步:更新1A首页比赛(比分→进球轴→desc)
第3步:更新1C球员赛季数据
第4步:更新1B联赛排名
第5步:跑自动检查(必须全绿)
node zuji_tools/check_all.js(结构+人数+进球一致性,0 ERROR才能继续)node zuji_tools/verify_data.js(首页数据五方校验)第6步:部署
./scripts_ops/deploy_site.sh --cos-only(自动:上传全部HTML/数据文件到 COS/CDN+设置no-cache缓存头)第7步:更新状态表和日志
| 数据类型 | 主源 | 次源(验证) | 验证方式 |
|---|---|---|---|
| 比赛比分/进球时间轴 | 直播吧/联赛官网(直接抄比分,不靠进球列表算) | 懂球帝 | 两源进球者+分钟一致 |
| 赛季出场/进球/助攻 | FotMob球队页 | 联赛官网统计页 | 两源一致;进球之和=首页进球轴。不用FBref(英超滞后) |
| 积分榜/射手榜 | 直接抄现成榜单(球迷屋/新浪/联赛官网,方法见3.5.5) | football-data API(程序化备选,key见关键配置) | 抄来即用,只用MATCHES反算关注队核对,不全量交叉 |
| 场均高级数据 per90 | StatMuse(球队页批量抓,详见第12章) | FBref(仅xG/xA验证) | Per90口径;StatMuse无反爬、一次返回整队,是当前主源 |
| 名单/号码/位置 | 俱乐部官网+懂球帝转会新闻 | Transfermarkt | ⚠️ 所有阵容页都滞后,必须用转会新闻+官网双源 |
| FC评分/六维 | FCRatings.com | — | fc六维=abilities对应项,统一采用FC27标准 |
| 29项detailed | FCRatings.com球员页 | — | 29项齐全,值1-99 |
数据源沿革(避免再走弯路):①场均高级数据早期用FootyStats(Cloudflare反爬、单球员页、临时工取数不一致),后改用FBref,2026-09-06起全面改用StatMuse(无反爬、球队页一次返回整队29+14项),FootyStats方案废弃但保留在3.5.1作历史参考;②积分榜/射手榜早期靠MATCHES自己算(慢、且MATCHES只有关注队不完整、乌龙球算错),后确立直接抄原则;③FBref的26-27英超数据严重滞后(第3轮打完联赛页仍全0),绝不能作为基础数据和积分榜主源,只用于场均高级数据的交叉验证。
说明(重要):场均高级数据的主源已切换为 StatMuse(球队页一次返回整队、无反爬、Per90口径,抓取方法和字段对照见第12章)。下表是早期FootyStats/FBref时代的字段对照,仅在StatMuse缺某字段时用于补漏或交叉验证。FBref数据最全但有Cloudflare反爬、且英超更新滞后;FootyStats方案已废弃(见3.5.1)。
| 字段 | 主数据源 | 次源/验证 | 获取方式 | 备注 |
|---|---|---|---|---|
| xG(预期进球) | FBref | Understat | FBref球员页scout报告 → npxG | Understat只覆盖五大联赛,用于验证 |
| xA(预期助攻) | FBref | Understat | FBref → xAG(Exp. Assisted Goals) | FBref叫xAG,就是xA |
| 进球 | FBref | FotMob | FBref → Non-Penalty Goals + Penalties | 基础数据 |
| 助攻 | FBref | FotMob | FBref → Assists | 基础数据 |
| 射门 | FBref | FotMob | FBref → Shots Total | 基础数据 |
| 射正 | FotMob | SofaScore | FotMob球员页 → Shots on target | FBref没有单独射正数 |
| 射正率 | FotMob(计算) | — | 射正÷射门×100% | 计算得出,不用单独查 |
| 关键传球 | FBref | SofaScore | FBref → Shot-Creating Actions | FBref叫"创造射门动作",包含关键传球,范围更广 |
| 创造绝佳机会 | SofaScore | FotMob | SofaScore球员页 → big chances created | 边锋/前腰关键字段 |
| 传球数 | FBref | FotMob | FBref → Passes Attempted | 基础数据 |
| 传球成功率 | FBref | FotMob | FBref → Pass Completion % | 基础数据 |
| 抢断 | FBref | FotMob | FBref → Tackles | 基础数据 |
| 拦截 | FBref | FotMob | FBref → Interceptions | 基础数据 |
| 夺回球权 | FBref | FotMob | FBref → Ball Recoveries | FBref和FotMob都有,FBref更全 |
| 解围 | FBref | FotMob | FBref → Clearances | 后卫关键字段 |
| 争顶成功数 | FBref | SofaScore | FBref → Aerials Won | FBref有成功数,无总数 |
| 争顶成功率 | SofaScore | — | SofaScore → aerial duels won % | FBref无法直接算(无总数),SofaScore有争顶总数和成功数 |
| 过人(成功) | FBref | SofaScore | FBref → Successful Take-Ons | 边锋关键字段 |
| 传中(成功/总数) | SofaScore | — | SofaScore → accurateCross / total crosses | 边后卫/边锋关键字段,FBref和FotMob都没有 |
| 传中成功率 | SofaScore(计算) | — | 成功传中÷总传中×100% | 计算得出 |
| 被犯规 | FotMob | SofaScore | FotMob → Fouls won | FBref没有此字段 |
| 触球 | FotMob | SofaScore | FotMob → Touches | FBref只有分区触球,没有总数 |
| 门将扑救 | FBref | FotMob | FBref → Saves | 门将专属 |
| 门将扑救成功率 | FBref | FotMob | FBref → Save Percentage | 门将专属 |
| 门将零封 | FBref | FotMob | FBref → Clean Sheets | 门将专属 |
| 门将失球 | FBref | FotMob | FBref → Goals Against | 门将专属 |
| 位置 | 必查字段 | 主数据源 |
|---|---|---|
| 边锋(LW/RW) | xG、xA、射门、关键传球、过人、传中、被犯规 | FBref + SofaScore |
| 中锋(ST/CF) | xG、射门、射正率、争顶成功率、触球 | FBref + SofaScore |
| 前腰(AMF) | xA、关键传球、创造机会、传球成功率、过人 | FBref + SofaScore |
| 后腰(DMF) | 传球数、传球成功率、抢断、拦截、夺回球权、触球 | FBref + FotMob |
| 边后卫(LB/RB) | 助攻、xA、关键传球、传中、抢断、夺回球权、过人 | FBref + SofaScore |
| 中后卫(CB) | 抢断、拦截、解围、夺回球权、争顶成功率、传球成功率 | FBref + SofaScore |
| 门将(GK) | 扑救、扑救成功率、零封、失球 | FBref |
your-api-key-here(积分榜/射手榜程序化备选,明文 Key 已清理,实际值见凭据台账)docs/足记凭据台账.md 读取,不写明文docs/足记凭据台账.md(明文已清理,不贴手册);网站地址 https://bxgj2030.top/./scripts_ops/deploy_site.sh --cos-only(自动上传全部文件并设置no-cache)https://crests.football-data.org/{ID}.png(完整ID对照见11.5节)https://flagcdn.com/w160/{code}.png。英国构成国特殊格式:英格兰=gb-eng、苏格兰=gb-sct、威尔士=gb-wls、北爱尔兰=gb-nir。禁止用gb表示英格兰球员(会显示英国米字旗)。核心原则:所有数据获取方法必须写死,包括用什么工具、什么数据源、URL格式、提取步骤、反爬应对、常见错误。这样不管是AI自己更新,还是别人接手,都能照着做,不用重新摸索。工具优先级:webfetch > Playwright/Puppeteer > curl。webfetch能自动处理反爬和JS渲染,是首选;curl大概率被拦截,不要用。
⚠️ 本节为2026-09-06之前的FootyStats旧方案,已废弃。当时结论"不要用StatMuse"是错误的——后来验证StatMuse用Node.js https.get可直连、无反爬、球队页一次返回整队数据,已成为场均per90的主源(第12章)。本节仅在StatMuse确实缺某小众字段时作补漏参考,不要再按本节批量抓数据。
(旧)数据源:FootyStats(https://footystats.org)。旧方案曾认为FBref被Cloudflare拦截、StatMuse缺字段——这些结论已被第12章的StatMuse实践推翻。
工具优先级:
FootyStats球员页面URL格式:
https://footystats.org/players/{国家路径}/{球员slug}
11个字段的准确label和所在区块(一个字都不能错):
| 字段名 | 含义 | FootyStats准确label | 所在区块 | 取哪一列 | 数据源 |
|---|---|---|---|---|---|
| shots | 场均射门 | Shots Taken | Attacking | Per 90(第3列) | FootyStats |
| shotsOnTarget | 场均射正 | Shots on Target(注意O大写) | Attacking | Per 90(第3列) | FootyStats |
| xG | 场均预期进球 | Expected Goals (xG) | Attacking | Per 90(第3列) | FootyStats |
| keyPasses | 场均关键传球 | Key Passes | Attacking | Per 90(第3列) | FootyStats |
| xA | 场均预期助攻 | Expected Assists (xA) | Attacking | Per 90(第3列) | FootyStats |
| dribbles | 场均成功过人 | Successful Dribbles(注意是Successful,不是Dribbles) | Attacking | Per 90(第3列) | FootyStats |
| tackles | 场均抢断 | Tackles(注意不是Total Tackles) | Defending | Per 90(第3列) | FootyStats |
| interceptions | 场均拦截 | Interceptions | Defending | Per 90(第3列) | FootyStats |
| passAccuracy | 传球成功率 | Pass Completion Rate | Passing | Total列(第2列),Per 90列显示N/A | FootyStats |
| aerialDuelsWon | 场均争顶成功 | Aerial Duels Won | Defending | Per 90(第3列) | FootyStats |
| ballRecoveries | 场均夺回球权 | Ball Recoveries | Miscellaneous | Per 90 | FBref搜索提取(FootyStats无此字段) |
注意:前10个字段从FootyStats获取,第11个字段(ballRecoveries夺回球权)FootyStats没有,需要用general_search搜索FBref球探报告页面提取。搜索关键词格式:{球员英文名} Ball Recoveries per 90 2024-25 Premier League FBref。
提取步骤(webfetch方式,推荐):
提取步骤(Playwright方式,备选):
反爬应对方法(用Playwright时必须看):
常见错误和解决方法(之前临时工犯过的,必须避免):
| 错误 | 后果 | 解决方法 |
|---|---|---|
| 用curl访问FootyStats | 被Cloudflare拦截返回403,全部数据为空 | 用webfetch或Playwright,不要用curl |
| (旧结论,已推翻)用StatMuse作为数据源 | 旧方案曾误判"StatMuse缺7字段、是SPA抓不到" | 已推翻:StatMuse正是当前主源(第12章),Node.js直连即可,本条作废 |
| dribbles的label用"Dribbles"而不是"Successful Dribbles" | dribbles字段抓不到,全部缺失 | label必须是"Successful Dribbles" |
| tackles和interceptions不限定区块,全局搜索 | 可能抓到错误区块的数据,或者抓不到 | 必须在Defending区块内搜索 |
| 只抓Attacking区块,不抓Defending和Passing | 缺抢断、拦截、传球成功率5个字段 | 三个区块都要抓 |
| passAccuracy取Per 90列 | Per 90列显示N/A,抓不到 | passAccuracy必须取Total列的百分比值 |
| 查不到数据就填0 | 数据造假,后续无法区分"真实0"和"没查到" | 查不到就标记// No data available,禁止填0 |
| 国家路径用错(如英格兰球员用france) | 被重定向到列表页,返回空数据 | 国家路径必须匹配球员国籍,不确定先查国籍 |
守门员数据说明:守门员的进攻字段(shots、shotsOnTarget、xG、dribbles)为0是正常的,但keyPasses、tackles、interceptions、passAccuracy应该有值。如果守门员的所有字段(包括passAccuracy)都是0,需要重新核实,可能是抓取失败。
铁律:所有场均数据提取必须使用标准脚本 extract_footystats.js,禁止自己写正则或提取逻辑。之前两个临时工取出不同的数据(Worker 1 tackles=0.51,DuMate tackles=1.50),就是因为各自写提取逻辑,一个取错了列,一个取对了。用标准脚本可以保证任何人跑出来的结果完全一致。
脚本位置:项目根目录 extract_footystats.js,每个任务包都会附带这个文件。
使用步骤:
saka.md)node extract_footystats.js saka.md脚本输出示例:
联赛: Premier League
{
"shots": 2.87,
"shotsOnTarget": 1.09,
"xG": 0.4,
"keyPasses": 2.59,
"xA": 0.29,
"dribbles": 1.86,
"tackles": 1.5,
"interceptions": 0.65,
"passAccuracy": 77.25,
"aerialDuelsWon": 1.2
}
✅ 10个字段全部提取成功
脚本处理的特殊情况:
如果脚本报错:
批量处理方法:
extract_footystats.js 提取数据原则:每个位置有不同的核心字段要求,核心字段必须100%补全,次要字段尽量补全(容错率80%)。核心字段全有 + 次要字段达标 = 该球员数据达标。
| 位置 | 核心字段(必须全有) | 次要字段(80%达标算过) | 次要至少要有 |
|---|---|---|---|
| ST/CF 中锋 | 射门、射正、xG | 关键传球、xA、过人、传球成功率 | 3/4 |
| LW/RW 边锋 | 射门、xG、关键传球、xA、过人 | 射正、传球成功率 | 2/2(全有) |
| CAM/AM 前腰 | 关键传球、xA、射门、xG | 过人、传球成功率、抢断、拦截 | 3/4 |
| CM 中前卫 | 关键传球、xA、抢断、拦截、传球成功率 | 射门、xG、过人、争顶成功 | 3/4 |
| CDM/DM 后腰 | 抢断、拦截、传球成功率、夺回球权、争顶成功 | 关键传球、xA、射门、xG、过人 | 4/5 |
| LM/RM 边前卫 | 关键传球、xA、过人、抢断 | 射门、xG、传球成功率、拦截 | 3/4 |
| CB 中后卫 | 抢断、拦截、争顶成功、传球成功率、夺回球权 | 射门、xG、xA | 3/3(全有) |
| LB/RB 边后卫 | 抢断、拦截、关键传球、xA、传球成功率 | 过人、争顶成功、射门 | 3/3(全有) |
| GK 门将 | 不需要补数据 | - | - |
注意:夺回球权(ballRecoveries)是后腰和中后卫的核心字段,但FootyStats没有此字段,必须用general_search搜索FBref提取。这是数据补全中最耗时的部分。
背景:2026-09-06统计发现756名球员中有503人场均数据不达标,需要大规模补全。单个AI处理503人耗时太长,建立6人并行分工机制。
分工方法:
任务包内容:
task_instructions.txt — 任务说明书(中文,详细操作指南,含如何搜索英文名、如何构建URL、标准提取脚本使用方法、查不到数据的处理方式、回复要求)player_list.csv — 球员名单(84人,含球队、中文名、国籍、位置、缺哪些核心字段、缺哪些次要字段、现有字段数)extract_footystats.js — 标准提取脚本(v4,支持10个FootyStats字段)任务说明书必须包含的内容:
文件名规范:
合并校验流程:
历史教训:
数据源:FCRatings.com(https://fcratings.com)。这是FC27官方评分的数据源,全队列表页可以批量提取,不需要逐个球员页搜索。
工具:webfetch(首选)或Playwright(备选)。FCRatings反爬不严格,curl也可能能用,但推荐webfetch。
球队页面URL格式:
https://fcratings.com/teams/{球队slug}
提取内容:球队列表页直接显示25人左右的OVR和六维(PAC/SHO/PAS/DRI/DEF/PHY),不需要进入球员个人页。
注意事项:
数据源:FCRatings.com球员个人页。
球员个人页URL格式:
https://fcratings.com/players/{球员slug}
注意事项:
数据源优先级:
注意事项:
重要规则(2026-09-06确立,2026-09-07强化):积分榜和射手榜直接抄现成榜单,不要自己根据MATCHES比赛结果算。原因:MATCHES只有8支关注队的比赛,算出来不完整、容易错(乌龙球也算不明白),而且要翻所有比赛,很慢。抄不算,是铁律。
当前覆盖7个联赛:英超PL、西甲PD、德甲BL、法甲FL、意甲SA、葡超PO、欧冠CL。standings.js/scorers.js都按这7个key维护。
数据源(直接抄网页榜单):
抄取字段:积分榜=排名/场次/胜/平/负/进球gf/失球ga/净胜球gd/积分pts(对应standings.js字段);射手榜=排名/球员name/球队team/进球goals/助攻assists/出场played。
注意事项:
数据源:
注意事项:
核心原则(2026-09-06确立):禁止凭印象写任何事实性信息,必须先搜2-3个媒体报道融合提炼。AI训练数据有截止日期,2026年的转会、伤停、主帅信息可能不知道,凭印象写必然出错。
后顾(赛后总结)写作规范:
前瞻(赛前预告)写作规范:
搜索关键词格式:
核心原则:靠工具不靠自觉。更新了哪一级数据,就跑哪一级的检查;全部通过才能部署。
| 工具 | 检查什么 | 运行方式 |
|---|---|---|
check_all.js | 结构/人数/ID唯一/资源引用/锁定状态/进球一致性 | node zuji_tools/check_all.js |
validate_data.js | 球员数据字段齐全/枚举合法/数值范围/fc=abilities | node zuji_tools/validate_data.js |
verify_data.js | 首页五方校验(比分↔进球轴/积分↔MATCHES/RANK↔积分/射手榜/desc) | node zuji_tools/verify_data.js |
change_detect.js | 变更检测(最近3天已赛/未来3天未赛/desc质量/更新建议) | node zuji_tools/change_detect.js |
deploy_site.sh | 一键上传全部文件到 COS/CDN+设置no-cache | ./scripts_ops/deploy_site.sh --cos-only |
| 改动 | 必查 |
|---|---|
| 首页卡片/UI | 已赛能展开、未赛能收起、预约按钮、球队筛选、联赛切换 |
| 积分/射手榜 | 切换、完整、不溢出、关注队金色高亮 |
| player_common.js | 8个俱乐部队全部回归一遍(共用一份,一改全影响) |
| MATCHES比分 | 比分=进球轴、积分交叉、API+懂球帝双源 |
| 名单/转会 | 新球员字段完整、离队移除、HTML人数同步、双源验证 |
为什么必须做:代码断言查不出"人眼一看就错"的问题——文字重叠、队名被时间盖住、百分比溢出框体、队徽国旗空白、颜色错配。用户原话:"你不是定位代码,你是检查的方法。如果真的是人看,一眼就看出来了。"检查必须像人眼一样看渲染后的画面(滚动着看,每一寸),而非只做代码断言。
cd match-tracker && python3 visual_check.py(本地服务 python3 -m http.server 8123 需先启动)| 问题 | 根因 | 修复规范(写进模板) |
|---|---|---|
| 赛程收起行 队名被时间盖住/重叠 | .stack-time 居中left:50%,与长队名相交;宽卡片padding未计入 | .stack-team max-width:30%;.stack-time right:32%+去"周X"前缀(replace(/^周[天一二三四五六日]\s+/,''));队名字号11px |
| 数据栏六项溢出框体(马竞56.2%) | 375px下6项挤压,24px数值超项宽 | ≤520px媒体查询:数值14px、排名标签8px、gap:1px |
| "主场"球场名截断(16页) | .th-stadium nowrap+ellipsis | white-space:normal + overflow-wrap:break-word + word-break:break-all |
| 英文队名截断(Deportivo La…) | .th-name-en 11px超容器3px | 字号10px |
| 首页顶部筛选行超宽3px | 10个队徽按钮+gap14超内容区 | .tf 20px + gap9px |
| 队徽/国旗全空白(射手榜/积分榜/首页/球员页) | crests.football-data.org / flagcdn 外链在用户手机端加载失败,显示alt文字挤占 | 外链禁用,全部本地化到 data/img/crests/{id}.png、data/img/flags/{code}.png;新页引用队徽一律用 crestUrl() 走本地 |
核心问题:AI训练数据有截止日期,2026年转会/主帅信息可能不知道,凭印象写导致事实错误。已犯错误:格拉利什(曼城→罗马)、恩佐(切尔西→利物浦?)、达尼洛(尤文→弗拉门戈,2025年1月就走了)、姆巴佩(巴黎→皇马)、卡塞米罗(曼联→迈阿密国际)等。AI的印象改不了,只能用方法弥补。
| 操作类型 | 必须先查什么 | 禁止行为 |
|---|---|---|
| 写desc(前瞻/后顾) | 查数据库确认:球员归属、主帅、球队名单、伤停球员是否在队 | 凭印象写"XX球员在XX队"、"XX主帅带队" |
| 分配任务给协作伙伴 | 查数据库确认:任务里的球员/球队在我们系统里存在,归属正确 | 凭印象分配"查尤文的达尼洛"(尤文不在我们系统,达尼洛已转会) |
| 审计协作伙伴交付包 | 先过滤掉我们系统里不存在的球队/球员,只处理存在的 | 看到交付包里有juventus.js就直接审计,不先确认我们有没有尤文页面 |
| 更新球员数据 | 查数据库确认:球员当前在哪个球队,字段是否存在 | 凭印象更新"姆巴佩在巴黎的数据"(实际已在皇马) |
| 新增比赛/赛程 | 查数据库确认:对阵双方球队在我们系统里存在,球员名单正确 | 凭印象新增"巴黎vs皇马"(实际姆巴佩已在皇马,对阵关系变了) |
以下球员已确认转会,绝对不能再按原球队写:
| 球员 | 原球队 | 现球队 | 转会时间 | 确认来源 |
|---|---|---|---|---|
| 格拉利什 | 曼城 | 罗马 | 2026年夏窗 | 双源验证 |
| 姆巴佩 | 巴黎圣日耳曼 | 皇家马德里 | 2024年夏窗 | 官方宣布 |
| 达尼洛 | 尤文图斯 | 弗拉门戈 | 2025年1月 | FBref/Transfermarkt |
| 卡塞米罗 | 曼联 | 迈阿密国际 | 2026年夏窗 | 双源验证 |
| 摩根·罗杰斯 | 阿斯顿维拉 | 切尔西 | 2026年夏窗 | 双源验证 |
| 埃兹里·孔萨 | 阿斯顿维拉 | 阿森纳 | 2026年夏窗 | 双源验证 |
注意:这个名单只是"已确认的重大转会",不是全部。操作前还是必须查数据库确认,不能只看这个名单。
定位:观赛指南+看点提炼,不是流水账(用户会看集锦,过程不重复)。
只写时间轴和集锦看不到的东西:
常规进球不写(进球只进goals时间轴,集锦能看到)。
不是"谁受伤了",而是"这个球员受伤对战术有什么影响"。
核心原则:前瞻是"提醒下一场看什么",不是"伤病名单播报"。读者想看的是这场比赛有什么看点、什么变量可能决定比赛,不是谁谁谁又伤了。
| 次数 | 时间点 | 内容来源 | 写什么 |
|---|---|---|---|
| 第一次 | 比赛结束后1小时内 | 直播吧/懂球帝即时战报+赛后采访 | 初步后顾:比分、关键事件、意外变化(红牌/伤退/新援首秀)、主帅赛后即时采访要点 |
| 第二次 | 比赛结束后6-12小时 | 国内博主复盘(懂球帝专栏/直播吧战术板/虎扑评分) | 补充:战术转折、争议判罚分析、球员状态信号、关键数据 |
| 第三次 | 比赛结束后24-48小时 | The Athletic/BBC/队报/图片报等深度分析 | 提炼:轮换深意、数据背后的趋势、长期影响、下一轮前瞻 |
| 次数 | 时间点 | 内容来源 | 写什么 |
|---|---|---|---|
| 第一次 | 新增比赛时(赛前7-14天) | 赛程公布+基本背景 | 初步前瞻:比赛性质、排名背景、大致看点 |
| 第二次 | 比赛前2-3天 | 国内博主赛前观点(懂球帝/直播吧前瞻) | 补充:伤停传闻、预计首发、核心对位 |
| 第三次 | 比赛前12-24小时 | 最终首发确认+国外媒体赛前分析 | 最终前瞻:确认伤停、首发预测、临场变量 |
每篇desc ≤90字,六要素压缩在一段内,不强制分段,信息密度优先:
① 看点钩子:这场为什么值得看,一句话具体信息("曼城若再平分差拉到5分"),禁"巅峰对决""焦点之战"。
② 背景数字:联赛位置/排名/分差/晋级意义,必须带数字。
③ 状态信号:最近走势一个趋势(连续不胜/主场强/进多丢多),不罗列战绩。
④ 战术对位:预期阵型/关键对位/风格碰撞一句话。
⑤ 伤停变量:只核心主力+影响,不列名单。
⑥ 信息量收尾:一个悬念或具体看点,禁"拭目以待"。字数硬上限90字,超了砍废话保事实。
禁用的AI腔(出现即返工):①排比/对仗句("不仅是实力的较量,更是意志的比拼");②总分总结构、每段首句都是主题句;③"值得注意的是""不可否认""综上所述""让我们拭目以待";④三个一组过度工整的并列;⑤空泛形容词(精彩绝伦/荡气回肠/技惊四座);⑥每篇固定"北京时间X月X日"开头;⑦完美总结式收尾(把全文复述一遍)。
人味写法(强制):①写具体(第几分钟、谁、什么数据、什么细节),具体本身就没AI味;②用引语(主帅发布会原话、球员赛后采访);③换视角(站在主队球迷/客队/中立角度看同一件事);④口语化连接("有意思的是""但问题在于""说到底");⑤留白不把话说满("这可能是""关键看");⑥长短句交替、短句收尾;⑦允许带一点点立场和情绪,不装客观播音腔。
写作流程(每篇必走):先搜2-3个媒体来源→提取事实与引语→按六段骨架填内容→自查AI腔清单→交给用户审。初稿只写骨架+事实,不追求一次成型;用户的修改意见是训练信号,每轮意见沉淀回本节。
同等内容给巴西考察球员多一分关注,不贴显性标签:
descUpdated时间戳descUpdated 时间戳;无descUpdated=未走三次更新流程=不允许上线{team:"阿森纳", comp:"英超 第2轮", date:"2026-08-30 23:30",
home:"阿斯顿维拉", away:"阿森纳",
score:"", ended:false, goals:[["59'","萨卡","a"]],
homeRank:5, awayRank:1, desc:"..."}
["分钟","进球者","h/a","点"/"乌"(可选)]["63'","佩德罗","a","乌"](算布莱顿进球)https://m.qiumiwu.com/league/yingchao/standings、西甲 https://m.qiumiwu.com/league/xijia/standings,其余联赛站内搜)https://sports.sina.com.cn/g/pl/table.html、7M体育、联赛官网;程序化可用football-data APIlast updated时间戳| 联赛 | 色条 | 卡片背景 |
|---|---|---|
| 英超 PL | #F9A825 金黄 | #FFF8E1 浅黄 |
| 西甲 PD | #2E7D32 绿 | #E8F5E9 浅绿 |
| 法甲 FL | #0D2240 藏蓝 | #EBEEF5 浅蓝灰 |
| 欧冠 CL | #1565C0 宝蓝 | #E3F2FD 浅蓝 |
| 德甲 BL | #D20514 红 | #FFEBEE 浅红 |
| 国际赛 INTL | #1B5E20 深绿 | #C8E6C9 浅绿 |
注:意甲SA、葡超PO目前只进积分榜/射手榜(7联赛),比赛卡片暂未设专属色,若后续这两个联赛出现比赛卡片再补色,不影响积分榜显示。
<script src="data/players/arsenal.js"></script>加载对应球队数据<script src="data/matches.js"></script>等加载比赛/积分榜/射手榜数据git status确认当前状态git add -A && git commit -m "描述修改内容"git log查看历史,git reset --hard <commit_id>回滚到任意版本./scripts_ops/deploy_site.sh --cos-onlyhttps://bxgj2030.top/<script src="data/players/arsenal.js?v=YYYYMMDDHHMM"></script>Cache-Control: no-cache, no-store, must-revalidate + Pragma: no-cache + Expires: 0git log --oneline查看历史,git reset --hard <commit_id>回滚<title>标签 + 积分榜header的.version-numbr:1)执行规则:做完一项划掉一项,绝对不重复列已完成事项;每次更新手册前先核对本清单。
data/matches.js,HTML只负责渲染(2026-09-06完成)data/standings.js 和 data/scorers.js(2026-09-06完成,同时修复deploy.sh的desc检测脚本)Shots Taken321.4768),升级到v4,支持10个FootyStats字段(含aerialDuelsWon)(2026-09-06完成)手册版本:v2.3 精简版(2026-09-07 逐字逐句校订)
v2.3本次校订:①在线地址/部署平台由surge.sh全面改为又拍云(deploy_upyun_sdk.py);②球队规模统一为31俱乐部+9国家队共40个球员页/数据文件;③数据源口径统一——积分榜/射手榜一律"直接抄现成榜单不自己算"(主源球迷屋/新浪/联赛官网,football-data API作程序化备选,禁用FBref抄英超),场均per90主源由FBref/FootyStats改为StatMuse(第12章),FootyStats旧方案3.5.1标废弃;④联赛数统一为7个(PL/PD/BL/FL/SA/PO/CL),删除"法甲德甲已删除"的错误说法;⑤StatMuse实际成果更正为26队737人、29项非门将+14项门将;⑥备份云端改为又拍云。
v2.2历史:从约19000字精简,删除历史试错记录、重复验证过程、已完成待办;保留执行规则、数据源映射、检查清单、更新流程。
完整历史记录:见 changelog.html
目的:本地+云端双备份,每次数据更新留痕,出问题能精准定位到某次更新、某个字段,方便回滚和排查。避免出现云端数据丢失、本地无备份的情况。
双备份架构:
工具位置:
tools/backup_full.js — 全量备份工具(备份整个网站,打包tar.gz,推荐每次部署前使用)tools/backup_data.js — 数据备份工具(仅备份data目录)tools/diff_update.js — 数据对比工具tools/check_dates.js — 比赛日期检查工具(每次部署前必须运行,检查日期异常)使用流程(每次更新/部署必走):
node tools/backup_full.js — 备份整个deploy_temp目录(含index.html、js、css、data、手册等全部89个文件),打包成tar.gz到backup/,自动清理30天以上旧备份node tools/backup_data.js — 备份当前data目录到backup/时间戳/node tools/diff_update.js backup/时间戳 deploy_temp/data — 生成HTML变更报告到diff_reports/目录node tools/check_dates.js — 扫描所有比赛日期,发现异常立即报警(未赛比赛日期已过去/已赛比赛日期在未来),有错误必须修正后才能部署全量备份说明:
报告内容:
注意事项:
| 联赛 | 代码 | 球队 |
|---|---|---|
| 英超 | PL | 阿森纳、曼城、利物浦、切尔西、热刺、曼联、纽卡、维拉、布莱顿、水晶宫、布伦特福德、埃弗顿、诺丁汉森林、富勒姆、伯恩茅斯、桑德兰、利兹、伊普斯维奇、考文垂、赫尔城 |
| 西甲 | PD | 巴萨、皇马、马竞、贝蒂斯 |
| 德甲 | BL | 拜仁、多特 |
| 法甲 | FL | 巴黎 |
| 意甲 | SA | 国米、罗马 |
| 葡超 | PO | 波尔图 |
| 巴西国家队 | 无 | 特殊处理,显示"暂无联赛数据(后续将显示世预赛数据)" |
网站:StatMuse.com
特点:自然语言查询,返回结构化JSON数据嵌入HTML中。支持批量获取球队所有球员的多项统计数据。
https://www.statmuse.com/fc/ask/most-{统计类型}-{球队slug}-player-{赛季}-season
示例:
https://www.statmuse.com/fc/ask/most-possession-won-arsenal-player-2025-26-seasonhttps://www.statmuse.com/fc/ask/most-expected-goals-real-madrid-player-2026-27-season说明:下表是2026-09-06最早验证可行的12项;2026-09-06晚已由协作方全量抓取,实际每个球员拿到 29项非门将数据 + 14项门将专属数据(Per90口径),成果存于 statmuse_full_data.json(26队/737人,0失败)。完整字段以该文件和下表字段对照为准,下表URL关键词仍然适用。
| 统计类型 | URL关键词 | JSON字段名 | 数据库字段 | 说明 |
|---|---|---|---|---|
| 夺回球权 | most-possession-won | REC | ballRecoveries | 防守核心数据 |
| 进球 | most-goals | G | goals | |
| 助攻 | most-assists | A | assists | |
| 射门 | most-shots | SH | shots | |
| 射正 | most-shots-on-target | SOT | shotsOnTarget | |
| 关键传球 | most-key-passes | PASS-KEY | keyPasses | 注意字段名是PASS-KEY,不是KP |
| 过人 | most-dribbles-completed | DRIB | dribbles | 注意字段名是DRIB,不是DRB |
| 抢断 | most-tackles | TKL | tackles | |
| 拦截 | most-interceptions | INT | interceptions | |
| 争顶成功 | most-aerial-duels-won | AER-W | aerialDuelsWon | 注意字段名是AER-W,不是ADW |
| 预期进球 | most-expected-goals | xG | xG | |
| 预期助攻 | most-expected-assists | xA | xA |
| 球队 | StatMuse slug | 数据库文件名 |
|---|---|---|
| 阿森纳 | arsenal | arsenal.js |
| 曼城 | manchester-city | man_city.js |
| 利物浦 | liverpool | liverpool.js |
| 切尔西 | chelsea | chelsea.js |
| 热刺 | tottenham-hotspur | spurs.js |
| 曼联 | manchester-united | man_utd.js |
| 纽卡斯尔 | newcastle-united | newcastle.js |
| 阿斯顿维拉 | aston-villa | aston_villa.js |
| 布莱顿 | brighton-&-hove-albion | brighton.js |
| 水晶宫 | crystal-palace | crystal_palace.js |
| 布伦特福德 | brentford | brentford.js |
| 埃弗顿 | everton | everton.js |
| 诺丁汉森林 | nottingham-forest | nottingham_forest.js |
| 富勒姆 | fulham | fulham.js |
| 伯恩茅斯 | bournemouth | bournemouth.js |
| 桑德兰 | sunderland | sunderland.js |
| 利兹联 | leeds-united | leeds.js |
| 皇马 | real-madrid | real_madrid.js |
| 巴萨 | barcelona | barcelona.js |
| 马竞 | atletico-madrid | atletico.js |
| 皇家贝蒂斯 | real-betis | betis.js |
| 拜仁 | bayern-munich | bayern.js |
| 多特蒙德 | borussia-dortmund | dortmund.js |
| 巴黎圣日耳曼 | paris-saint-germain | psg.js |
| 国际米兰 | inter | inter.js |
| 罗马 | roma | roma.js |
关键脚本:batch_all_stats.js(项目根目录)
步骤:
"编码,需要先替换为普通引号"NAME":[0,{"value":[0,"开始)"字段名":[0,{"value":[0,值],"display":[0,"显示值"]}值 / (出场时间 / 90)advanced对象中注意事项:
⚠️ 字段命名铁律(2026-09-07 血的教训):预期进球/预期助攻在不同批次脚本里出现过两套写法——全拼expectedGoals/expectedAssists和短名xG/xA,而渲染层(ADV_POSITION_CONFIG、ADV_FIELD_LABELS、双排对齐)只认短名。曾导致 387 人次的 xG/xA 格子空白。规定:所有新抓取、新合并、派给协作方的数据,per90 一律用短名 xG/xA,禁止再写全拼。common.js 已加 normalizeAdv() 在渲染前兜底转换(短名优先、转后删全拼、用副本不污染原数据),但数据层仍必须统一,不能依赖兜底。同理字段单位、口径以第12章对照表为准,不得自造别名。
| 数据源 | 优点 | 缺点 |
|---|---|---|
| StatMuse | 批量获取、字段齐全、支持历史赛季、Node.js直接访问、无反爬 | ask聚合稳定覆盖五大联赛+巴黎/国米/罗马/AC米兰;不覆盖英冠(coventry/hull/ipswich)和葡超(porto),试各种slug都422,别纠缠 |
| FootyStats | 数据详细、有advanced区块 | Cloudflare反爬、需webfetch、单球员页面 |
| FBref | 数据最权威 | Cloudflare反爬、无法批量、英超更新滞后 |
| FotMob | 界面友好 | 默认显示当前赛季、API禁止访问 |
node fetch_2026_27.js 抓27队全部(约9分钟,可加队slug参数单队重抓),产出 statmuse_2026_27_raw.jsonnode build_map_fingerprint.js 用25-26数值指纹反推重建英文→中文映射 name_map_auto.json(见12.9)node match_2026_27.js 三级匹配(auto本队/transferred转会/miss无名单),产出 match_report.json + need_review.jsonnode merge_2026_27.js 把auto+transferred写入球员文件(旧值备份到per90_2526)python3 deploy_2026_27.py 精准部署URL模板:https://www.statmuse.com/fc/ask/{urlSlug}-{teamSlug}-player-2026-27-season,Node https.get直连,UA必须用Chrome120桌面UA。
指纹反推映射法(解决"英文→中文匹配率低"的关键,比人工建name_map高效得多):25-26全量数据(statmuse_full_data.json,英文名+per90数值)与现有球员文件(中文名+相同per90数值),用 ballRecoveries/keyPasses/tackles/dribbles/interceptions/aerialDuelsWon/crosses/clearances 这8个命名一致字段拼数值指纹,至少3个字段全等即判定同一人,自动重建英文→中文映射。25-26实测737人指纹配对536人(72.7%),叠加旧表后26-27自动匹配率从21.9%→78.1%。
译名全称/简称坑:name_map里常是全称"哈里·凯恩",球员文件里是简称"凯恩",精确相等会误判缺失。匹配函数要做 cnCore(取"·"后部分)+ 双向包含匹配,多人同时命中才标歧义人工确认(match_2026_27.js 的 findInRoster 已实现)。
⚠️ 血的教训(2026-09-07):甲方早已明确「场均数据冬窗后才碰26-27、半年更一次」,但当时只被授权做列表页三个基础数,却擅自把全队per90从25-26整体覆盖成才打3轮的26-27并上线,属于越权。铁律:更改per90赛季口径、整批覆盖数据前,必须得到甲方明确授权;讨论方案阶段不得擅自上线。本次最终决策是不回滚、改为双赛季同屏保留。
注意:过人是现代全能中锋(罗纳尔多、亨利、哈兰德、伊萨克)的核心武器之一,必须放在位置相关,不能放展开看。
注意:解围是中后卫四大核心维度之一(Gradient Sports数据确认),必须放在位置相关。
等临时工全量数据(statmuse_full_data.json)抓回来后,合并到数据库,然后按照本规则实现详情页的颜色区分和展开功能。
在补全球员缺失数据之前,必须先做三个圆分类,把缺失球员按数据可得性分成五类,然后再派任务。不能盲目地一个一个查,否则会浪费大量时间和人力。
三个圆的定义:
2026-09-07的教训:之前补全88名缺失球员时,没有先做三个圆分类,直接派任务让师姐一个一个查,导致:
正确做法:先花10分钟做三个圆分类,把88人分成五类,然后按分类派任务,一次性做完,不用一轮一轮补。
| 分类 | 定义 | 处理方式 | 优先级 |
|---|---|---|---|
| 1. 在小圆里 | 球员25-26赛季在你之前已经抓过的球队中 | 直接从已有数据文件(如statmuse_full_data.json)拿,必须找到,找不到就是名字匹配问题 | 最高(最快,零成本) |
| 2. 在大圆里但不在小圆里 | 球员25-26赛季在数据源网站有数据的球队中,但你之前没抓这些队 | 重新去数据源网站抓这些球队的数据(一次抓整队,不是一个球员一个球员抓) | 高(一次抓整队,效率高) |
| 3. 不在大圆里 | 球员25-26赛季在数据源网站也没有数据的球队中 | 换其他数据源(如FBref),或确认确实没有数据后撇开 | 中 |
| 4. 替补门将/青年球员 | 替补门将、青年队球员、赛季无出场的球员 | 直接撇开,肯定没有per90数据,不用浪费时间 | 最低(直接跳过) |
| 5. 不确定 | 不确定球员25-26赛季在哪支球队 | 先查清楚25-26赛季在哪队,然后按上述四类分类处理 | 先查再分类 |
小圆:statmuse_full_data.json里的26支球队
大圆:StatMuse网站覆盖的所有球队(五大联赛+其他联赛)
球员圆:88名缺失per90数据的球员
分类结果:
| 分类 | 人数 | 处理方式 |
|---|---|---|
| 1. 在小圆里 | 16人 | 直接从statmuse_full_data.json拿,必须找到(马丁内斯、热苏斯、阿德耶米等) |
| 2. 在大圆里但不在小圆里 | 10人 | 重新抓6支球队数据(沃尔夫斯堡、阿贾克斯、佛罗伦萨等) |
| 3. 不在大圆里 | 2人 | 赛季无出场/FBref无此人,直接撇开 |
| 4. 替补门将 | 25人 | 直接撇开,肯定没有数据 |
| 5. 不确定 | 35人 | 先查25-26赛季在哪队,再分类处理 |
效果:分类后,16人直接从已有数据拿(零成本),25人直接撇开(不用管),只剩下10人需要重新抓球队数据+35人需要先查,工作量减少了一半以上,而且不用一轮一轮补。
grep -c "per90_2526" 师姐文件;合并后必须全量检查grep -L "per90_2526" data/players/*.js,缺的从git旧提交恢复(git show 3a98bea:data/players/{slug}.js 提取per90_2526按name合并,不覆盖per90)<div class="team-header" id="teamHeader"></div>(用正则替换)背景:2026-09-07合并师姐"新球队建设"包时发生覆盖事故——师姐旧队更新文件不带per90_2526导致41队25-26数据丢失;师姐基于旧底版common.js导致27队sm字段为空;师姐HTML退回旧h1导致Header消失。全部是"合并时没自动关卡"造成的。
validate_merge.pypython3 validate_merge.py(查当前状态全绿)或 python3 validate_merge.py <交付zip>(合并前查交付包)id="teamHeader"与id="playerCount",版本号统一<div class="team-header" id="teamHeader">;缺则只提取JS/CSS不采用HTMLvalidate_merge.py <交付zip>,有警告先看:sm空→补sm;缺teamHeader→不采用其HTML;缺2526→确认是否旧队更新(是→禁止整包覆盖)validate_merge.py全绿背景:团队从2人(草包+婉师姐)扩展为多人(+临时工+外部评审),用户要求"按行业标准来办"。本章用六项行业公认标准逐条核对现有做法:GitHub Flow(Git工作流)、Conventional Commits(提交规范)、SemVer(语义化版本)、Code Review(代码评审)、CI/CD(发布流程)、RACI(权责矩阵)+ 异步协作最佳实践。核对结论:对的坚持、错的改正、缺的补上。
| 领域 | 行业标准 | 我们现状 | 核对结论 |
|---|---|---|---|
| 沟通机制 | 异步优先+文档化(低风险异步、高风险评审) | collab目录+传话"发布了"+正式回复格式 | ✅ 对,坚持(补:统一命名+回复时限) |
| Git工作流 | GitHub Flow:main永远可部署、小步提交、可回滚 | 每日git提交+回滚点(8e9e626/3a98bea等) | ✅ 对,坚持(补:提交信息规范) |
| 提交信息 | Conventional Commits:type(scope): desc | 中文长句(如"合并TASK-017赛程阵容Tab+版本号统一") | ❌ 改:从现在起用规范格式 |
| 版本号 | SemVer:MAJOR.MINOR.PATCH | 时间戳202609072300(缓存刷新参数) | ❌ 改:双轨制(见17.4) |
| 代码评审 | PR模板+自查清单+及时反馈 | validate_merge.py自动关卡+CEO人工验收回复 | ✅ 对,坚持(补:交付自查清单模板) |
| 发布流程 | 校验全绿→部署→回滚预案(触发/步骤/执行人) | validate全绿→部署 COS/CDN→git回滚 | ✅ 对,坚持(补:正式回滚预案) |
| 任务分配 | RACI矩阵(一事一A,A唯一) | 草包统筹、师姐功能侧、临时工一次性、用户拍板 | ✅ 方向对,正式化RACI(见17.5) |
<角色>_<类型>_<主题>_<日期>.extcaobao(草包)、wan(师姐)、tmp(临时工)、ext(外部评审)task(任务包)、delivery(交付包)、reply(回复)、note(规范/通知)、data(数据文件)caobao_task_TASK020_xxx_2026-09-08.zip、wan_delivery_TASK020_xxx_2026-09-08.zip、caobao_reply_验收TASK020_2026-09-08.txt行业标准:Conventional Commits(Angular/Vue/React等主流项目采用)。
落地格式(简化版):
feat(球员页): 新增阵容/赛程Tab切换 fix(首页): 修复手机返回空白(bfcache) docs(手册): 第17章协作标准 chore(部署): 部署v2300 data(球员): 补全曼城25-26场均数据
| 任务/角色 | 用户(甲方) | 草包(CEO) | 师姐(功能侧) | 临时工(数据侧) | 外部评审 |
|---|---|---|---|---|---|
| 需求决策 | A | C | I | I | I |
| 任务分配与验收 | A | R | I | I | I |
| 数据侧执行 | I | R | I | R(分派时) | I |
| 功能侧执行 | I | R(统筹) | R(执行) | I | I |
| 部署上线 | I | R | I | I | I |
| 质量评审 | I | A | R(自查) | R(自查) | C |
A=最终负责(唯一) R=执行 C=咨询 I=知情。核心:用户是唯一A(最终拍板);草包是部署/验收的A+R;师姐是功能执行的R;临时工是数据执行的R;外部评审只做C(提供意见不决策)。
标准发布流程(每步必须):
回滚预案(三件事写死):
任何交付包必须随附交付说明,包含以下五段(缺一段验收时退回补交):
【TASK-XXX 交付说明】 一、改动内容:改了哪些文件、各改了什么(逐条) 二、验证结果:怎么验证的、测了什么、结果如何(写明浏览器/尺寸) 三、自查清单: [ ] 数据文件带per90_2526(旧队更新时) [ ] common.js含全部关键函数+sm字段非空 [ ] HTML含id="teamHeader"(球员页) [ ] 版本号统一 [ ] 语法检查通过(node --check / chromium实测) 四、待确认问题:需要草包侧决策/确认的事项 五、数据说明:数据来源、口径、与上次的差异
事故复盘(2026-09-08):师姐TASK-017/016/019b三次交付均基于旧底版(缺goTo/缺Tab/sm空),草包每次"提取式打补丁"重复劳动。更深层:TASK-017合并时用 git stash push 备份,把含Tab的common.js存进stash后工作区被重置,导致Tab版本从未进入git历史、从未上线——备份用git commit,绝不用git stash(commit可追溯,stash会吞修改)。
行业标准对应:GitHub Flow的"单一事实来源+开工前拉最新+CI自动拦截"。落地为基线制度:
baseline/ 目录(最新common.js/index.html/模板)+ BASELINE.json(版本号+文件SHA256+关键函数指纹),用 python3 make_baseline.py 生成。协作方必须基于包内baseline修改,禁止用自己本地旧版。validate_merge.py <zip> 自动对比:交付的common.js/index.html若缺基线关键函数(renderTeamHeader/renderSeasonBlock/openPlayerModal/loadTeamStats/goTo/goBack/initViewTabs/renderSchedule等)→ 硬错误退回,机器拦截,不靠人工发现。<角色>_<类型>_<主题>_<日期>.ext(caobao_task_/wan_delivery_/caobao_reply_/caobao_note_)。使用流程:
# 草包发任务前 python3 make_baseline.py # 生成基线(版本+指纹) zip 任务包.zip 任务说明.txt baseline/ 相关文件 # baseline内含BASELINE.json # 合并交付包前(必须) python3 validate_merge.py 交付包.zip # 【7】基线一致性检查自动拦截旧底版
分工原则:草包负责决策/商量/大环境(统筹+验收+部署),师姐负责小检查/小改动执行。用户可直接向师姐派小任务。
A类(师姐可直接发布)——小改动:
B类(禁止直接发布,必须发草包验收合并):
工具包:deploy_single.py(单文件发布,含Content-Type映射+禁止名单)、validate_merge.py、make_baseline.py、BASELINE.json 已打包发师姐(collab/caobao_task_工作包_授权边界与直接发布)。
回滚责任仍在草包:师姐直接发布出错→草包用git/旧版回滚,不影响B类流程。
问题:此前"手动校验→手动部署→手动记版本",环节多易漏(曾发生没校验就发布、Tab版本被stash吞)。行业标准:发布流程固化成可执行命令,校验内嵌,不通过自动停止。
标准发布(一条命令):
python3 release.py "改动摘要" # 默认PATCH(bug修复) python3 release.py "改动摘要" --minor # MINOR(新功能) python3 release.py "改动摘要" --major # MAJOR(不兼容变更)
自动完成4步:①validate_merge.py全绿(红字禁止继续)②部署 COS/CDN ③git commit+打SemVer tag ④changelog.html记录。任何一步失败即停止,不产生半成品。
一键回滚(执行人:草包唯一):
python3 rollback.py # 回滚到上一个tag python3 rollback.py v1.4.0 # 回滚到指定版本 python3 rollback.py <commit> # 回滚到指定提交
自动完成:checkout目标版本→校验全绿→部署。未提交的新工作不受影响。
SemVer规则(已通过release.py强制):MAJOR=不兼容变更 / MINOR=新功能 / PATCH=bug修复。当前 v1.4.0。每次发布自动打tag+更新changelog,版本永远可追溯。
回滚预案三件事(17.6已定义,现在可执行):触发条件=validate报错/线上异常;操作=python3 rollback.py;执行人=草包。
铁律:写代码的人不测自己的代码。用户已明确不再当第一道测试(此前一直是用户发现错误,成本极高)。
测试三级流程:
RACI更新:师姐兼任QA(R:功能执行+测试执行),草包(A:验收/部署),用户(A:唯一拍板/终验)。
责任链:用户发现错误时,先查"自查漏了还是QA漏了",写进对应环节的检查清单,不允许同一类错误第二次到用户手里。
事故:TASK-017批量套用阿森纳模板生成62页,--team-color变量未按队替换,30个豪门页全变阿森纳红。代码检查(validate/chromium抓DOM)全部通过,因为代码结构没问题——只有人眼能发现"颜色不对"。
教训:
批量后必查命令:
# 检查是否全站同一个颜色(应多色) grep -l -- "--team-color: *#C41E3A" *_players.html | wc -l # 应远小于页面总数 grep -o -- "--team-color: *[^;]*" *_players.html | sort | uniq -c # 看颜色分布
为什么升级:用户指出"代码层面检查看不到颜色不对/元素挤压/超出边界/图标不显示"——TASK-020测试(Playwright抓DOM+查函数)通过了所有代码检查,但30个球队页全是阿森纳红色,代码检查完全没发现。行业标准:视觉回归测试+Vision Model QA(截图→AI看图→结构化断言),代码断言测不了"样子对不对"。
检测员职责:像用户一样打开网站、用眼睛看、逐寸逐按钮检查(手机375px为主+桌面1440px)。每页从上到下逐区域看图,每个按钮真的点。
逐寸检查清单(每页通用):颜色跟队走 / 队标图标无裂图 / 无挤压重叠错位 / 无溢出被切 / 间距一致 / 文字可读(深底浅字)/ 空态区分"无数据正常"与"应该有没有"。球员页:Header→数据栏6项→Tab→列表→详情弹窗(三色规则/双赛季同格/✕能关/返回)。
视觉基线(草包侧):
python3 /tmp/visual_shot.py # Playwright全站截图(线上URL,手机+桌面,等networkidle) python3 visual_diff.py # 改版后对比基线,列出视觉变化页,AI分类(有意/无意)
基线目录 /home/user/deploy_site_shots/{mobile,desktop}/(68页×2尺寸)。改版后diff >0.5%像素即需人工/AI确认变化是否有意。
铁律:检测结论必须"人眼看着对",不许"代码看起来对"。用户报的视觉问题优先于所有代码级检查。
一句话:足记不只是"网站+AI工具",而是让AI成为产品的心脏——数据活、质检AI首检、保护物理级、错误自动吸收、内容人机分层、体验拟人化、协作规则化。
七大系统:①数据神经系统(Schema+来源标注+交叉验证+异常检测)②质检免疫系统(L1机器→L2视觉→L3探索→L4师姐→L5用户)③安全防护(部署前快照+指纹校验+自动回滚+凭证管理+恢复演练)④自我进化(错误→代码级防再犯规则,不靠记性)⑤内容引擎(DESC护城河+AI周边素材/速览/故事)⑥体验系统(拟人化走查/个性化/仪式感/语音/问答)⑦协作操作系统(任务自动路由+决策自动化)。
铁律:每个教训必须变成"机器拦",不是"人记";重复决策自动化,人只管例外;检测结论必须"人眼看着对"。
完整版:docs/AI战略白皮书_v1_2026-09-08.md(collab: caobao_note_AI战略白皮书_v1_全盘AI规划_2026-09-08.md)
教训一:rsync污染——`rsync -a --delete ./ /home/user/deploy_site/` 把项目根的 node_modules/task*/worker*/zip/py 全部同步进部署目录,线上被传了1588个文件(原本只有134个)。铁律:deploy_site 只能由部署脚本(deploy_site.sh)维护,禁止rsync整个项目根;往部署目录同步必须用白名单式复制(只拷 *.html + data/)。
教训二:清理白名单——线上清理垃圾文件时,白名单漏了 `*_players.html`,62个球员页被误删(幸好本地完整,重部署恢复)。铁律:线上删除前必须列出完整白名单(*_players.html + index/manual/changelog + data/ + collab/),先dry-run打印清单确认再删。
教训三:又拍云SDK目录判断——getlist 返回 type='F' 是文件夹(不是'folder'),删目录要先递归删内容再删目录。写清理脚本时先验证 type 取值。
正确部署流程:改文件(项目根)→ validate_merge.py 全绿 → 用 deploy_site.sh(只认 deploy_site)→ curl 抽查线上 200 → visual_shot.py --new + visual_diff.py 看变化分类 → git commit。
本章一句话总结:协作的行业标准核心是"异步文档化沟通 + 一事一A + 校验关卡 + 可回滚"——我们已有骨架(collab/validate/每日git),补上命名统一、提交规范、SemVer、回滚预案、自查清单五块,即可按行业标准运转,多人加入不乱套。
触发背景:用户连续报出射手榜无国旗、按钮无描边、球衣配色丢失、列表卡片无赛季数据——这些我设的检查全没拦住。根因分析:
根因一:视觉diff只做"变化检测",不做"对错检测"——visual_diff 对比的是基线截图;基线=TASK-021修复后状态,基线里就没有国旗/描边/卡片数据,diff自然报"无变化"。基线固化错误=错误永远发现不了。
根因二:检查清单只查负面现象,不查正面验收——旧清单查"裂图/溢出/重叠",不查"射手榜必须有国旗、按钮必须有描边"这类产品定义。
根因三:产品定义散在聊天里,没固化——用户确认过的规则(球衣配色、双赛季同格、8色、列表页三数据)没变成可逐条勾选的机器清单。
升级方案(L3对错检测层):新增《产品验收标准清单》PRODUCT_ACCEPTANCE.md(collab: caobao_note_产品验收标准清单_2026-09-08.md),A-F六类条目全部固化用户确认过的产品定义。规则:
① 每次全站测试必须逐条对照该清单;② 清单比视觉diff权威,"看起来没坏"不算过,清单条目不满足=问题;③ 基线≠权威,清单=权威,基线缺项要补基线;④ 错误自动吸收:每次用户报错→先问"这为什么没拦住"→升级清单/检查工具→再改bug,不许先修后忘;⑤ 发现清单没覆盖的新产品定义→立即补清单。
检查体系四层(升级后):L1代码校验(validate_merge.py)→ L2视觉diff(visual_diff.py,变化检测)→ L3产品定义对照(PRODUCT_ACCEPTANCE.md,对错检测) → L4人眼(师姐TASK-026全量130页次)+ L5用户终验。
铁律:用户报的每个错,第一反应必须是"升级检查体系",第二才是改bug。改完bug必须把该错误写进验收清单,否则下次还是漏。
来源:不探索,查行业标准(Design Tokens 2014年Salesforce提出,全球设计系统标配;视觉回归测试为前端CI标准)。用户原话:"肯定有行业标准,你去抄嘛,探索个毛线"。
Design Tokens铁律:所有主题色走 var(--team-color)/var(--team-watermark-color),禁止裸写死(裸写死=违反单一事实来源,改一处坏一处)。三层:primitives(基础色值)→semantic(--team-color语义层)→component(组件层)。合规检查工具:python3 check_hardcoded_colors.py .(部署/测试前必跑,全库裸写死=0才放行)。
本次实战抓到的两个真bug:①62页详情弹窗评分均值ratingAvg裸写死color:#C41E3A(阿森纳模板残留24处)→已改var(--team-color);②球衣渐变第二段裸写死#EF0107:linear-gradient(180deg, var(--team-watermark-color,#EF0107) 0%, #EF0107 100%)——球衣"上半段跟队色、下半段永远阿森纳红"(皇马白球衣变白→红渐变)→已改双token。这两个都是"画好了又变"的代码级真凶。
视觉回归基线管理(行业标准):①基线快照必须进git版本控制(禁只存本地目录);②只有"有意的、用户/设计批准的"UI变化才更新基线;③基线来自"确认正确的需求",不来自"当前现状"——现状拍照=固化错误;④基线生成环境=测试环境(测线上URL,禁止测本地臆想版);⑤差异=回归缺陷,先审后更新。
组件集中原则:同样的样式(弹窗rating/卡片/Header)必须集中在common.css,禁止逐页复制62份——复制62份=改1处要改62处,漏1个就"变了"(62页#f8f8f8/#888/#333同类样式逐页复制,待收敛)。
行业标准:CI/CD流水线在合并前自动跑测试门禁。我们无CI服务器(静态站+又拍云+师姐协作),适配为本地发布门禁脚本:python3 release_gate.py,5关全绿才允许合并/部署。
五关:①validate_merge全绿(数据+代码+基线7关)②Design Tokens合规(check_hardcoded_colors全绿)③页面结构完整(62页teamHeader/ts-goals/common.js/goBack)④数据一致(62文件≥15人+seasonStats存在)⑤git工作区干净。
红灯=预期拦截也记录:门4红灯≠禁止前进,是"待办清单"(如seasonStats=TASK-024进行中),部署前确认红灯项有明确负责人在做即可。
问题:旧流程"师姐做A→交付→草包验证合并(15-20分钟)→师姐干等→发结果→做B"串行阻塞,师姐交付后空转,任务排队积压(025/026曾长期排队),全量覆盖推进慢。
规则(流水线缓冲,参考生产管理):①师姐手上常备≥2个任务(交付前就已拿到下一个);②交付-验证异步化:她交付→立即做手上下一个,草包异步验证→验证结果发collab→她有错才修,不阻塞主流水;③草包验证必须脚本化提速(发布门禁+自动抽查),目标10分钟内闭环;④任务包一次多批派发(如027+025+026一起排队),师姐按编号顺序执行;⑤版本基线:她每次交付前确认基于线上最新版(TASK-022教训:测旧版=白测)。
事故:皇马红牌显示1.75/7张,西甲官网实际=0张(4轮黄牌8、红牌0);切尔西2.67/8张同样离谱。StatMuse球队红牌字段不可靠,已全库置空(77处),待英超/西甲官方源逐队核实后补,宁缺毋滥。
铁律:①任何per90类数据入库前做合理性检查:红牌per90>0.5、单场>2张、出场数>赛程轮次×2 等必须人工核实;②新数据源首次使用前,用已知球队(如皇马红牌=0)交叉验证;③per90字段语义固定=25-26上赛季数据,26-27本赛季场均冬窗后统一补充,禁止拿旧数据冒充新赛季(弹窗26-27列无数据显示"-",不fallback)。
事故:TASK-025扫描发现per90字段赛季混合无标记——同一队内拉亚per90.minutes=270(26-27的3场)与萨利巴=2614(25-26整季)并存,数据语义被破坏。根因:per90曾在多轮任务中被部分覆盖(StatMuse 26-27赛季初数据混入25-26基准)。
治理方案(已执行,TASK-025B):①per90统一=25-26上赛季基准(数据源:statmuse_full_data.json 26队全量英文名匹配530人 + per90_2526备份412人,两源皆无=置空不编818人);②per90Season字段全库统一标"2025-26"(杜绝无标记混放);③26-27本赛季场均冬窗后统一更新(用户拍板,禁止赛季初小样本提前补——已证实1分钟传360球伪值);④零分母治理:minutes缺失/0带场均值的置空;⑤门将字段单独核查补齐。
新铁律:①per90语义固定=25-26上赛季,26-27数据只存seasonStats(apps/goals/assists/cleanSheets),冬窗后整体换新;②任何per90改动必须同步per90Season标记;③字段短名铁律(手册12.6):expectedGoals/expectedAssists全拼一律xG/xA(全库654处已清零);④从StatMuse全量复制数据时禁止带"门将模板值"(arsenal 3人advanced曾整段被拉亚模板覆盖,已用全量正确值修复);⑤新数据入库先做跨源交叉验证(19.7)。
背景:用户连问"AI检查到底行不行""你是不是没好好检查",并用两张截图证明代码级检查抓不到的视觉问题(拜仁队名时间黏连/巴黎时间缺前缀/利物浦队徽爆框/国旗缺失)。结论:代码检查(L1-L3)拦数据与结构,拦不住"人眼级排版与交互"。
拟人检查三查法(《视觉检查操作方法》collab存档):①截图查:手机414+桌面1280双宽度chromium headless真渲染截图(不受缓存干扰);②DOM查:getComputedStyle查主题色/球衣渐变真实样式(截图看不出的用这个);③交互查:JS真点每个可点元素(切Tab/开弹窗/验证跳转目标)。
检查经验库(盖楼式防漏,docs/检查经验库_人眼发现.md):每次用户/拟人发现漏网问题→立即追加为"必查项"→下次检查必须验证。覆盖面只增不减,历史漏网(球衣染错色/全队变红/按钮无描边/弹窗同值冒充/长队名黏连/队徽爆框/国旗缺失/按钮行为不对…)全部进库。
行业标准融入(ISTQB/黑盒测试查证):①四级测试:组件(JSON合法)→集成(页面↔数据)→系统(师姐全站测试)→验收(用户终验);②用例设计四法:场景法(用户主流程走通)、边界值(0出场/末位排名/空数据/超长队名/OVR极值)、错误猜测法(=检查经验库)、回归(改动后全站复测);③兼容性:手机375+桌面1280必测;④缺陷管理:一事一报/客观描述/跟踪到底。
铁律:检查动作全部脚本化/清单化可分配,草包不闷头全看——归纳方法→派师姐执行→草包验收,效率2/3师姐、1/3草包。
甲方定调:验收标准=工具能不能自己发现所有问题并修复,而非产品形态。检测能力分四层,逐层加厚:
L1数据层(全量):JSON合法/字段口径/缺失/零分母/赛季混合——validate_merge.py+自动化断言。盲区:值本身对错(需官方源人工核实,如红牌)。
L2结构层(全量):页面完整性/引用残留/链接/硬编码颜色——断言脚本+check_hardcoded_colors.py。盲区:排版视觉。
L3视觉层(人眼级):破图/溢出/颜色/间距/遮挡——Playwright手机414+桌面1280双宽度截图+DOM复核。盲区:截图看不出但人眼难受的细节。
L4交互层(全量):每个按钮真点/Tab/弹窗/跳转——JS交互自动化。盲区:设计合理性判断(需甲方球商)。
漏检进化机制(盖楼式,已生效):每次甲方/拟人发现漏网→根因分析(为什么没查到)→补进检查经验库必查项→下次必查。覆盖面只增不减,检测能力随轮次加厚。
效率目标:问题从发现到修复上线闭环≤2小时;执行完工作立即巡检,不等定时。
问题:草包与师姐经又拍云collab异步交换文件,无通知机制,此前全靠用户传话"发布了",用户被迫当人肉信使。
双向自动轮询(已上线):草包侧定时任务「collab交付自动巡检」(每30分钟):跑 poll_collab.py 查collab新 wan_delivery_* → 自动下载→验证→合并→门禁→部署→git→汇报。师姐侧同构(每30分钟查 caobao_task_* 自动开工)。补充(2026-09-08脱手测试):草包每次执行完工作(发任务包/部署/改数据/更新手册)后,立即手动跑一次 poll_collab.py 检查师姐新交付,不等30分钟定时;师姐同理(每次交付完立即查新任务)。目标是全自动闭环、用户完全脱手。
休眠/唤醒协议:①用户1小时无交流=离线:巡检触发时读 /tmp/collab_inbox/active.txt 时间戳(草包每回复更新),超3600秒→停本任务+传 caobao_note_休眠 通知→师姐见文件自停;②用户回来发消息=自动唤醒:恢复任务+传 caobao_note_唤醒 通知→师姐自恢复;③消耗优化:活跃期30分钟、休眠期零消耗,用户手动通知两边兜底。
铁律:草包每轮回复顺手更新active.txt(收到用户消息的第一时间写当前时间戳,不攒不拖);休眠/唤醒通知文件命名 caobao_note_休眠_日期.txt / caobao_note_唤醒_日期.txt,师姐轮询按优先级处理(休眠>唤醒>任务包>说明)。
防御式判定(2026-09-08教训修正):active.txt 缺失或读取失败 → 一律视为用户活跃,禁止判离线。休眠的唯一依据是「文件存在且确实超过3600秒」。宁可多跑一次巡检,绝不因文件缺失误休眠——用户全程在聊天却被判定离线导致师姐休眠,就是这个漏洞(15:15误休眠事故)。巡检任务query已同步此逻辑。
历史教训:师姐交付曾用 wan_delivery_* / wan_TASK026_截图* / 交付N_* 三种风格顺手命名,导致巡检脚本两次漏检。现定死四类命名,所有协作方必须严格使用,禁止任何变体:
① 师姐交付:wan_delivery_任务号_内容简述_日期.zip(示例 wan_delivery_TASK026FIX_图标与返回按钮修复_2026-09-08.zip)——内容简述用"修复/数据/报告"等词,中间产物截图单独打 wan_delivery_任务号_截图_日期.zip。
② 草包派任务:caobao_task_任务号_内容简述_日期.zip。
③ 草包通知/决策:caobao_note_类型_日期.txt(类型=休眠/唤醒/决策/说明)。
④ 禁止:不带delivery/task/note前缀的裸命名(如"交付1")、中文无后缀(交付3_TASK017)、时间戳缺失。
商业化方向已交底(2026-09-08):项目已进入商业化准备阶段,026终测通过后输出《商业化就绪度清单》。
背景:出场/进球/助攻/零封为一级数据,每周必刷。2026-09-09 教训:串行抓取会卡死(48队×2页串行+超时挂起,15队后停摆),必须用并发。
https://www.statmuse.com/fc/ask/most-appearances-{teamSlug}-player-2026-27-seasonmost-save-pct 页(CS/SV/GC 同页返回),savePct=SV/(SV+GC)×100(坑4)most-apps 是 422 死路,出场必须用 most-appearances(most-appearances / most-games-played 均可,实测 200)t042/work/fetch_ss_fast.py(并发版),禁止串行/禁止一次只抓一页https://www.statmuse.com/fc/ask/{teamSlug}-players-2026-27-season(同源、一页整队名单,号码→英文名)t042/work/merge_ss_2627.py