diff --git a/.playwright-mcp/console-2026-07-31T07-54-18-095Z.log b/.playwright-mcp/console-2026-07-31T07-54-18-095Z.log
new file mode 100644
index 0000000..5d1fcac
--- /dev/null
+++ b/.playwright-mcp/console-2026-07-31T07-54-18-095Z.log
@@ -0,0 +1 @@
+[ 9545ms] [WARNING] Manifest: property 'start_url' ignored, should be same origin as document. @ https://git.zones.sbnews.net/assets/site-manifest.json:0
diff --git a/.playwright-mcp/console-2026-07-31T07-59-11-220Z.log b/.playwright-mcp/console-2026-07-31T07-59-11-220Z.log
new file mode 100644
index 0000000..06c2536
--- /dev/null
+++ b/.playwright-mcp/console-2026-07-31T07-59-11-220Z.log
@@ -0,0 +1 @@
+[ 11298ms] [WARNING] Manifest: property 'start_url' ignored, should be same origin as document. @ https://git.zones.sbnews.net/assets/site-manifest.json:0
diff --git a/.playwright-mcp/page-2026-07-31T07-54-23-946Z.yml b/.playwright-mcp/page-2026-07-31T07-54-23-946Z.yml
new file mode 100644
index 0000000..dc92fc0
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-31T07-54-23-946Z.yml
@@ -0,0 +1,75 @@
+- generic [active] [ref=e1]:
+ - generic [ref=e2]:
+ - navigation "导航栏" [ref=e3]:
+ - generic [ref=e4]:
+ - link "首页" [ref=e5] [cursor=pointer]:
+ - /url: /
+ - link "探索" [ref=e7] [cursor=pointer]:
+ - /url: /explore/repos
+ - link "帮助" [ref=e8] [cursor=pointer]:
+ - /url: https://docs.gitea.com
+ - generic [ref=e9]:
+ - link "注册" [ref=e10] [cursor=pointer]:
+ - /url: /user/sign_up
+ - link "登录" [ref=e14] [cursor=pointer]:
+ - /url: /user/login
+ - main "首页" [ref=e18]:
+ - generic [ref=e20]:
+ - img "Logo" [ref=e21]
+ - generic [ref=e22]:
+ - heading "HAHA" [level=1] [ref=e23]
+ - heading "一款极易搭建的自托管 Git 服务" [level=2] [ref=e24]
+ - generic [ref=e25]:
+ - generic [ref=e26]:
+ - heading "易安装" [level=1] [ref=e27]
+ - paragraph [ref=e30]:
+ - text: 直接
+ - link "运行适合您平台的二进制文件" [ref=e31] [cursor=pointer]:
+ - /url: https://docs.gitea.com/installation/install-from-binary
+ - text: ,通过
+ - link "Docker" [ref=e32] [cursor=pointer]:
+ - /url: https://github.com/go-gitea/gitea/tree/master/docker
+ - text: 部署,或使用
+ - link "软件包" [ref=e33] [cursor=pointer]:
+ - /url: https://docs.gitea.com/installation/install-from-package
+ - text: 安装。
+ - generic [ref=e34]:
+ - heading "跨平台" [level=1] [ref=e35]
+ - paragraph [ref=e38]:
+ - text: 任何
+ - link "Go 语言" [ref=e39] [cursor=pointer]:
+ - /url: https://go.dev/
+ - text: 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行!
+ - generic [ref=e40]:
+ - generic [ref=e41]:
+ - heading "轻量级" [level=1] [ref=e42]
+ - paragraph [ref=e45]: 一个廉价的树莓派就足以满足 Gitea 的最低系统硬件要求。最大程度节省您的服务器资源!
+ - generic [ref=e46]:
+ - heading "开源化" [level=1] [ref=e47]
+ - paragraph [ref=e50]:
+ - text: 所有代码都开源在
+ - link "gitea.dev" [ref=e51] [cursor=pointer]:
+ - /url: https://gitea.dev
+ - text: ,还等什么?赶快加入我们来
+ - link "共同发展" [ref=e52] [cursor=pointer]:
+ - /url: https://github.com/go-gitea/gitea
+ - text: 这个伟大的项目,成为贡献者吧!
+ - group "页脚" [ref=e53]:
+ - contentinfo "关于软件" [ref=e54]:
+ - link "由 Gitea 强力驱动" [ref=e55] [cursor=pointer]:
+ - /url: https://about.gitea.com
+ - generic [ref=e56]: "版本: 1.27.1"
+ - generic [ref=e57]:
+ - text: "页面:"
+ - strong [ref=e58]: 1ms
+ - text: "模板:"
+ - strong [ref=e59]: 1ms
+ - group "链接" [ref=e60]:
+ - menu [ref=e61] [cursor=pointer]:
+ - generic [ref=e62]: Auto
+ - menu [ref=e66] [cursor=pointer]:
+ - generic [ref=e67]: 简体中文
+ - link "许可证" [ref=e70] [cursor=pointer]:
+ - /url: /assets/licenses.txt
+ - link "API" [ref=e71] [cursor=pointer]:
+ - /url: /api/swagger
\ No newline at end of file
diff --git a/.playwright-mcp/page-2026-07-31T07-59-17-752Z.yml b/.playwright-mcp/page-2026-07-31T07-59-17-752Z.yml
new file mode 100644
index 0000000..58742b1
--- /dev/null
+++ b/.playwright-mcp/page-2026-07-31T07-59-17-752Z.yml
@@ -0,0 +1,75 @@
+- generic [active] [ref=f1e1]:
+ - generic [ref=f1e2]:
+ - navigation "导航栏" [ref=f1e3]:
+ - generic [ref=f1e4]:
+ - link "首页" [ref=f1e5] [cursor=pointer]:
+ - /url: /
+ - link "探索" [ref=f1e7] [cursor=pointer]:
+ - /url: /explore/repos
+ - link "帮助" [ref=f1e8] [cursor=pointer]:
+ - /url: https://docs.gitea.com
+ - generic [ref=f1e9]:
+ - link "注册" [ref=f1e10] [cursor=pointer]:
+ - /url: /user/sign_up
+ - link "登录" [ref=f1e14] [cursor=pointer]:
+ - /url: /user/login
+ - main "首页" [ref=f1e18]:
+ - generic [ref=f1e20]:
+ - img "Logo" [ref=f1e21]
+ - generic [ref=f1e22]:
+ - heading "HAHA" [level=1] [ref=f1e23]
+ - heading "一款极易搭建的自托管 Git 服务" [level=2] [ref=f1e24]
+ - generic [ref=f1e25]:
+ - generic [ref=f1e26]:
+ - heading "易安装" [level=1] [ref=f1e27]
+ - paragraph [ref=f1e30]:
+ - text: 直接
+ - link "运行适合您平台的二进制文件" [ref=f1e31] [cursor=pointer]:
+ - /url: https://docs.gitea.com/installation/install-from-binary
+ - text: ,通过
+ - link "Docker" [ref=f1e32] [cursor=pointer]:
+ - /url: https://github.com/go-gitea/gitea/tree/master/docker
+ - text: 部署,或使用
+ - link "软件包" [ref=f1e33] [cursor=pointer]:
+ - /url: https://docs.gitea.com/installation/install-from-package
+ - text: 安装。
+ - generic [ref=f1e34]:
+ - heading "跨平台" [level=1] [ref=f1e35]
+ - paragraph [ref=f1e38]:
+ - text: 任何
+ - link "Go 语言" [ref=f1e39] [cursor=pointer]:
+ - /url: https://go.dev/
+ - text: 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行!
+ - generic [ref=f1e40]:
+ - generic [ref=f1e41]:
+ - heading "轻量级" [level=1] [ref=f1e42]
+ - paragraph [ref=f1e45]: 一个廉价的树莓派就足以满足 Gitea 的最低系统硬件要求。最大程度节省您的服务器资源!
+ - generic [ref=f1e46]:
+ - heading "开源化" [level=1] [ref=f1e47]
+ - paragraph [ref=f1e50]:
+ - text: 所有代码都开源在
+ - link "gitea.dev" [ref=f1e51] [cursor=pointer]:
+ - /url: https://gitea.dev
+ - text: ,还等什么?赶快加入我们来
+ - link "共同发展" [ref=f1e52] [cursor=pointer]:
+ - /url: https://github.com/go-gitea/gitea
+ - text: 这个伟大的项目,成为贡献者吧!
+ - group "页脚" [ref=f1e53]:
+ - contentinfo "关于软件" [ref=f1e54]:
+ - link "由 Gitea 强力驱动" [ref=f1e55] [cursor=pointer]:
+ - /url: https://about.gitea.com
+ - generic [ref=f1e56]: "版本: 1.27.1"
+ - generic [ref=f1e57]:
+ - text: "页面:"
+ - strong [ref=f1e58]: 3ms
+ - text: "模板:"
+ - strong [ref=f1e59]: 3ms
+ - group "链接" [ref=f1e60]:
+ - menu [ref=f1e61] [cursor=pointer]:
+ - generic [ref=f1e62]: Auto
+ - menu [ref=f1e66] [cursor=pointer]:
+ - generic [ref=f1e67]: 简体中文
+ - link "许可证" [ref=f1e70] [cursor=pointer]:
+ - /url: /assets/licenses.txt
+ - link "API" [ref=f1e71] [cursor=pointer]:
+ - /url: /api/swagger
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
index 5ac059f..4279ced 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -35,7 +35,7 @@
3. 相同或相似的功能必须封装为可复用的方法,避免重复代码。
4. 查询字段、路由、菜单、配置前,优先以当前项目代码和 `sbnews.sql` / `docs/sql/` 中结构为准;如需线上核对,再按用户要求使用可用 MCP 或指定连接方式。
5. 不通过 WSL sshpass/scp 上传代码到服务器;项目代码更新由用户自行通过 SFTP 等方式处理。
-6. 项目级文档(如协作规范、业务进度、设计稿映射、产品方案、实现流程、爬虫说明等)统一存放在项目根目录;仅子项目专属文档放在对应子目录。
+6. 新增项目级文档(如协作规范、业务进度、设计稿映射、产品方案、实现流程、爬虫说明等)统一存放在 `docs/`;根目录仅保留 `README.md`、`AGENTS.md`、`文档索引.md` 等入口文件。仅子项目专属的 README / AGENTS 等说明可放在对应子目录。
---
@@ -111,7 +111,7 @@
| 5 | 命名一致性 | 字段、方法、路由命名与现有风格一致 |
| 6 | 安全性 | SQL 拼接、用户输入、权限校验是否安全 |
| 7 | 幂等性 | SQL 初始化必须可重复执行 |
-| 8 | 文档同步 | 功能完成后更新 `业务进度管理.md` |
+| 8 | 文档同步 | 功能完成后更新 `docs/业务进度管理.md` |
## 代码变更后部署
@@ -128,7 +128,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\deploy-server.ps1 -Sudo -Auto
设计稿与页面/组件映射统一维护在:
-- [设计稿映射.md](./设计稿映射.md)
+- [设计稿映射.md](./docs/设计稿映射.md)
开发或还原视觉前,先确认设计稿名称、页面路径、实现状态与备注。
@@ -136,7 +136,7 @@ powershell -ExecutionPolicy Bypass -File .\scripts\deploy-server.ps1 -Sudo -Auto
当前业务进度、待办事项、避坑记录统一维护在:
-- [业务进度管理.md](./业务进度管理.md)
+- [业务进度管理.md](./docs/业务进度管理.md)
开发或接手任务前,先查看该文档确认已完成事项、进行中事项、待办事项与避坑记录。
diff --git a/01-产品方案文档.md b/docs/01-产品方案文档.md
similarity index 100%
rename from 01-产品方案文档.md
rename to docs/01-产品方案文档.md
diff --git a/02-实现流程文档.md b/docs/02-实现流程文档.md
similarity index 100%
rename from 02-实现流程文档.md
rename to docs/02-实现流程文档.md
diff --git a/docs/Gitea部署说明.md b/docs/Gitea部署说明.md
new file mode 100644
index 0000000..ce1f4ab
--- /dev/null
+++ b/docs/Gitea部署说明.md
@@ -0,0 +1,70 @@
+# Gitea 部署说明
+
+> 部署时间:2026-07-31
+>
+> 当前阶段:安装已完成,服务正常运行。
+
+## 访问方式
+
+- 正式访问地址:
+- 后端监听:`0.0.0.0:3000`。该端口仍保留用于服务器直连和 Nginx 反向代理,但日常访问应使用 HTTPS 域名。
+- 协议:HTTPS(Nginx 终止 TLS,再转发至 Gitea HTTP 3000 端口)
+- Git 操作:当前仅启用 HTTP/HTTPS 克隆和推送,未映射 Git SSH 端口,避免与宿主机的 SSH 22 端口冲突。
+
+Nginx 虚拟主机配置位于 `/www/server/panel/vhost/nginx/git.zones.sbnews.net.conf`,反向代理配置位于 `/www/server/panel/vhost/nginx/proxy/git.zones.sbnews.net/`。
+
+## 容器配置
+
+| 项目 | 当前配置 |
+| --- | --- |
+| 容器名 | `gitea` |
+| Gitea 版本 | 1.27.1 |
+| 镜像摘要 | `sha256:34e3f6b75f5cbb6aebce588037fc5a53c84213e4d4b00da0a8d73e031a558e52` |
+| 重启策略 | `unless-stopped` |
+| 端口映射 | `0.0.0.0:3000 -> 3000/tcp` |
+| 数据库 | SQLite,数据位于持久化卷内 |
+| 数据卷 | `gitea-data`,宿主机位置为 `/var/lib/docker/volumes/gitea-data/_data` |
+| 应用根地址 | `https://git.zones.sbnews.net/` |
+
+## 首次初始化
+
+1. 在浏览器打开 。
+2. 使用已创建的管理员账号登录。
+3. 创建组织与仓库;初期请使用 HTTPS 克隆地址。
+
+> HTTPS 域名已配置完成。后续更换域名或端口时,需同步更新 Gitea 的 `ROOT_URL` 和 Nginx 反向代理的 `Host` 请求头。
+
+## 反向代理跨域校验修复
+
+2026-07-31 曾出现 `cross-origin request detected` 与 `Frontend is not initialized` 提示。根因是 Nginx 反代把请求头设置为 `Host: localhost`,而浏览器请求的 `Origin` 是 `https://git.zones.sbnews.net`,导致 Gitea 的 CSRF 校验拒绝表单提交。
+
+已将反代请求头改为:
+
+~~~
+proxy_set_header Host git.zones.sbnews.net;
+proxy_set_header X-Forwarded-Host git.zones.sbnews.net;
+proxy_set_header X-Forwarded-Proto https;
+proxy_set_header X-Forwarded-Port 443;
+~~~
+
+并将 Gitea 的 `DOMAIN`、`ROOT_URL` 更新为 `git.zones.sbnews.net` 和 `https://git.zones.sbnews.net/`。修改后 Nginx 配置检查、Gitea 健康检查、HTTPS 页面与浏览器静态资源加载均已验证通过。
+
+## 常用运维命令
+
+以下命令均在服务器上执行:
+
+~~~
+ssh sbnews
+sudo docker ps --filter name=gitea
+sudo docker logs --tail 200 gitea
+sudo docker restart gitea
+sudo docker stop gitea
+sudo docker start gitea
+sudo docker volume inspect gitea-data
+~~~
+
+## 注意事项
+
+- Gitea 数据存放在 Docker 卷中。备份或迁移前先确认容器已停止,或使用 Gitea 官方备份方式,避免只备份容器层。
+- 当前镜像已固定到上述摘要,不会随宿主机重启自动升级。升级前应先备份数据,并在测试环境验证目标版本。
+- 调整端口、域名、HTTPS 或 Git SSH 后,应同步更新本文档、[服务器运行环境](./服务器运行环境.md) 和 [文档索引](../文档索引.md)。
diff --git a/业务进度管理.md b/docs/业务进度管理.md
similarity index 96%
rename from 业务进度管理.md
rename to docs/业务进度管理.md
index c6ab230..f5c9083 100644
--- a/业务进度管理.md
+++ b/docs/业务进度管理.md
@@ -13,6 +13,56 @@
## 一、已完成事项
+### 88. HG 赔率平台展示名统一为皇冠
+
+- 状态:代码已修改,待构建与页面验证 - 时间:2026-07-13
+
+完成内容:
+- `source_site=hg` 的平台展示名称由“滚球”统一调整为“皇冠”。
+- 前台赔率接口、管理端赔率列表、赛事中心默认平台选项和比赛详情赔率平台选项保持一致。
+- 用户端对接口返回的旧 `hg=滚球` 标签增加兼容归一化,筛选项和盘口卡片标题固定显示“皇冠”。
+- 比赛详情赔率平台筛选改为无左右内边距的等宽文字 Tab,当前平台均匀铺满可用宽度,使用统一 `gap` 分隔,并通过蓝色文字和底部下划线标识激活项;平台较多时保留横向滚动。
+- `platform_key=hg`、历史赔率数据、抓取任务和“滚球盘”盘口类型保持不变。
+
+涉及模块:
+- `server/app/api/controller/MatchController.php`
+- `server/app/adminapi/lists/match/MatchOddsLists.php`
+- `uniapp/src/packages_match/components/MatchCenterTabsPanel.vue`
+- `uniapp/src/components/match-odds-detail/match-odds-detail.vue`
+
+验证说明:
+- 已完成平台展示名和“滚球盘”盘口类型的静态区分检查。
+- 按当前项目规范,本次未执行构建、测试、提交或部署。
+
+### 87. 比赛详情多平台赔率绑定
+
+- 状态:代码已修改,待构建与页面验证 - 时间:2026-07-13
+
+完成内容:
+- 赛事中心和世界杯专题页的独立“赔率”Tab 改为通过本地显示开关隐藏,原赔率模板、状态和请求逻辑继续保留,便于后续恢复。
+- 赛事中心顶部内容 Tab 改为按实际显示数量自动等分宽度;当前“赛程 / 直播”各占一半,恢复赔率 Tab 后自动三等分。
+- 世界杯专题旧链接携带 `tab=odds` 时自动回落到赛程,避免进入已隐藏的赔率内容。
+- 比赛详情页在“比赛数据”后新增“赔率”Tab,并隐藏比赛数据内原有的简易主胜/平/客胜赔率区域,避免重复展示。
+- 比赛详情主导航重构为可横向滚动的自然宽度文字 Tab,取消等宽 `flex: 1` 和项目左右内边距,使用容器 `gap` 控制间距;直播红点改为绝对定位,避免影响文字与下划线中心。
+- 赛事赛程卡的 `mc__odds-item` 改为按主客队与比赛日期批量匹配第三方赔率,只回填主胜、平、客胜;无效的 `0`/`0.00` 转为空字符串,缺失项不渲染。
+- 新增 `match-odds-detail.vue` 详情赔率组件,首次进入赔率 Tab 时按需请求,支持“全部平台 / 皇冠 / 球探”筛选,并展示独赢、让球、大小球盘口。
+- 赔率组件区分“接口请求失败”和“接口成功但没有赔率”,请求失败时显示重试入口,不再误显示为“暂无赔率”。
+- 本地 H5 开发环境改为通过 Vite `/api` 同源代理访问测试服,避免自定义请求头触发的跨域预检超时;App、小程序及生产环境仍使用原接口域名。
+- `/api/match/odds` 新增可选参数 `home_team`、`away_team`、`match_date`;详情页使用比赛双方名称和比赛日期进行文本匹配,不依赖站内 `match_id`。
+- 日期文本匹配兼容 `YYYY-MM-DD`、`MM-DD`、`YYYY/MM/DD`、`MM/DD` 以及不补零格式;未传入新参数时继续保持原通用赔率列表行为。
+
+涉及模块:
+- `server/app/api/controller/MatchController.php`
+- `uniapp/src/api/match.ts`
+- `uniapp/src/components/match-odds-detail/match-odds-detail.vue`
+- `uniapp/src/pages/match_detail/match_detail.vue`
+- `uniapp/src/packages_match/components/MatchCenterTabsPanel.vue`
+- `uniapp/src/packages_match/components/WorldCupPanel.vue`
+
+验证说明:
+- 已完成请求参数、查询条件、Tab 状态和模板结构的静态复核。
+- 按当前项目规范,本次未执行构建、测试、提交或部署。
+
### 86. 赛事中心赛程 / 直播 / 赔率统一组件
- 状态:代码已修改,待构建与页面验证 - 时间:2026-07-11
@@ -20,9 +70,9 @@
完成内容:
- 用户端赛事中心新增 `MatchCenterTabsPanel.vue`,在当前页面内容区域统一切换“赛程 / 直播 / 赔率”,不再因点击三个 Tab 显示世界杯主题组件。
- 赛程 Tab 迁移并保留原赛事列表、运动分类、联赛筛选、进行中/未开始/已结束分组和已结束赛事分页;运动与联赛分类条仅在赛程显示。
-- 直播 Tab 新增 `/api/match/liveCards` 通用接口,基于 `la_match_live` 关联可见且未结束的赛事,前端不显示运动或联赛分类筛选。
+- 直播 Tab 新增 `/api/match/liveCards` 通用接口,以 `la_match_live` 的有效抓取状态和播放地址为准,不强制要求绑定站内赛事;前端不显示运动或联赛分类筛选。
- 赔率 Tab 新增 `/api/match/odds` 通用接口,只保留滚球盘/今日盘/早盘以及联赛/球队关键词搜索,并将赔率与普通站内赛事进行详情匹配。
-- 世界杯专题卡仍进入原世界杯专题页;`worldCupLiveCards`、`worldCupOdds` 原接口与专题功能保持兼容。
+- 世界杯专题卡仍进入原世界杯专题页;`worldCupLiveCards` 也改为展示当前有效直播流,不再强制绑定世界杯赛事,`worldCupOdds` 原接口保持兼容。
涉及模块:
- `server/app/api/controller/MatchController.php`
@@ -46,6 +96,9 @@
- 球探数据使用 `source_site=titan007` 写入 `la_match_odds`,平台名称在用户端和管理端统一显示为“球探”。
- HG 与球探改为独立抓取来源,单个来源失败不会阻断另一个来源入库;球探相关参数支持通过 `TITAN_ODDS_*` 环境变量覆盖。
- 多平台赔率聚合键调整为“主客队 + 比赛月日”,兼容 HG 与球探不同的联赛名和时间文本格式,使同场比赛可以展示多个平台。
+- 赛事中心盘口组件新增独立的平台筛选行,支持“全部平台 / 皇冠 / 球探”,请求会携带 `source_site`、当前运动和联赛条件。
+- 盘口类型筛选行(全部盘口、滚球盘、今日盘、早盘)已按当前页面需求注释隐藏,暂不显示。
+- `/api/match/odds` 与 `/api/match/worldCupOdds` 增加 `platform_options`,统一返回已支持平台并兼容数据库中的后续新来源。
涉及模块:
- `docker/crawler/titan_odds.py`
@@ -56,10 +109,13 @@
- `docker/crawler/tests/test_match_odds.py`
- `server/app/api/controller/MatchController.php`
- `server/app/adminapi/lists/match/MatchOddsLists.php`
+- `uniapp/src/packages_match/components/MatchCenterTabsPanel.vue`
验证说明:
- 已分析球探页面、赛程脚本和公开赔率接口的实时响应格式。
-- 按当前项目规范,本次未执行测试、提交或部署命令。
+- 已在测试服重建并重启 `sport-era-crawler`,确认容器内存在 `/app/titan_odds.py`,且 cron 已注册 `match_odds` 每 5 分钟执行。
+- 已手动触发一次 `match_odds`,确认 `/api/match/odds?source_site=titan007&limit=300` 返回 101 场球探世界杯赔率。
+- 本次未执行测试或提交命令。
### 84. 赛事中心世界杯快捷 Tab
@@ -91,7 +147,7 @@
- 已在 `admin` 目录执行 `npm run build`,管理端构建通过;构建产生的 `server/public/admin` 哈希产物已恢复,避免混入源码改动。
- 已通过部署脚本将新增后端接口同步到测试服运行目录,并通过后台 API 写入菜单,确认“赔率列表”位于“赛事管理”下。
- 已请求 `https://test-server.sbnews.net/adminapi/match.matchOdds/lists?page_no=1&page_size=5&sport_type=FT&has_odds=1`,接口返回 200,当前有赔率记录 48 条。
-- 已在本地管理端 `http://localhost:5176/match/match_odds` 验证页面渲染,菜单显示“赔率列表”,表格展示“滚球”平台赔率数据。
+- 已在本地管理端 `http://localhost:5176/match/match_odds` 验证页面渲染,菜单显示“赔率列表”,表格展示当前 `hg` 平台赔率数据(现展示名为“皇冠”)。
### 82. 世界杯专题赔率 Tab
@@ -99,7 +155,7 @@
完成内容:
- 后端新增 `/api/match/worldCupOdds` 接口,以 `la_match_odds` 赔率抓取结果为主数据源按比赛聚合返回,不强制绑定世界杯赛程;赛程匹配仅用于补充图标、状态和详情跳转。
-- 新增 `MatchOdds` 模型读取第三方赔率表,当前 `source_site=hg` 前端展示为“滚球”,盘口类型展示为滚球盘/今日盘/早盘。
+- 新增 `MatchOdds` 模型读取第三方赔率表,当前 `source_site=hg` 前端展示为“皇冠”,盘口类型展示为滚球盘/今日盘/早盘。
- 用户端世界杯专题页在“比分和赛程”和“排名”之间新增“赔率”Tab,按赔率比赛卡片展示联赛、时间、主客队、平台、更新时间、独赢、让球、大小球赔率。
- 赔率 Tab 支持按盘口类型筛选,并可通过关键词搜索联赛、主队、客队;后端接口同步支持 `show_type`、`source_site`、`keyword` 参数。
- 后端会剔除没有任何盘口值的平台和比赛,避免前台展示只有赛程信息但没有赔率的空卡片。
@@ -109,7 +165,7 @@
- 已执行 `php -l server\app\api\controller\MatchController.php`、`php -l server\app\common\model\match\MatchOdds.php`,语法检查通过。
- 已执行 `npm run build:h5`,H5 构建通过。
- 已请求 `https://test-server.sbnews.net/api/match/worldCupOdds?limit=300`,接口返回 200,当前可取到 45 场有盘口值的足球赔率,空赔率比赛为 0。
-- 已在本地 H5 `http://localhost:8991/packages_match/pages/worldcup?tab=odds` 验证“赔率”Tab 渲染,页面展示 45 张有盘口值的赔率比赛卡,包含“滚球”平台及独赢/让球/大小球赔率。
+- 已在本地 H5 `http://localhost:8991/packages_match/pages/worldcup?tab=odds` 验证“赔率”Tab 渲染,页面展示 45 张有盘口值的赔率比赛卡,包含当前 `hg` 平台(现展示名为“皇冠”)及独赢/让球/大小球赔率。
### 81. 第三方赛事赔率定时抓取
diff --git a/docs/服务器运行环境.md b/docs/服务器运行环境.md
new file mode 100644
index 0000000..ae0b236
--- /dev/null
+++ b/docs/服务器运行环境.md
@@ -0,0 +1,93 @@
+# 测试服务器运行环境
+
+> 采集时间:2026-07-31 15:59(Asia/Shanghai;包含 Gitea 反向代理配置修复后的状态)
+>
+> 采集方式:通过 `ssh sbnews` 执行只读检查。本文记录当前快照,不包含账号、密码、环境变量等敏感信息。
+
+## 服务器概况
+
+| 项目 | 当前值 |
+| --- | --- |
+| 主机名 | `ip-172-31-25-241` |
+| 操作系统 | Ubuntu 22.04.5 LTS |
+| 已运行时间 | 13 周 6 天 10 小时 |
+| 项目运行目录 | `/www/wwwroot/test-server.sbnews.net` |
+
+## 资源使用情况
+
+| 资源 | 总量 | 已使用 | 可用 / 剩余 | 说明 |
+| --- | ---: | ---: | ---: | --- |
+| 内存 | 7.6 GiB | 3.9 GiB | 3.5 GiB 可用 | `free -h` 的 `available` 值,包含可回收缓存 |
+| Swap | 0 B | 0 B | 0 B | 未配置交换分区 |
+| 根分区 `/` | 124 GB | 64 GB | 61 GB | 使用率 52% |
+
+## 宿主机运行服务
+
+### 项目相关服务
+
+| 服务 | 状态 | 用途 |
+| --- | --- | --- |
+| `nginx.service` | running | Web 服务与反向代理 |
+| `mysqld.service` | running | MySQL 数据库 |
+| `docker.service` | running | Docker 容器引擎 |
+| `containerd.service` | running | Docker 容器运行时 |
+| `cron.service` | running | 宿主机定时任务 |
+| `supervisord.service` | running | 进程守护 |
+| `mtranserver.service` | running | 本地翻译服务 |
+| `site_total.service` | running | 站点统计服务 |
+| `pure-ftpd.service` | running | FTP 服务 |
+| `ssh.service` | running | SSH 远程访问 |
+| `redis-server.service` | inactive | 本机 Redis 服务未运行,且未发现 TCP 6379 监听 |
+
+系统同时运行 chrony、日志、网络、BT 面板等基础服务;完整服务清单可通过 `systemctl list-units --type=service --state=running` 查看。
+
+## Docker 运行状态
+
+- Docker 版本:`29.1.3`
+- Compose 项目:`docker`
+- Compose 配置:`/www/wwwroot/test-server.sbnews.net/docker/docker-compose.crawler.yml`
+- Docker 负责运行 Python 爬虫与容器内 cron;本次确认 Nginx、MySQL 由宿主机服务提供。
+- Gitea 以独立 Docker 容器运行,详情见 [Gitea 部署说明](./Gitea部署说明.md)。
+
+### 容器
+
+| 容器 | 镜像 | 状态 | 重启策略 | 挂载 |
+| --- | --- | --- | --- | --- |
+| `gitea` | `docker.gitea.com/gitea:1.27.1` | 正常运行,Nginx HTTPS 域名反代至 HTTP `3000` | `unless-stopped` | Docker 卷 `gitea-data` → `/data` |
+| `sport-era-crawler` | `sport-era-crawler:latest` | 正常运行,已持续 2 周 | `always` | crawler `logs` → `/app/logs`;crawler `data` → `/app/data` |
+| `sport-era-kb-worker` | `sport-era-crawler:latest` | 已退出,Docker 持续重启 | `always` | 与 crawler 共用 `logs`、`data` 挂载 |
+
+### Docker 存储占用
+
+| 类别 | 占用 | 可回收 |
+| --- | ---: | ---: |
+| 镜像 | 13.03 GB | 13.03 GB |
+| 容器 | 126.8 MB | 0 B |
+| 构建缓存 | 12.04 GB | 9.627 GB |
+| 本地卷 | 5.444 kB | 0 B |
+
+> 以上数值来自 `docker system df`。即使 Docker 显示可回收空间,也不得未经确认直接执行清理命令,避免影响正在使用的镜像或后续回滚。
+
+## 待处理风险
+
+- `sport-era-kb-worker` 当前退出码为 `1`,重启次数为 `17`,在 Compose 中显示 `Restarting (1)` 已约 3 周。
+- 本机 `redis-server.service` 为 inactive,且未发现 TCP 6379 监听。项目是否改用远程 Redis 或其他缓存连接,需以服务器 `server/.env` 为准后再确认。
+- Gitea 已监听 `0.0.0.0:3000`,正式入口为 `https://git.zones.sbnews.net/`。Nginx 反代和 Gitea 的根地址已统一为该域名,浏览器静态资源与健康检查已通过。
+- 本次仅记录运行状态,未读取日志、未重启容器、未修改服务器。排查时可优先使用:
+
+~~~
+ssh sbnews
+sudo docker logs --tail 200 sport-era-kb-worker
+sudo docker inspect sport-era-kb-worker
+~~~
+
+## 常用只读检查命令
+
+~~~
+ssh sbnews
+free -h
+df -h /
+sudo docker ps
+sudo docker compose -f /www/wwwroot/test-server.sbnews.net/docker/docker-compose.crawler.yml ps
+sudo docker system df
+~~~
diff --git a/docs/比赛详情赔率绑定实施计划.md b/docs/比赛详情赔率绑定实施计划.md
new file mode 100644
index 0000000..69d0710
--- /dev/null
+++ b/docs/比赛详情赔率绑定实施计划.md
@@ -0,0 +1,15 @@
+# 比赛详情赔率绑定实施计划
+
+**目标:** 隐藏独立赔率入口,并在比赛详情页按比赛双方名称和日期展示多平台盘口。
+
+**实现方式:** 保留现有通用赔率列表代码,通过显示开关隐藏入口;扩展 `/api/match/odds` 的可选文本筛选参数;详情页首次进入赔率 Tab 时请求并展示当前比赛的平台盘口。
+
+## 任务
+
+- [x] 修改 `server/app/api/controller/MatchController.php`:读取 `home_team`、`away_team`、`match_date`,在通用赔率查询中增加可选文本筛选和日期格式兼容。
+- [x] 修改 `uniapp/src/api/match.ts`:为 `getMatchOdds` 增加三个可选请求参数。
+- [x] 修改 `uniapp/src/packages_match/components/MatchCenterTabsPanel.vue`:通过开关隐藏赛事中心赔率 Tab,保留原实现。
+- [x] 修改 `uniapp/src/packages_match/components/WorldCupPanel.vue`:通过开关隐藏世界杯赔率 Tab,并避免旧 `tab=odds` 激活隐藏页面。
+- [x] 修改 `uniapp/src/pages/match_detail/match_detail.vue`:新增赔率 Tab、平台筛选、懒加载和盘口展示,隐藏比赛数据里的旧简易赔率。
+- [x] 更新 `业务进度管理.md`:记录比赛详情赔率绑定方式和独立入口隐藏状态。
+- [x] 静态复核请求参数、Tab 状态、模板标签和工作区改动;不自动执行构建、测试、提交或部署。
diff --git a/docs/比赛详情赔率绑定设计.md b/docs/比赛详情赔率绑定设计.md
new file mode 100644
index 0000000..1cacdbd
--- /dev/null
+++ b/docs/比赛详情赔率绑定设计.md
@@ -0,0 +1,28 @@
+# 比赛详情赔率绑定设计
+
+## 目标
+
+- 赛事中心和世界杯专题页不再显示独立赔率 Tab,但保留原赔率功能代码。
+- 赔率强绑定到比赛详情页,在详情 Tab 中展示当前比赛的滚球、球探及后续平台盘口。
+- 绑定不依赖站内 `match_id`,由比赛双方名称和比赛日期进行文本匹配。
+
+## 交互设计
+
+- 比赛详情 Tab 顺序调整为:文字直播、比赛数据、赔率、阵容、近期战绩、AI分析。
+- 进入详情页时不立即请求赔率;首次切换到赔率 Tab 时按需加载。
+- 赔率页提供“全部平台 / 滚球 / 球探”平台筛选,不提供联赛或球队搜索。
+- 每个平台展示独赢、让球、大小球盘口;没有匹配数据时展示“暂无赔率”。
+- 比赛数据 Tab 中原有的简易主胜/平/客胜区域隐藏,避免重复展示。
+
+## 数据绑定
+
+- 用户端调用 `/api/match/odds` 时传入 `home_team`、`away_team`、`match_date`。
+- 后端对主队、客队字段分别进行文本包含匹配。
+- `match_date` 统一按 `YYYY-MM-DD` 传递,后端兼容赔率记录中的 `YYYY-MM-DD`、`MM-DD`、`YYYY/MM/DD`、`MM/DD` 日期文本。
+- 未传入上述条件时,`/api/match/odds` 保持原通用列表行为,兼容现有调用方。
+
+## 显示开关
+
+- `MatchCenterTabsPanel.vue` 和 `WorldCupPanel.vue` 使用本地布尔开关过滤赔率 Tab。
+- 原赔率模板、状态与请求逻辑保留,后续恢复入口时只需调整开关。
+
diff --git a/爬虫任务脚本文档.md b/docs/爬虫任务脚本文档.md
similarity index 100%
rename from 爬虫任务脚本文档.md
rename to docs/爬虫任务脚本文档.md
diff --git a/设计稿映射.md b/docs/设计稿映射.md
similarity index 100%
rename from 设计稿映射.md
rename to docs/设计稿映射.md
diff --git a/docs/赔率平台皇冠展示名实施计划.md b/docs/赔率平台皇冠展示名实施计划.md
new file mode 100644
index 0000000..4f97697
--- /dev/null
+++ b/docs/赔率平台皇冠展示名实施计划.md
@@ -0,0 +1,6 @@
+# 赔率平台皇冠展示名实施计划
+
+- [x] 修改前台 API 的 HG 平台名称映射。
+- [x] 修改管理端赔率列表的 HG 平台名称映射。
+- [x] 修改用户端赛事中心和比赛详情的默认平台名称。
+- [x] 更新业务进度并检查仍需保留的“滚球盘”文案。
diff --git a/docs/赔率平台皇冠展示名设计.md b/docs/赔率平台皇冠展示名设计.md
new file mode 100644
index 0000000..0210596
--- /dev/null
+++ b/docs/赔率平台皇冠展示名设计.md
@@ -0,0 +1,6 @@
+# 赔率平台皇冠展示名设计
+
+- 将 `source_site=hg` 的平台展示名称由“滚球”统一改为“皇冠”。
+- 前台接口、管理端赔率列表和用户端默认筛选选项保持一致。
+- `platform_key=hg`、数据库历史数据、抓取任务和“滚球盘”盘口类型保持不变。
+
diff --git a/赛事中心赛程直播赔率组件实施计划.md b/docs/赛事中心赛程直播赔率组件实施计划.md
similarity index 94%
rename from 赛事中心赛程直播赔率组件实施计划.md
rename to docs/赛事中心赛程直播赔率组件实施计划.md
index 224596e..5a6c53b 100644
--- a/赛事中心赛程直播赔率组件实施计划.md
+++ b/docs/赛事中心赛程直播赔率组件实施计划.md
@@ -21,15 +21,14 @@
在 `MatchLiveService` 增加:
```php
-public static function getLiveCards(int $sportType = 0, string $leagueName = '', bool $worldCupOnly = false): array
+public static function getLiveCards(int $sportType = 0, string $leagueName = ''): array
```
查询必须保留:
```php
-->join('match m', 'm.id = live.match_id')
-->where(['m.is_show' => 1])
-->where([['m.status', '<>', 2]])
+->leftJoin('match m', 'm.id = live.match_id')
+->where('live.fetch_status', 1)
```
`MatchLive` 模型已启用 `SoftDelete`,查询自动排除已软删除记录,不额外重复拼接 `delete_time` 条件。
@@ -43,18 +42,12 @@ if ($sportType > 0) {
if ($leagueName !== '') {
$query->where('m.league_name', $leagueName);
}
-if ($worldCupOnly) {
- $query->where(function ($query) {
- $query->where('m.league_name', '世界杯')
- ->whereOr('m.competition_id', 61);
- });
-}
```
`getWorldCupLiveCards()` 改为调用:
```php
-return self::getLiveCards(0, '', true);
+return self::getLiveCards();
```
- [ ] **Step 2: 新增公开接口**
@@ -75,7 +68,7 @@ public function liveCards()
- [ ] **Step 3: 保持世界杯接口响应兼容**
-`worldCupLiveCards()` 继续返回 `season_id` 和 `list`,不改变专题页字段结构。
+`worldCupLiveCards()` 继续返回 `season_id` 和 `list`,不改变专题页字段结构,但不再强制按世界杯赛事过滤。
### Task 2: 通用赔率查询
@@ -296,6 +289,6 @@ npm run build:h5
1. 赛事中心默认显示赛程。
2. 三个 Tab 切换时 URL 和页面外壳不切换为世界杯主题。
-3. 直播按运动/联赛刷新。
-4. 赔率盘口和关键词筛选有效。
+3. 直播不显示运动或联赛分类筛选,并展示全部可用直播。
+4. 赔率不显示运动或联赛分类条,盘口和联赛/球队关键词筛选有效。
5. 世界杯专题卡仍能进入专题页。
diff --git a/赛事中心赛程直播赔率组件设计.md b/docs/赛事中心赛程直播赔率组件设计.md
similarity index 94%
rename from 赛事中心赛程直播赔率组件设计.md
rename to docs/赛事中心赛程直播赔率组件设计.md
index 572e2cc..63c4dd3 100644
--- a/赛事中心赛程直播赔率组件设计.md
+++ b/docs/赛事中心赛程直播赔率组件设计.md
@@ -29,7 +29,7 @@
## 直播 Tab
- 新增通用赛事直播接口,不复用只过滤世界杯的 `worldCupLiveCards`。
-- 从 `la_match_live` 关联可见赛事,返回未结束且存在可播放地址的直播卡。
+- 以 `la_match_live` 的有效抓取状态和播放地址为准;赛事关联仅用于补充赛事信息,不作为显示前提。
- 不显示运动分类或联赛分类筛选,直接展示当前可用的全部直播。
- 直播卡保留赛事名称、主播、观看数、关注数、公告、封面和播放地址。
- H5、App 的视频播放和海报模式继续复用现有世界杯直播卡的兼容处理。
@@ -62,6 +62,8 @@
通用与世界杯接口复用服务层的查询、格式化和赛事匹配方法,避免复制赔率盘口组装与直播地址解析逻辑。
+世界杯直播接口不再强制按世界杯赛事过滤,和通用直播接口一样展示当前有效直播流。
+
## 状态与交互
- 切换 Tab 时按需加载对应数据,已加载数据可缓存,筛选条件改变后重新请求。
diff --git a/pc/AGENTS.md b/pc/AGENTS.md
index 0578144..776d053 100644
--- a/pc/AGENTS.md
+++ b/pc/AGENTS.md
@@ -69,4 +69,4 @@ npm run generate
- 接口 baseURL 由 `runtimeConfig` 或环境配置控制,不要写死。
- 页面级数据获取优先使用 `useAsyncData` / `useFetch`。
- 与 uniapp 共享前台接口契约,避免同一业务前台两套字段命名。
-- 设计稿与页面映射维护在根目录 `设计稿映射.md`。
+- 设计稿与页面映射维护在 `docs/设计稿映射.md`。
diff --git a/server/AGENTS.md b/server/AGENTS.md
index ac6dcfb..a381742 100644
--- a/server/AGENTS.md
+++ b/server/AGENTS.md
@@ -89,7 +89,7 @@ Step 2: 前端并行消费契约
Step 3: 集成联调与文档同步
- 检查接口响应格式、权限、字段、字典
- - 同步更新 `业务进度管理.md`
+ - 同步更新 `docs/业务进度管理.md`
```
## 与前端 Agent 的协作方式
diff --git a/uniapp/AGENTS.md b/uniapp/AGENTS.md
index 95fe0ef..9d1209e 100644
--- a/uniapp/AGENTS.md
+++ b/uniapp/AGENTS.md
@@ -84,7 +84,7 @@ npm run build:h5
## 设计稿对照
-设计稿与本项目页面/组件的映射关系集中维护于根目录 [`设计稿映射.md`](../设计稿映射.md)。接到新需求或还原设计稿前先查该文档,确认:
+设计稿与本项目页面/组件的映射关系集中维护于 [`docs/设计稿映射.md`](../docs/设计稿映射.md)。接到新需求或还原设计稿前先查该文档,确认:
- 设计稿名称 ↔ uniapp 页面路径
- 当前实现状态(已完成 / 待开发 / 部分完成)
diff --git a/文档索引.md b/文档索引.md
new file mode 100644
index 0000000..0ea66de
--- /dev/null
+++ b/文档索引.md
@@ -0,0 +1,46 @@
+# Sport Era 文档索引
+
+> 新增项目级文档统一存放在 [`docs/`](./docs/);根目录仅保留本索引及项目入口说明。源码子目录中的 README、AGENTS 等模块说明继续就近维护。
+
+## 项目管理
+
+- [业务进度管理](./docs/业务进度管理.md):已完成、进行中和待办事项,以及避坑记录。
+- [设计稿映射](./docs/设计稿映射.md):设计稿与页面、组件的映射关系。
+- [产品方案文档](./docs/01-产品方案文档.md):产品定位、功能规划与技术方案。
+- [实现流程文档](./docs/02-实现流程文档.md):项目实现步骤与流程说明。
+
+## 功能设计与实施记录
+
+- [赛事中心赛程、直播、赔率组件设计](./docs/赛事中心赛程直播赔率组件设计.md)
+- [赛事中心赛程、直播、赔率组件实施计划](./docs/赛事中心赛程直播赔率组件实施计划.md)
+- [比赛详情赔率绑定设计](./docs/比赛详情赔率绑定设计.md)
+- [比赛详情赔率绑定实施计划](./docs/比赛详情赔率绑定实施计划.md)
+- [赔率平台皇冠展示名设计](./docs/赔率平台皇冠展示名设计.md)
+- [赔率平台皇冠展示名实施计划](./docs/赔率平台皇冠展示名实施计划.md)
+- [直播间功能设计规格](./docs/superpowers/specs/2026-06-21-match-live-streams-design.md)
+
+## 运维与爬虫
+
+- [测试服务器运行环境](./docs/服务器运行环境.md):服务器资源、宿主机服务、Docker 容器与当前风险快照。
+- [Gitea 部署说明](./docs/Gitea部署说明.md):Gitea 的访问地址、持久化数据、运维命令与首次初始化步骤。
+- [爬虫任务脚本文档](./docs/爬虫任务脚本文档.md):爬虫任务的功能和执行说明。
+- [Docker crawler 说明](./docker/crawler/README.md):爬虫容器的源码级说明。
+
+## 数据库脚本
+
+- [`docs/sql/`](./docs/sql/):数据库表、字段、索引、配置、菜单和定时任务的初始化或变更 SQL。
+- 命名约定:`create_` 为建表,`alter_` 为字段调整,`insert_` 为配置、菜单或定时任务初始化,`fix_` 为数据修复。
+- 执行前以当前代码与数据库结构为准;SQL 必须保持幂等,且不得将数据库密码写入脚本或文档。
+
+## 模块说明
+
+- [后端说明](./server/README.md) / [后端规范](./server/AGENTS.md)
+- [管理后台说明](./admin/README.md) / [管理后台规范](./admin/AGENTS.md)
+- [手机端说明](./uniapp/README.md) / [手机端规范](./uniapp/AGENTS.md)
+- [PC 前台说明](./pc/README.md) / [PC 前台规范](./pc/AGENTS.md)
+
+## 文档维护规则
+
+1. 新增项目级文档先放入 `docs/`,再补充本索引的对应链接。
+2. 设计或实现变更完成后,同步更新 [业务进度管理](./docs/业务进度管理.md);涉及页面设计时同步更新 [设计稿映射](./docs/设计稿映射.md)。
+3. 服务器状态文档是快照,任何后续部署、容器重建或资源变化后,应重新采集并更新采集时间。