# 自定义推送模块 - 前端对接指南

> **日期**: 2026-03-18
> **后端状态**: ✅ 已完成，可直接对接
> **页面路由**: `/notification/push`（通知中心 → 自定义推送）

---

## 页面功能说明

管理员可以通过该页面，向C端用户发送自定义通知消息。

**核心流程**：
1. 填写推送标题和内容
2. 选择推送通道（站内信 / 短信 / 企业微信）
3. 选择推送目标（全部用户 / 指定用户）
4. 如选择"指定用户"，通过搜索框搜索并勾选用户
5. 点击发送，展示推送结果（成功/失败数）

---

## 接口清单

| # | 接口 | 方法 | 路径 | 说明 |
|---|------|------|------|------|
| 1 | 搜索推送目标用户 | GET | `/admin/notification/custom-push/users` | 选择"指定用户"时，搜索用户列表 |
| 2 | 发送自定义推送 | POST | `/admin/notification/custom-push` | 执行推送，返回成功/失败数 |
| 3 | 查询推送日志 | GET | `/admin/notification/logs` | 已有接口，用于查看推送记录 |

---

## 接口 1：搜索推送目标用户

**使用场景**：推送目标选择"指定用户"时，输入关键词搜索C端用户，展示为可勾选列表。

```
GET /admin/notification/custom-push/users?keyword=张三
```

### 请求参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| keyword | String | 否 | 搜索关键词，支持按**真实姓名**或**手机号**模糊搜索。不传则返回最近注册的20个用户 |

### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "id": "2025607151170445314",
      "realName": "张三",
      "phone": "138****1234",
      "avatarUrl": "https://oss.example.com/avatar/xxx.jpg"
    },
    {
      "id": "2025607151170445315",
      "realName": "张丽",
      "phone": "139****5678",
      "avatarUrl": null
    }
  ]
}
```

### 响应字段

| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 用户ID（雪花ID，注意用String接收） |
| realName | String | 真实姓名，可能为null（用户未完善资料） |
| phone | String | 手机号（脱敏显示），可能为null |
| avatarUrl | String | 头像URL，可能为null |

### 前端实现建议
- 用 `el-select` 远程搜索模式（`remote` + `filterable`），绑定搜索方法
- 搜索结果展示为：头像 + 姓名 + 手机号
- 支持多选（`multiple`），选中后存入 `userIds` 数组
- 防抖 300ms，避免频繁请求
- 无头像时显示默认头像或姓名首字占位

---

## 接口 2：发送自定义推送

**使用场景**：填写完推送内容后，点击"发送"按钮调用此接口。

```
POST /admin/notification/custom-push
Content-Type: application/json
```

### 请求参数

```json
{
  "title": "暑期特惠活动通知",
  "content": "亲爱的用户，暑期呼伦贝尔亲子营限时9折优惠，详情请查看小程序首页！",
  "channel": "INAPP",
  "targetType": "ALL_USERS",
  "userIds": null,
  "categoryCode": "PROMO",
  "link": "/pages/product/list"
}
```

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| title | String | **是** | 推送标题 |
| content | String | **是** | 推送内容（纯文本） |
| channel | String | **是** | 推送通道，见下方通道枚举 |
| targetType | String | **是** | 目标类型，见下方枚举 |
| userIds | Long[] | 条件必填 | 目标用户ID列表，`targetType=SPECIFIC_USERS` 时必填 |
| categoryCode | String | 否 | 消息分类编码，默认 `SYSTEM`，见下方分类枚举 |
| link | String | 否 | 跳转链接（站内信时使用），如小程序页面路径 |

### 通道枚举（channel）

| 值 | 中文 | 说明 | 推送对象 |
|----|------|------|----------|
| `INAPP` | 站内信 | 写入用户消息表，小程序"消息"页展示 | C端用户（小程序） |
| `SMS` | 短信 | 发送短信到用户手机号 | C端用户（手机号） |
| `WECHAT_WORK` | 企业微信 | 通过企微应用消息推送 | **仅员工**（企微内部成员） |

> ⚠️ **注意**：企业微信通道（`WECHAT_WORK`）只能推送给企微内部员工，不能推给C端普通用户。前端应在选择该通道时给予提示。

### 目标类型枚举（targetType）

| 值 | 中文 | 说明 |
|----|------|------|
| `ALL_USERS` | 全部用户 | 推送给所有活跃用户（最多1000人） |
| `SPECIFIC_USERS` | 指定用户 | 推送给 `userIds` 中指定的用户 |

### 消息分类枚举（categoryCode）

| 值 | 中文 | 使用场景 |
|----|------|----------|
| `SYSTEM` | 系统消息 | 系统公告、维护通知等（默认值） |
| `ORDER` | 订单消息 | 订单相关通知 |
| `TRIP` | 行程消息 | 行程提醒 |
| `PROMO` | 优惠促销 | 活动优惠、营销推送 |

### 响应示例

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "totalCount": 15,
    "successCount": 14,
    "failCount": 1
  }
}
```

