# 多渠道内容管理功能迁移指南

## 功能概述

多渠道内容管理功能允许同一个活动在不同渠道（小程序、发卡行H5页面）展示不同的内容，包括活动名称、图片、描述等字段。

## 核心概念

### 主渠道 (Primary Channel)
- 每个活动都有一个主渠道，其内容作为默认内容
- 主渠道类型可以是：
  - `miniapp`: 小程序
  - `issuer`: 发卡行

### 渠道内容差异化 (Channel Contents)
- 其他渠道可以基于主渠道内容进行差异化配置
- 只需配置与默认内容不同的字段
- 支持差异化的字段包括：
  - 活动名称 (name)
  - Banner图片 (banner_image_url)
  - 详情图片 (detail_image_url)
  - 奖励描述 (reward_description)
  - 活动描述 (description)
  - 商户描述 (merchant_description)
  - 条款条件 (terms_and_conditions)
  - 常见问题 (qna)
  - 适用卡片文本 (eligible_cards_text)
  - 无适用卡片提示信息 (no_eligible_cards_message)
  - 默认按钮文本 (default_action_button_text)

## 数据库结构

### 新增字段

在 `campaigns` 表中新增了以下字段：

```sql
-- 主渠道类型（miniapp 或 issuer）
primary_channel_type VARCHAR(20) DEFAULT 'miniapp'

-- 主渠道ID（当主渠道是发卡行时使用）
primary_channel_id BIGINT UNSIGNED NULL

-- 渠道差异化内容（JSON格式）
channel_contents JSON NULL
```

### 数据结构示例

```json
{
  "miniapp": {
    "name": "小程序专用活动名称",
    "banner_image_url": "https://example.com/miniapp-banner.jpg"
  },
  "issuer_1": {
    "name": "XX银行专用活动名称",
    "description": "XX银行专用活动描述",
    "banner_image_url": "https://example.com/bank-banner.jpg"
  }
}
```

## 迁移现有数据

### 使用迁移命令

我们提供了一个专门的 Artisan 命令来迁移现有的活动数据：

```bash
# 预览迁移（不会实际修改数据）
php artisan campaign:migrate-to-multichannel --dry-run

# 执行实际迁移
php artisan campaign:migrate-to-multichannel
```

### 迁移逻辑

1. **识别需要迁移的活动**: 查找 `primary_channel_type` 为 NULL 的活动
2. **设置默认值**:
   - `primary_channel_type` = `'miniapp'`
   - `primary_channel_id` = `NULL`
   - `channel_contents` = `NULL`
3. **保留现有数据**: 所有现有的活动字段和发卡行关联保持不变

### 迁移前准备

1. **备份数据库**: 确保在迁移前创建完整的数据库备份
2. **测试环境验证**: 在测试环境先执行迁移命令
3. **使用 dry-run**: 先使用 `--dry-run` 参数预览迁移结果

## 管理界面使用

### 主渠道配置

1. 在活动编辑界面找到"渠道配置"部分
2. 选择主渠道类型（小程序 或 发卡行）
3. 如果选择发卡行，需要进一步选择具体的发卡行

### 渠道内容差异化配置

1. 点击"渠道内容差异化配置"的"展开配置"按钮
2. 选择要配置的渠道
3. 为该渠道配置差异化的内容字段
4. 留空的字段将使用主渠道的默认内容

### 预览功能

- 使用"预览各渠道内容"按钮查看各渠道的最终展示内容
- 使用"重置所有差异化配置"清空所有渠道差异化设置

## API 接口

### 创建活动

POST `/api/admin/campaigns`

新增字段：
```json
{
  "primaryChannelType": "miniapp",
  "primaryChannelId": null,
  "channelContents": {
    "miniapp": {
      "name": "小程序专用名称"
    }
  }
}
```

### 更新活动

PUT `/api/admin/campaigns/{id}`

同创建活动的字段结构。

### 查询活动

GET `/api/admin/campaigns/{id}`

返回数据包含：
```json
{
  "primaryChannelType": "miniapp",
  "primaryChannelId": null,
  "channelContents": { ... },
  "issuers": [ ... ]
}
```

## 注意事项

### 兼容性

- 新功能完全向后兼容
- 现有的 API 调用无需修改
- 现有的活动数据不会丢失

### 性能考虑

- JSON 字段查询性能：`channel_contents` 使用 JSON 类型存储，查询时避免复杂的 JSON 操作
- 建议使用模型方法获取渠道内容：`$campaign->getContentForChannel('miniapp')`

### 数据完整性

- 主渠道ID 设置了外键约束，删除发卡行时会自动设置为 NULL
- 渠道关联删除时，对应的渠道差异化内容需要手动清理

## 故障排除

### 迁移失败

如果迁移命令执行失败：

1. 检查数据库连接
2. 确认 Campaign 模型已更新
3. 检查数据库表结构是否正确
4. 查看具体错误信息

### 界面显示问题

如果管理界面显示异常：

1. 清除浏览器缓存
2. 检查 JavaScript 控制台错误
3. 确认已加载最新的前端代码

### 数据查询问题

如果渠道内容查询异常：

1. 确认 `channel_contents` 字段的 JSON 格式正确
2. 使用模型提供的方法而非直接查询 JSON 字段
3. 检查渠道键名格式（如 `issuer_1`）

## 联系支持

如遇到问题，请提供：
1. 具体的错误信息
2. 操作步骤
3. 数据库和应用日志
4. 环境信息（Laravel 版本、PHP 版本等）