# 投注玩法说明

本文档为 **Explanation（说明）**：集中描述 thebet365 第一版**足球赛前盘**的每种玩法如何下注、如何判赢。  
派彩金额公式见 [结算与返水金额规则.md](./结算与返水金额规则.md)；结算操作流程见 [settlement-and-fund-flow-analysis.md](./settlement-and-fund-flow-analysis.md)。

---

## 1. 范围与注单类型

### 1.1 产品范围（v1）

| 项 | 说明 |
|----|------|
| 运动 | 仅足球（`SPORT_TYPE_FOOTBALL`） |
| 时段 | **赛前盘**：开球时间之前可下注（`isPreMatchKickoff`） |
| 不含 | 滚球、Cash Out、改单、系统串关 |

与玩家端「我的 → 投注规则」文案一致（`apps/player/src/i18n/zh-CN.ts` `rules_p1`–`rules_p5`）。

### 1.2 注单类型

| 类型 | 枚举 | 说明 |
|------|------|------|
| 单关 | `SINGLE` | 1 个选项，1 笔本金 |
| 串关 | `PARLAY` | 2–5 腿（`PARLAY_MIN_LEGS=2`，`PARLAY_MAX_LEGS=5`），赔率连乘 |

**数据模型**：库表为 `Bet`（注单）+ `BetSelection`（选项腿）。玩家端 Pinia store 名 `betSlip`，逻辑上等价于「投注单」。

### 1.3 API 入口

| 操作 | 路径 |
|------|------|
| 单关下注 | `POST /api/player/bets/single` |
| 串关下注 | `POST /api/player/bets/parlay` |

---

## 2. 玩法总览表

权威目录：`packages/shared/src/market-catalog.ts` → `FOOTBALL_MARKET_CATALOG`（**共 18 种**足球盘口）。

| marketType | 中文名 | 时段 | 主要选项 | 默认线 | 单关 | 串关 | 串关序 | 结算分类 | 结算依据 | 默认 seed |
|------------|--------|------|----------|--------|------|------|--------|----------|----------|-----------|
| `FT_1X2` | 全场 1X2 | FT | HOME / DRAW / AWAY | — | ✓ | ✓ | 3 | SCORE | 全场比分 | ✓ |
| `FT_HANDICAP` | 全场让球 | FT | HOME / AWAY | -0.5 | ✓ | ✓ | 1 | HANDICAP | 全场比分 + 让球线 | ✓ |
| `FT_OVER_UNDER` | 全场大小 | FT | OVER / UNDER | 2.5 | ✓ | ✓ | 2 | TOTAL | 全场总进球 + 大小线 | ✓ |
| `FT_ODD_EVEN` | 全场单双 | FT | ODD / EVEN | — | ✓ | ✓ | 4 | ODD_EVEN | 全场总进球奇偶 | ✓ |
| `HT_1X2` | 半场 1X2 | HT | HOME / DRAW / AWAY | — | ✓ | ✓ | 7 | SCORE | 半场比分 | ✓ |
| `HT_HANDICAP` | 半场让球 | HT | HOME / AWAY | -0.5 | ✓ | ✓ | 5 | HANDICAP | 半场比分 + 让球线 | ✓ |
| `HT_OVER_UNDER` | 半场大小 | HT | OVER / UNDER | 1.5 | ✓ | ✓ | 6 | TOTAL | 半场总进球 + 大小线 | ✓ |
| `FT_CORRECT_SCORE` | 全场波胆 | FT | 见 §3.E | — | ✓ | ✗ | — | CORRECT_SCORE | 全场精确比分 | ✓ |
| `HT_CORRECT_SCORE` | 上半场波胆 | HT | 见 §3.E | — | ✓ | ✗ | — | CORRECT_SCORE | 半场精确比分 | ✗ |
| `SH_CORRECT_SCORE` | 下半场波胆 | SH | 见 §3.E | — | ✓ | ✗ | — | CORRECT_SCORE | 下半场比分（FT−HT） | ✗ |
| `OUTRIGHT_WINNER` | 冠军 | OUTRIGHT | 球队 code | — | ✓ | ✗ | — | OUTRIGHT | 冠军球队 code | ✗* |
| `FT_TEAM_TOTAL_HOME` | 主队进球大小 | FT | OVER / UNDER | 1.5 | ✓ | ✓ | 8 | TOTAL | 主队全场进球 | ✓ |
| `FT_TEAM_TOTAL_AWAY` | 客队进球大小 | FT | OVER / UNDER | 1.5 | ✓ | ✓ | 9 | TOTAL | 客队全场进球 | ✓ |
| `HT_FT` | 半全场 | FT | 9 组合，见 §3.F | — | ✓ | ✓ | 10 | SCORE | 半场结果 + 全场结果 | ✓ |
| `FT_TOTAL_GOALS` | 总进球数 | FT | TG_0_1 … TG_7_PLUS | — | ✓ | ✓ | 11 | SCORE | 全场总进球区间 | ✓ |
| `FT_CORNERS_HANDICAP` | 全场角球让球 | FT | HOME / AWAY | -0.5 | ✓ | ✓ | 12 | MANUAL_STATS | 主客角球 + 让球线 | ✓ |
| `FT_CORNERS_OVER_UNDER` | 全场角球大小 | FT | OVER / UNDER | 8.5 | ✓ | ✓ | 13 | MANUAL_STATS | 角球总数 + 大小线 | ✓ |
| `FT_CARDS_OVER_UNDER` | 全场罚牌大小 | FT | OVER / UNDER | 3.5 | ✓ | ✓ | 14 | MANUAL_STATS | 罚牌总数 + 大小线 | ✓ |

