# 套餐接口快速导航

## 🎯 快速查找

### 按功能查找

| 需求 | 文件 | 行号 |
|------|------|------|
| 查看套餐数据模型 | `internal/model/package.go` | 28-56 |
| 查看套餐 API 请求/响应结构 | `internal/model/dto/package_dto.go` | 1-173 |
| 查看套餐 HTTP 处理器 | `internal/handler/admin/package.go` | 1-148 |
| 查看套餐业务逻辑 | `internal/service/package/service.go` | 1-745 |
| 查看套餐数据访问 | `internal/store/postgres/package_store.go` | 1-150 |
| 查看套餐 API 路由 | `internal/routes/package.go` | 1-78 |
| 查看路由注册入口 | `internal/routes/admin.go` | 71-78 |

### 按字段查找

| 字段 | Model 位置 | DTO 位置 | 说明 |
|------|-----------|---------|------|
| `duration_days` | `package.go:46` | `package_dto.go:96` | 套餐天数（按天时必填） |
| `calendar_type` | `package.go:45` | `package_dto.go:95` | 套餐周期类型 |
| `duration_months` | `package.go:37` | `package_dto.go:79` | 套餐时长（月数） |
| `real_data_mb` | `package.go:38` | `package_dto.go:80` | 真流量额度 |
| `virtual_data_mb` | `package.go:39` | `package_dto.go:81` | 虚流量额度 |
| `enable_virtual_data` | `package.go:40` | `package_dto.go:82` | 是否启用虚流量 |

### 按 API 端点查找

| 端点 | Handler 方法 | 路由文件 | 行号 |
|------|-------------|---------|------|
| `GET /packages` | `List()` | `package.go` | 15-21 |
| `POST /packages` | `Create()` | `package.go` | 23-29 |
| `GET /packages/:id` | `Get()` | `package.go` | 31-37 |
| `PUT /packages/:id` | `Update()` | `package.go` | 39-45 |
| `DELETE /packages/:id` | `Delete()` | `package.go` | 47-53 |
| `PATCH /packages/:id/status` | `UpdateStatus()` | `package.go` | 55-61 |
| `PATCH /packages/:id/shelf` | `UpdateShelfStatus()` | `package.go` | 63-69 |
| `PATCH /packages/:id/retail-price` | `UpdateRetailPrice()` | `package.go` | 71-77 |

---

## 🔍 关键代码片段

### 1. 套餐周期类型校验
**文件**：`internal/service/package/service.go:65-80`

**用途**：创建套餐时验证 `calendar_type` 和 `duration_days` 的配合

```go
if calendarType == constants.PackageCalendarTypeByDay {
    if req.DurationDays == nil || *req.DurationDays <= 0 {
        return nil, errors.New(errors.CodeInvalidParam, "按天套餐必须提供有效的duration_days")
    }
}
```

### 2. 虚流量配置校验
**文件**：`internal/service/package/service.go:51-63`

**用途**：验证虚流量配置的合法性

```go
if req.EnableVirtualData {
    if *req.VirtualDataMB > realDataMB {
        return nil, errors.New(errors.CodeInvalidParam, "虚流量额度不能大于真流量额度")
    }
}
```

### 3. 代理用户套餐过滤
**文件**：`internal/store/postgres/package_store.go:57-66`

**用途**：代理用户只能看到已分配的套餐

```go
if isAgent {
    query = query.Joins("INNER JOIN tb_shop_package_allocation ...").
        Where("tb_shop_package_allocation.shop_id = ? AND tb_shop_package_allocation.status = ?",
            shopID, constants.StatusEnabled)
}
```

---

## 📊 数据流向

```
HTTP 请求
    ↓
PackageHandler (internal/handler/admin/package.go)
    ↓
PackageService (internal/service/package/service.go)
    ├─ 业务逻辑校验
    ├─ 调用 PackageStore
    └─ 返回 DTO
    ↓
PackageStore (internal/store/postgres/package_store.go)
    ├─ 数据库查询
    └─ 返回 Model
    ↓
HTTP 响应 (DTO)
```

---

## 🛠️ 常见操作

### 添加新的套餐字段

1. **Model 层**：`internal/model/package.go` 的 `Package` 结构体
2. **DTO 层**：`internal/model/dto/package_dto.go` 的相关 Request/Response
3. **Service 层**：`internal/service/package/service.go` 的业务逻辑
4. **Store 层**：`internal/store/postgres/package_store.go` 的查询条件
5. **数据库**：迁移文件中添加新列

### 修改套餐 API 响应

1. 修改 `PackageResponse` 结构体（`package_dto.go:71-99`）
2. 修改 Service 的转换逻辑（`service.go` 中的 `toDTO()` 方法）
3. 测试 API 端点

### 添加新的套餐 API 端点

1. 在 `PackageHandler` 中添加方法（`internal/handler/admin/package.go`）
2. 在 `PackageService` 中添加业务逻辑（`internal/service/package/service.go`）
3. 在 `registerPackageRoutes()` 中注册路由（`internal/routes/package.go`）

---

## 📝 相关文档

- **套餐系统升级**：`docs/package-system-upgrade/`
- **套餐与佣金业务模型**：`docs/commission-package-model.md`
- **API 文档生成规范**：`docs/api-documentation-guide.md`

---

## 🔗 相关模块

| 模块 | 说明 | 文件 |
|------|------|------|
| **PackageSeries** | 套餐系列管理 | `internal/routes/package_series.go` |
| **PackageUsage** | 套餐使用记录 | `internal/routes/package_usage.go` |
| **ShopPackageAllocation** | 套餐分配给代理 | `internal/store/postgres/shop_package_allocation_store.go` |
| **ShopSeriesAllocation** | 系列分配给代理 | `internal/store/postgres/shop_series_allocation_store.go` |

