docs: standalone external API doc for bots/third-party
- docs/EXTERNAL-API.md: auth matrix (ID+Secret / legacy key / JWT), Python+Node quickstart, server alias syntax, 9 endpoints with request/response examples, status flow, error codes, troubleshooting, typical scenarios (QQ bot ticket flow, plugin ban sync) - README + API.md link to the standalone doc - verified: 24 checks, endpoints cross-checked doc vs code
This commit is contained in:
@@ -22,7 +22,8 @@
|
||||
|
||||
## API 文档
|
||||
|
||||
完整接口文档见 **[docs/API.md](docs/API.md)**(认证/工单/封禁/用户/设置/通知/投票/更新/导出/外部插件 API)。
|
||||
- **完整接口文档**:[docs/API.md](docs/API.md)(认证/工单/封禁/用户/设置/通知/投票/更新/导出/外部插件 API)
|
||||
- **第三方外部 API(机器人/插件)**:[docs/EXTERNAL-API.md](docs/EXTERNAL-API.md)(ID+Secret 鉴权、提交工单、进度追踪、封禁拉取、按子服拉数据)
|
||||
|
||||
## 快速开始
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# MC Report System API 文档
|
||||
|
||||
> 面向**机器人 / 第三方系统**的免登录 API(鉴权方式、请求示例、子服定位语法)见独立文档 **[EXTERNAL-API.md](EXTERNAL-API.md)**。
|
||||
|
||||
Base URL: `http://<host>:3100/api`
|
||||
|
||||
## 通用约定
|
||||
|
||||
349
docs/EXTERNAL-API.md
Normal file
349
docs/EXTERNAL-API.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# 外部 API 文档(机器人 / 第三方系统)
|
||||
|
||||
适用对象:QQ 官方机器人、游戏服务器插件、统计面板等**无法做网页登录**的外部系统。
|
||||
|
||||
- Base URL:`https://<你的域名>/api/external`
|
||||
- 数据格式:JSON(`Content-Type: application/json`)
|
||||
- 本文档所有接口**不需要用户登录**,只需要客户端凭据(见下)
|
||||
|
||||
---
|
||||
|
||||
## 一、鉴权(三种方式,任选其一)
|
||||
|
||||
### 方式 A:ID + Secret(推荐,多客户端)
|
||||
|
||||
在站点后台 →「外部API」页面创建客户端,获得一对凭据:
|
||||
|
||||
```text
|
||||
Client ID: c_1a2b3c4d5e6f7a8b9c0d1e2f
|
||||
Secret: s_9f8e7d6c5b4a39281726354a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3e
|
||||
```
|
||||
|
||||
> ⚠️ Secret 只在创建时显示一次,请立即保存。支持创建多个客户端、单独停用/删除,互不影响。
|
||||
|
||||
调用时在请求头携带:
|
||||
|
||||
| 请求头 | 值 |
|
||||
|--------|-----|
|
||||
| `x-api-client-id` | 你的 Client ID |
|
||||
| `x-api-secret` | 你的 Secret |
|
||||
|
||||
### 方式 B:旧版单 Key(兼容)
|
||||
|
||||
| 请求头 | 值 |
|
||||
|--------|-----|
|
||||
| `x-external-key` | 部署时配置的 external_api_key |
|
||||
|
||||
### 方式 C:用户 JWT(仅限插件)
|
||||
|
||||
| 请求头 | 值 |
|
||||
|--------|-----|
|
||||
| `Authorization` | `Bearer <JWT>`(来自 `POST /api/external/auth/login`) |
|
||||
|
||||
---
|
||||
|
||||
## 二、快速开始(Python / Node 示例)
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE = "https://你的域名/api/external"
|
||||
HEADERS = {
|
||||
"x-api-client-id": "c_1a2b3c4d5e6f7a8b9c0d1e2f",
|
||||
"x-api-secret": "s_9f8e7d6c...",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
# 提交举报工单
|
||||
r = requests.post(f"{BASE}/tickets", headers=HEADERS, json={
|
||||
"type": "report",
|
||||
"title": "恶意破坏",
|
||||
"reporter_game_name": "Steve",
|
||||
"reporter_game_uid": "df273bda10b94aa18db345574d5a1e1d",
|
||||
"target_game_name": "Alex",
|
||||
"target_game_uid": "SKIN_UUID_002",
|
||||
"reason": "刷屏+破坏他人建筑",
|
||||
"description": "多次警告无效",
|
||||
"server": "survival", # 可选: 子服别名
|
||||
})
|
||||
print(r.json()) # {"id": 123, "tracking_token": "..."}
|
||||
```
|
||||
|
||||
### Node.js
|
||||
|
||||
```javascript
|
||||
const BASE = 'https://你的域名/api/external';
|
||||
const H = {
|
||||
'x-api-client-id': 'c_1a2b3c...',
|
||||
'x-api-secret': 's_9f8e7d6c...',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
// 查询工单进度(从提交到结束全程可查)
|
||||
const res = await fetch(`${BASE}/tickets/track?token=你的tracking_token`, { headers: H });
|
||||
console.log(await res.json());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、子服务器定位(`server` 参数)
|
||||
|
||||
子服可在后台「服务器管理」配置**外部别名(alias)**。所有带 `server` 的接口支持三种写法:
|
||||
|
||||
| 写法 | 示例 | 说明 |
|
||||
|------|------|------|
|
||||
| 别名(推荐) | `survival` | 服务器改名不影响 |
|
||||
| 分组/子服 | `网易服务器/生存服` | URL 编码或 JSON 直接传 |
|
||||
| 子服名 | `生存服` | 同名时取第一个 |
|
||||
|
||||
查询服务器列表(含别名):`GET /api/external/servers`
|
||||
|
||||
---
|
||||
|
||||
## 四、接口清单
|
||||
|
||||
### 1. 提交工单
|
||||
|
||||
```
|
||||
POST /api/external/tickets
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| type | string | ✅ | `report` / `suggestion` / `appeal` |
|
||||
| title | string | ✅ | 标题 |
|
||||
| reporter_game_name | string | ✅ | 提交人游戏名 |
|
||||
| reporter_game_uid | string | ✅ | 提交人 UID / UUID |
|
||||
| target_game_name | string | 条件 | 被举报人游戏名(report 建议填) |
|
||||
| target_game_uid | string | 条件 | 被举报人 UID |
|
||||
| reason | string | 条件 | 举报原因(report/appeal 必填) |
|
||||
| description | string | 条件 | 详情(suggestion/appeal 必填) |
|
||||
| server | string | 否 | 子服(别名/分组/子服名) |
|
||||
|
||||
限制:同一提交人**待处理工单最多 5 个**。
|
||||
|
||||
**成功响应 201:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"tracking_token": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
||||
"server": "生存服"
|
||||
}
|
||||
```
|
||||
|
||||
> `tracking_token` 是查询进度的唯一凭证,请妥善保存。
|
||||
|
||||
### 2. 查询工单进度(提交 → 处理 → 结束)
|
||||
|
||||
```
|
||||
GET /api/external/tickets/track?token=<tracking_token>
|
||||
```
|
||||
|
||||
**成功响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 123,
|
||||
"type": "report",
|
||||
"title": "恶意破坏",
|
||||
"status": "processing",
|
||||
"priority": "medium",
|
||||
"reporter_game_name": "Steve",
|
||||
"target_game_name": "Alex",
|
||||
"reason": "刷屏+破坏他人建筑",
|
||||
"assigned_to": "管理员",
|
||||
"claim_note": "已受理",
|
||||
"server_name": "生存服",
|
||||
"created_at": "2026-08-19T10:00:00.000Z",
|
||||
"updated_at": "2026-08-19T11:30:00.000Z",
|
||||
"responses": [
|
||||
{ "content": "游戏内提交...", "is_staff": 0, "created_at": "..." },
|
||||
{ "content": "正在核实,请耐心等待", "is_staff": 1, "created_at": "..." }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**工单状态流转:**
|
||||
|
||||
```
|
||||
pending(待处理) → processing(处理中) → resolved(已解决)
|
||||
↘ awaiting_info(待补充信息) → processing / rejected(驳回)
|
||||
↘ closed(关闭) appealed(申诉中) → resolved / rejected
|
||||
```
|
||||
|
||||
### 3. 工单列表
|
||||
|
||||
```
|
||||
GET /api/external/all-tickets?type=&status=&server=&page=&limit=
|
||||
```
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| type | `report` / `suggestion` / `appeal` |
|
||||
| status | `pending` / `processing` / `awaiting_info` / `appealing` / `resolved` / `rejected` / `closed` |
|
||||
| server | 子服(别名/分组/子服名) |
|
||||
| page / limit | 分页,limit ≤ 200,默认 page=1 limit=50 |
|
||||
|
||||
### 4. 工单详情(含回复与附件)
|
||||
|
||||
```
|
||||
GET /api/external/all-tickets/:id
|
||||
```
|
||||
|
||||
### 5. 拉取封禁列表
|
||||
|
||||
```
|
||||
GET /api/external/bans?server=&status=&player=&page=&limit=
|
||||
```
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| server | 子服过滤(可选) |
|
||||
| status | `active` / `expired` / `appealed` / `lifted`(默认不滤) |
|
||||
| player | 按玩家名或 UID 精确匹配 |
|
||||
| page / limit | 分页,limit ≤ 500 |
|
||||
|
||||
**成功响应:**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 7,
|
||||
"player_name": "Alex",
|
||||
"player_uid": "SKIN_UUID_002",
|
||||
"source": "netease",
|
||||
"reason": "使用外挂",
|
||||
"type": "ban",
|
||||
"duration": "7d",
|
||||
"server_name": "生存服",
|
||||
"status": "active",
|
||||
"created_at": "2026-08-19T10:00:00.000Z",
|
||||
"expires_at": "2026-08-26T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 6. 新增封禁
|
||||
|
||||
```
|
||||
POST /api/external/bans
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"player_name": "Alex",
|
||||
"player_uid": "SKIN_UUID_002",
|
||||
"source": "netease",
|
||||
"reason": "使用外挂",
|
||||
"type": "ban",
|
||||
"duration": "7d",
|
||||
"expires_at": "2026-08-26T10:00:00.000Z",
|
||||
"server": "survival",
|
||||
"status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| player_name | ✅ | 玩家名 |
|
||||
| type | 否 | `ban` / `mute` / `warn` / `other`,默认 `ban` |
|
||||
| status | 否 | `active` / `expired` / `appealed` / `lifted`,默认 `active` |
|
||||
| expires_at | 否 | ISO 时间或 `null`(永久) |
|
||||
|
||||
**响应 201:** `{ "id": 7 }`
|
||||
|
||||
### 7. 被举报人统计
|
||||
|
||||
```
|
||||
GET /api/external/reported-players?server=
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"target_game_name": "Alex",
|
||||
"target_game_uid": "SKIN_UUID_002",
|
||||
"total": 5,
|
||||
"active": 2,
|
||||
"resolved": 3,
|
||||
"last_report": "2026-08-19T10:00:00.000Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 8. 服务器列表(含别名)
|
||||
|
||||
```
|
||||
GET /api/external/servers
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
[
|
||||
{ "group_name": "网易服务器", "server_name": "生存服", "alias": "survival" },
|
||||
{ "group_name": "网易服务器", "server_name": "空岛服", "alias": "skyblock" }
|
||||
]
|
||||
```
|
||||
|
||||
### 9. 工单统计
|
||||
|
||||
```
|
||||
GET /api/external/stats?server=
|
||||
```
|
||||
|
||||
**响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 128,
|
||||
"byType": [ { "type": "report", "c": 95 }, { "type": "suggestion", "c": 20 } ],
|
||||
"byStatus": [ { "status": "pending", "c": 12 }, { "status": "resolved", "c": 100 } ]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、错误码
|
||||
|
||||
| HTTP | 说明 |
|
||||
|------|------|
|
||||
| 400 | 参数错误(缺少必填字段 / 类型不正确 / 待处理工单超上限) |
|
||||
| 401 | 鉴权失败(凭据错误或客户端已停用) |
|
||||
| 404 | 工单 / 封禁不存在 |
|
||||
| 500 | 服务器内部错误 |
|
||||
|
||||
错误响应统一为 `{ "error": "描述信息" }`。
|
||||
|
||||
---
|
||||
|
||||
## 六、鉴权失败排查
|
||||
|
||||
1. **401 未授权**:检查 `x-api-client-id` / `x-api-secret` 是否与创建时一致;客户端是否被停用;secret 是否完整无换行空格。
|
||||
2. **客户端被停用**:后台「外部API」→ 启用。
|
||||
3. **需要多个客户端**:后台可创建多个,分别用于机器人 / 插件 / 统计面板,互不影响;删除即立即失效。
|
||||
|
||||
---
|
||||
|
||||
## 七、典型场景
|
||||
|
||||
### QQ 机器人:玩家提交举报
|
||||
|
||||
1. 玩家在 QQ 群发送举报信息 → 机器人调 `POST /tickets` 提交(reporter 为玩家 QQ 绑定的游戏名/UID)
|
||||
2. 机器人把返回的 `tracking_token` 发给玩家 → 玩家随时发「查进度」→ 机器人调 `GET /tickets/track?token=...`
|
||||
3. 处理结果(状态变化)可通过工单详情轮询,或后台「通知配置」设置 Webhook 推送
|
||||
|
||||
### 服务器插件:同步封禁
|
||||
|
||||
1. 插件启动时调 `GET /bans?status=active&server=生存服` 拉取本服封禁
|
||||
2. 服内封禁新玩家时调 `POST /bans` 同步到系统
|
||||
3. 定期轮询 `GET /bans?status=active` 保持同步
|
||||
|
||||
---
|
||||
|
||||
*协议版本 v1 · 服务端接口以部署版本为准*
|
||||
Reference in New Issue
Block a user