\* `OUTRIGHT_WINNER` 不在常规赛事 seed 模板中，由世界杯 48 强等单独同步，见 [默认数据说明.md](./默认数据说明.md)。

**默认 seed 刻意不含**：`HT_CORRECT_SCORE`、`SH_CORRECT_SCORE`（系统仍识别并可结算）。

---

## 3. 按类别详解

以下判赢逻辑对应 `apps/api/src/domains/settlement/domain/settlement-calculator.ts` → `settleSelection()`。  
腿级结果：`WIN` | `HALF_WIN` | `PUSH` | `HALF_LOSE` | `LOSE` | `VOID`。

### 3.A 独赢盘（1X2）

**结算分类**：`SCORE`

#### FT_1X2（全场 1X2 / Full Time 1X2）

| 项 | 内容 |
|----|------|
| 玩法说明 | 预测**全场 90 分钟**（含补时，不含加时/点球）结束时的赛果 |
| 选项 | `HOME` 主胜 · `DRAW` 和局 · `AWAY` 客胜 |
| 判赢 | 比较 `ftHome` 与 `ftAway`：主胜 / 和 / 客胜 |
| 示例 | 全场 2:1，选 `HOME` → **WIN**；选 `DRAW` → **LOSE** |
| 串关 | 允许（`parlayOrder=3`） |
| 快照字段 | 无盘口线 |

#### HT_1X2（半场 1X2）

| 项 | 内容 |
|----|------|
| 玩法说明 | 预测**上半场**结束时的赛果 |
| 选项 | `HOME` / `DRAW` / `AWAY` |
| 判赢 | 比较 `htHome` 与 `htAway` |
| 示例 | 半场 0:0、全场 1:0，选半场 `DRAW` → **WIN** |
| 串关 | 允许（`parlayOrder=7`） |

---

### 3.B 让球盘（亚洲盘）

**结算分类**：`HANDICAP`（角球盘为 `MANUAL_STATS`，算法同为让球）

**通用规则**：

- 选项：`HOME`（主队受让/让球侧）/ `AWAY`（客队）
- 让球线存于 `BetSelection.handicapLine`（下注时快照）
- 主队视角：`adj = 本队进球 + handicapLine − 对手进球`
  - `adj > 0` → WIN；`adj = 0` → PUSH；`adj < 0` → LOSE
