# 数字票（Digital Ticket）— 设计文档

> 日期：2026-07-23 | 优先级：P0

## 1. 目标

引入数字票作为停车业务的统一抽象模型。所有进场方式（RFID/车牌识别/手动）最终创建数字票，以票的状态驱动计费、支付和放行。

## 2. 状态机

```
                    ┌──────────┐
               ┌──→ │  已过期   │ ←──┐
               │    └──────────┘    │
               │     超时未支付      │ 超时未离场
               │                    │
  ┌────────┐  │  ┌───────────┐  ┌──┴───┐  ┌────────┐
  │ 已创建  │─→│  │  待支付    │─→│ 已支付 │─→│ 已离场  │
  └────────┘    └───────────┘  └──────┘  └────────┘
  车辆入场      自动转换       支付成功    验证放行
```

| 状态 | 描述 | 触发条件 |
|------|------|---------|
| created | 车辆入场，数字票生成 | 入场事件触发 |
| pending_payment | 待支付 | 创建完成后自动进入 |
| paid | 已支付，费用结清 | 支付成功回调 |
| exited | 已离场，流程结束 | 验证通过后开闸 |
| expired | 超时未支付或未离场 | 定时任务/超时逻辑 |

## 3. 数据模型

### digital_ticket 表

| 字段 | 类型 | 说明 |
|------|------|------|
| id | uint | 主键 |
| ticket_no | string | 票号（UUID，二维码凭证） |
| plate_number | string | 车牌 |
| trigger_mode | string | rfid / plate_recognition / manual |
| state | string | created / pending_payment / paid / exited / expired |
| vehicle_record_id | uint | 关联 vehicle_record |
| entry_time | datetime | 入场时间 |
| exit_time | datetime | 出场时间 |
| fee | float64 | 计费金额 |
| payment_method | string | cash / free / wechat / alipay |
| payment_order_no | string | 支付单号（关联 payment_record） |
| paid_at | datetime | 支付时间 |
| expire_at | datetime | 超时过期时间 |
| event_log | text(JSON) | 事件日志数组 |

### event_log 格式

```json
[
  {"at": "2026-07-23 10:30", "event": "created", "trigger": "manual"},
  {"at": "2026-07-23 12:30", "event": "fee_calculated", "fee": 15.0},
  {"at": "2026-07-23 12:31", "event": "paid", "method": "cash", "amount": 20}
]
```

## 4. API

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /digital-ticket/create | 创建票（入场时） |
| GET | /digital-ticket/:ticketNo | 查询票（扫码用） |
| POST | /digital-ticket/:ticketNo/calculate | 计费 |
| POST | /digital-ticket/:ticketNo/pay | 支付 |
| POST | /digital-ticket/:ticketNo/exit | 离场验证 |
| GET | /digital-ticket/list | 列表 |

## 5. 与现有流程关系

```
任何进场方式 → DigitalTicket.Create() + VehicleEntry()
                                    │
                            状态: created → pending_payment
                                    │
                             ExitPreview / ExitConfirm
                                    │
                            状态: paid → exited
```

数字票作为业务状态层，位于 `internal/modules/digital-ticket/`，不替代 vehicle_record。

## 6. 文件变更

| 文件 | 操作 |
|------|------|
| `internal/dao/digital_ticket.go` | 新建 |
| `internal/modules/digital-ticket/api.go` | 新建 |
| `internal/modules/digital-ticket/service/service.go` | 新建 |
| `internal/modules/digital-ticket/repository/repo.go` | 新建 |
| `internal/service/vehicle/vehicle.go` | 修改（VehicleEntry 创建 digital_ticket） |
| `internal/initialize/gorm.go` | 修改（AutoMigrate） |
| `internal/initialize/router.go` | 修改（路由注册） |