### 响应字段

| 字段 | 类型 | 说明 |
|------|------|------|
| totalCount | Integer | 推送总人数 |
| successCount | Integer | 成功数 |
| failCount | Integer | 失败数（如用户无手机号、通道异常等） |

### 前端实现建议
- 发送前弹 `el-dialog` 确认框，显示"即将向 X 人推送，确认发送？"
- 发送按钮加 loading 状态（推送可能需要几秒）
- 发送成功后用 `el-result` 或 `el-message-box` 展示推送结果：
  - 全部成功：成功图标 + "推送完成，共成功 14 人"
  - 部分失败：警告图标 + "推送完成，成功 14 人，失败 1 人，详情请查看通知日志"
- 提供"查看推送日志"跳转按钮，跳到 `/notification/log` 页面
- 企业微信通道选中时，显示提示文字："企业微信仅支持推送给内部员工"

---

## 接口 3：查询推送日志（已有接口，复用）

**使用场景**：推送完成后查看推送记录详情，或在通知日志页面筛选自定义推送记录。

```
GET /admin/notification/logs?eventCode=CUSTOM_PUSH&page=1&pageSize=20
```

> 已有接口，筛选条件加 `eventCode=CUSTOM_PUSH` 即可查看自定义推送的发送记录。

---

## 页面布局建议

```
┌──────────────────────────────────────────────┐
│  自定义推送                                    │
├──────────────────────────────────────────────┤
│                                              │
│  推送标题：  [________________________]       │
│                                              │
│  推送内容：  [________________________]       │
│             [________________________]       │
│             [________________________]       │
│                                              │
│  推送通道：  ○ 站内信   ○ 短信   ○ 企业微信    │
│             ⚠️ 企微仅支持推送给内部员工         │
│                                              │
│  消息分类：  [系统消息 ▼]                      │
│                                              │
│  跳转链接：  [________________________]       │
│             (站内信时生效，如小程序页面路径)      │
│                                              │
│  推送目标：  ○ 全部用户   ○ 指定用户            │
│                                              │
│  选择用户：  [搜索姓名或手机号... ▼]            │
│             ┌──────────────────────┐         │
│             │ 👤 张三  138****1234  │         │
│             │ 👤 张丽  139****5678  │         │
│             └──────────────────────┘         │
│             (targetType=SPECIFIC_USERS时显示)  │
│                                              │
│                    [ 发送推送 ]                │
│                                              │
└──────────────────────────────────────────────┘
```

### 表单校验规则
- 标题：必填，最长50字
- 内容：必填，最长500字
- 通道：必选
- 目标类型：必选
- 用户列表：目标类型为"指定用户"时必选至少1人

---

## 完整调用示例

### 示例1：向全部用户推送站内信

```javascript
await request.post('/admin/notification/custom-push', {
  title: '暑期特惠活动',
  content: '呼伦贝尔亲子营限时9折优惠！',
  channel: 'INAPP',
  targetType: 'ALL_USERS',
  categoryCode: 'PROMO',
  link: '/pages/product/list'
})
```

### 示例2：向指定用户发送短信

```javascript
await request.post('/admin/notification/custom-push', {
  title: '出行提醒',
  content: '您的呼伦贝尔之旅将于3天后出发，请做好准备！',
  channel: 'SMS',
  targetType: 'SPECIFIC_USERS',
  userIds: ['2025607151170445314', '2025607151170445315'],
  categoryCode: 'TRIP'
})
```

### 示例3：搜索用户

```javascript
// 输入关键词搜索
const { data } = await request.get('/admin/notification/custom-push/users', {
  params: { keyword: '张' }
})
// data = [{ id, realName, phone, avatarUrl }, ...]
```