- 客队选项使用 **相反符号** 的让球线（代码内对客队取 `-line`）
- 四分之一盘（`.25` / `.75`）可产生半赢半输，见 [§5](#5-四分之一盘25--75)

#### FT_HANDICAP（全场让球）

| 项 | 内容 |
|----|------|
| 默认线 | -0.5（表示主队让半球，即主队需净胜至少 1 球才全赢） |
| 统计 | `ftHome`、`ftAway` |
| 串关 | 允许；**禁止** `.25`/`.75` 线进入串关 |

**示例**（线 -0.5，选主队 `HOME`）：

| 比分 | 结果 |
|------|------|
| 2:1 | WIN（2 + (-0.5) − 1 = 0.5 > 0） |
| 1:1 | LOSE |
| 1:0 | WIN |

#### HT_HANDICAP（半场让球）

| 项 | 内容 |
|----|------|
| 默认线 | -0.5 |
| 统计 | `htHome`、`htAway` |
| 串关 | 允许（禁止四分之一线） |

#### FT_CORNERS_HANDICAP（全场角球让球）

| 项 | 内容 |
|----|------|
| 默认线 | -0.5 |
| 统计 | 管理员录入 `homeCorners`、`awayCorners`；缺失时结算报错 `SETTLEMENT_STAT_MISSING` |
| 判赢 | 与足球让球相同，但用角球数代替进球 |
| 串关 | 允许（禁止四分之一线） |

---

### 3.C 大小盘（Over/Under）

**结算分类**：`TOTAL`（角球/罚牌为 `MANUAL_STATS`，算法同为大小）

**通用规则**：

- 选项：`OVER`（大）/ `UNDER`（小）
- 大小线存于 `BetSelection.totalLine`
- 大球：`总进球 > line` → WIN；`= line` → PUSH；`< line` → LOSE
- 小球：相反
- 支持四分之一盘半赢半输；串关禁止 `.25`/`.75` 线

| marketType | 中文名 | 默认线 | 统计对象 |
|------------|--------|--------|----------|
| `FT_OVER_UNDER` | 全场大小 | 2.5 | `ftHome + ftAway` |
| `HT_OVER_UNDER` | 半场大小 | 1.5 | `htHome + htAway` |
| `FT_TEAM_TOTAL_HOME` | 主队进球大小 | 1.5 | `ftHome` |
| `FT_TEAM_TOTAL_AWAY` | 客队进球大小 | 1.5 | `ftAway` |
| `FT_CORNERS_OVER_UNDER` | 全场角球大小 | 8.5 | `homeCorners + awayCorners` |
| `FT_CARDS_OVER_UNDER` | 全场罚牌大小 | 3.5 | `homeCards + awayCards` |

**示例**（`FT_OVER_UNDER` 线 2.5，选 `OVER`）：

| 比分 | 总进球 | 结果 |
|------|--------|------|
| 2:1 | 3 | WIN |
| 1:1 | 2 | LOSE |
| 2:0 | 2 | LOSE（2 不大于 2.5） |

角球/罚牌盘：结算前须在管理端录入对应统计字段，否则无法确认结算。

---

### 3.D 单双（Odd/Even）

#### FT_ODD_EVEN（全场单双）

| 项 | 内容 |
|----|------|
| 选项 | `ODD` 单 · `EVEN` 双 |
| 判赢 | 全场总进球 `ftHome + ftAway` 为奇数或偶数 |
| 示例 | 0:0 → 总进球 0 → **双（EVEN 赢）** |
| 串关 | 允许（`parlayOrder=4`） |

---

### 3.E 波胆（Correct Score）— 仅单关

**结算分类**：`CORRECT_SCORE`  
**串关**：全部 `allowParlay: false`，不可进入串关。

| marketType | 比分来源 |
|------------|----------|
| `FT_CORRECT_SCORE` | 全场 `ftHome:ftAway` |
| `HT_CORRECT_SCORE` | 半场 `htHome:htAway` |
| `SH_CORRECT_SCORE` | 下半场 `(ftHome−htHome):(ftAway−htAway)` |

**选项类型**：

1. **精确比分**：code 形如 `SCORE_2_1`（表示 2:1）
2. **其它主胜** `OTHER_HOME`：主胜，且精确比分不在模板列表中
3. **其它和局** `OTHER_DRAW`：和局，且精确比分不在模板列表中
4. **其它客胜** `OTHER_AWAY`：客胜，且精确比分不在模板列表中

**模板列表**（`market-catalog.ts`）：

- 全场：`FT_CORRECT_SCORE_TEMPLATE`（28 项，含 3 个 OTHER_*）
- 半场/下半场：`HT_CORRECT_SCORE_TEMPLATE`（17 项）

**判赢逻辑**：

- 选 `SCORE_h_a`：实际比分完全相等 → WIN，否则 LOSE
- 若实际比分在模板中有对应 `SCORE_*` 项，则 OTHER_* 选项 LOSE
- 若实际比分**不在**模板中，则按主胜/和/客胜归到对应 OTHER_* → WIN

**示例**（全场波胆，实际 4:2）：

- 模板含 `SCORE_4_2` → 选 `SCORE_4_2` **WIN**，选 `OTHER_HOME` **LOSE**
- 若模板不含 4:2 → 选 `OTHER_HOME` **WIN**（主队胜）

---

### 3.F 组合 / 区间

#### HT_FT（半全场 / Half Time–Full Time）

| 项 | 内容 |
|----|------|
| 玩法说明 | 同时预测**半场结果**与**全场结果** |
| 选项 code | `{半场}_{全场}`，各为 `HOME` / `DRAW` / `AWAY`，共 9 种 |
| 判赢 | 实际组合须与选项完全一致 |

| code | 含义 |
|------|------|
| `HOME_HOME` | 半场主胜 + 全场主胜 |
| `HOME_DRAW` | 半场主胜 + 全场和 |
| `HOME_AWAY` | 半场主胜 + 全场客胜 |
| `DRAW_HOME` | 半场和 + 全场主胜 |
| `DRAW_DRAW` | 半场和 + 全场和 |
| `DRAW_AWAY` | 半场和 + 全场客胜 |
| `AWAY_HOME` | 半场客胜 + 全场主胜 |
| `AWAY_DRAW` | 半场客胜 + 全场和 |
| `AWAY_AWAY` | 半场客胜 + 全场客胜 |

**示例**：半场 1:0、全场 1:1 → 半场 HOME、全场 DRAW → 选 `HOME_DRAW` **WIN**。

#### FT_TOTAL_GOALS（总进球数区间）

| 选项 code | 区间 |
|-----------|------|
| `TG_0_1` | 0–1 球 |
| `TG_2_3` | 2–3 球 |
| `TG_4_6` | 4–6 球 |
| `TG_7_PLUS` | 7 球及以上 |

判赢：按全场 `ftHome + ftAway` 落入区间。  
**示例**：3:2 → 总进球 5 → 选 `TG_4_6` **WIN**。

---

### 3.G 冠军（Outright）

#### OUTRIGHT_WINNER

| 项 | 内容 |
|----|------|
| 玩法说明 | 预测联赛/赛事**最终冠军**（如世界杯夺冠球队） |
| 选项 | 各参赛队 `selectionCode` = 球队 code（如 `FRA`、`BRA`） |
| 判赢 | `selectionCode === winnerTeamCode`（管理员指定冠军） |
| 串关 | **禁止** |
| 前置条件 | 联赛内常规赛事须全部 `SETTLED` 或 `CANCELLED` 后才可结算冠军盘 |
| 玩家入口 | `/bet` →「优胜冠军」→ `OutrightBetModal`（**不走** BetSlip 串关） |

---

## 4. 串关规则

实现：`packages/shared/src/betting-rules.ts`（`canSelectForParlay`）、`apps/api/src/domains/betting/bets.service.ts`、`apps/player/src/stores/betSlip.ts`。

| 规则 | 说明 |
|------|------|
| 腿数 | **2–5 腿** |
| 同场限制 | **每场比赛最多 1 项**（前端 `SAME_MATCH`；后端 `PARLAY_SAME_MATCH_FORBIDDEN`） |
| 禁止玩法 | 波胆（3 种）、冠军盘 |
| 禁止盘口线 | 让球/大小族（含队进球、角球、罚牌）的 **`.25` / `.75` 线**（`QUARTER_LINE`） |
| 可串关玩法 | `PARLAY_MARKET_TYPES` 共 **14 种**（见总览表「串关=✓」行） |
| 串关列表 API | `GET /api/player/matches?scope=parlay` 仅返回含可串关盘口的赛事 |

**串关派彩**（连乘有效因子、任一脚 LOSE 整单 LOST 等）见 [结算与返水金额规则.md §3](./结算与返水金额规则.md)。

---

## 5. 四分之一盘（.25 / .75）

让球/大小盘盘口线为 **0.25 或 0.75** 的整数倍时（如 -0.25、2.75），系统将盘口**拆成两条半盘**分别判定，再合并为腿级结果：

| 两半组合 | 合并结果 |
|----------|----------|
| 两赢 | WIN |
| 两输 | LOSE |
| 一赢一走 | HALF_WIN |
| 一输一走 | HALF_LOSE |
| 一赢一输 | PUSH |

| 场景 | 单关 | 串关 |
|------|------|------|
| 四分之一线 | **允许**下注 | **禁止**选入（`QUARTER_LINE`） |

**示例 1** — 全场让球 **-0.25**，选主队，比分 **0:0**：

- 拆为 -0 与 -0.5 两半：-0 → PUSH；-0.5 → LOSE
- 合并 → **HALF_LOSE**（退一半本金，见派彩文档）

**示例 2** — 全场大小 **2.25**，选小球，总进球 **2**：

- 拆为 2.0 与 2.5：对 2.0 小球 PUSH；对 2.5 小球 WIN
- 合并 → **HALF_WIN**

---

## 6. 下注校验与限额

### 6.1 下注校验（`BetsService.validateSelection`）

| 校验项 | 说明 |
|--------|------|
| 盘口状态 | 选项与盘口均为 `OPEN` |
| 玩家可见 | `showOnPlayer = true` |
| 赛事 | `PUBLISHED`；非冠军盘须未开球 |
| 运动 | 仅足球 |
| 赔率版本 | 请求 `oddsVersion` 须与库内一致 |
| 单关/串关 | 单关要求 `allowSingle`；串关走 `canSelectForParlay` |
| 资金 | 通过 `FundsPostingService.freezeBet` 冻结本金 |

### 6.2 默认限额（`betting-limits.service.ts`）

| 配置项 | 默认值 |
|--------|--------|
| 最小单注 | 1 |
| 单关最大投注 | 50,000 |
| 串关最大投注 | 20,000 |
| 单关最高派彩 | 500,000 |
| 串关最高派彩 | 1,000,000 |
| 玩家每日投注上限 | 200,000 |

可在管理端 `systemConfig` 覆盖；`potentialReturn` 超限会拒单（`MAX_PAYOUT`）。

### 6.3 其它

- **未知 marketType** 结算时默认 **LOSE**
- **选项 code 回退**：若快照无 code，可从中文名推断（`settlement-helpers.ts`）
- **玩家选盘**：赛事详情 → 点赔率 → `BetSlipDrawer`；波胆用 `CorrectScorePanel`

---

## 7. 下注与结算流程摘要

```mermaid
sequenceDiagram
  participant Player
  participant API
  participant Admin
  Player->>API: POST /player/bets/single 或 parlay
  API->>API: validateSelection + freezeBet
  Admin->>API: recordScore
  Admin->>API: previewSettlement
  Admin->>API: confirmSettlement
  API->>API: settleSelection 逐腿判赢
  API->>API: calculatePayout 或 calculateParlayPayout
  API->>Player: 钱包 settleBet 入账
```

| 阶段 | 说明 |
|------|------|
| 下注 | 创建 `Bet` + `BetSelection`，冻结 `stake` |
| 录入比分 | 赛事 → `PENDING_SETTLEMENT` |
| 预览 | 生成 `SettlementBatch`（PREVIEW），可含角球/罚牌统计 |
| 确认 | 写入腿级 `resultStatus`、注单 `status`/`actualReturn`，解冻并派彩 |

**跨场串关**：每场结算时只更新该场腿的 `resultStatus`；全部腿有结果后才调用 `calculateParlayPayout` 一次。

详细流程见 [settlement-and-fund-flow-analysis.md](./settlement-and-fund-flow-analysis.md)。

---

## 8. 代码真源与相关文档

### 8.1 代码索引

| 主题 | 文件 |
|------|------|
| 玩法目录（18 种） | `packages/shared/src/market-catalog.ts` |
| 串关选盘规则 | `packages/shared/src/betting-rules.ts` |
| 下注与校验 | `apps/api/src/domains/betting/bets.service.ts` |
| 下注限额 | `apps/api/src/domains/betting/betting-limits.service.ts` |
| 腿级结算 | `apps/api/src/domains/settlement/domain/settlement-calculator.ts` |
| 结算流程 | `apps/api/src/domains/settlement/settlement.service.ts` |
| 结算辅助 | `apps/api/src/domains/settlement/domain/settlement-helpers.ts` |
| 单元测试 | `apps/api/src/domains/settlement/domain/settlement-calculator.spec.ts` |
| Smoke 用例 | `apps/api/src/domains/operations/smoke-tests/smoke-test.cases.ts` |
| 玩家投注单 | `apps/player/src/stores/betSlip.ts` |

### 8.2 相关文档

| 文档 | 内容 |
|------|------|
| [结算与返水金额规则.md](./结算与返水金额规则.md) | 单关/串关派彩公式、四分之一盘金额、返水 |
| [settlement-and-fund-flow-analysis.md](./settlement-and-fund-flow-analysis.md) | 结算三步、钱包流水 |
| [默认数据说明.md](./默认数据说明.md) | seed 盘口范围、48 强冠军盘 |
| [UAT_CHECKLIST.md](./UAT_CHECKLIST.md) | 投注与串关 UAT 项 |

### 8.3 文档分工

| 本文档 | 结算金额文档 |
|--------|--------------|
| 每种玩法怎么选、怎么判赢 | stake × odds 怎么算 |
| 串关能否选、同场限制 | 串关连乘因子与 payout |
| 角球/罚牌统计要求 | HALF_WIN 派彩数值示例 |

---

*最后更新：与 `FOOTBALL_MARKET_CATALOG`（18 种）及 `settlement-calculator.ts` 实现对齐。*
