Compare commits
2 Commits
609ab002b3
...
87ae55ebcf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87ae55ebcf | ||
|
|
82a997fb07 |
610
docs/api-json.md
Normal file
610
docs/api-json.md
Normal file
@@ -0,0 +1,610 @@
|
||||
# Xboard API 返回 JSON 结构
|
||||
|
||||
基于 `reference/Xboard` 控制器、资源类、服务类静态分析整理。
|
||||
|
||||
说明:
|
||||
- `T` 代表具体数据类型。
|
||||
- “标准成功壳子”来自 `App\Helpers\ApiResponse::success()`。
|
||||
- “标准失败壳子”来自 `App\Helpers\ApiResponse::fail()` 和全局异常处理。
|
||||
- 少量接口直接 `response()->json()` 或返回文本/文件,不走统一壳子。
|
||||
- 后台前缀统一记为 `/api/v2/{admin_secure_path}`。
|
||||
|
||||
## 统一返回壳子
|
||||
|
||||
### 标准成功壳子 `StandardSuccess<T>`
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "操作成功",
|
||||
"data": "<T>",
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
### 标准失败壳子 `StandardFail`
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "fail",
|
||||
"message": "错误信息",
|
||||
"data": null,
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
如果抛出 `ApiException`,`error` 可能带校验细节:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "fail",
|
||||
"message": "错误信息",
|
||||
"data": null,
|
||||
"error": {
|
||||
"field": [
|
||||
"具体错误"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 分页壳子 `Paginate<T>`
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 100,
|
||||
"current_page": 1,
|
||||
"per_page": 10,
|
||||
"last_page": 10,
|
||||
"data": [
|
||||
"<T>"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 简单列表壳子 `DataTotal<T>`
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
"<T>"
|
||||
],
|
||||
"total": 100
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义分页壳子 `DataPagination<T>`
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
"<T>"
|
||||
],
|
||||
"pagination": {
|
||||
"current_page": 1,
|
||||
"last_page": 10,
|
||||
"per_page": 15,
|
||||
"total": 150
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 裸 `data` 壳子 `BareData<T>`
|
||||
|
||||
```json
|
||||
{
|
||||
"data": "<T>"
|
||||
}
|
||||
```
|
||||
|
||||
### 仅消息 `MessageOnly`
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "文本消息"
|
||||
}
|
||||
```
|
||||
|
||||
## 共享数据结构
|
||||
|
||||
### `AuthData`
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "用户订阅 token",
|
||||
"auth_data": "Bearer <sanctum_token>",
|
||||
"is_admin": false
|
||||
}
|
||||
```
|
||||
|
||||
### `SessionToken`
|
||||
|
||||
来自 Sanctum token 原始序列化,核心字段通常包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "随机 token 名称",
|
||||
"abilities": ["*"],
|
||||
"last_used_at": "2026-04-18T00:00:00.000000Z",
|
||||
"expires_at": "2027-04-18T00:00:00.000000Z",
|
||||
"created_at": "2026-04-18T00:00:00.000000Z",
|
||||
"updated_at": "2026-04-18T00:00:00.000000Z"
|
||||
}
|
||||
```
|
||||
|
||||
### `PlanResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"group_id": 1,
|
||||
"name": "套餐名",
|
||||
"tags": ["tag1"],
|
||||
"content": "展示文案",
|
||||
"month_price": 1000,
|
||||
"quarter_price": 2000,
|
||||
"half_year_price": 3000,
|
||||
"year_price": 4000,
|
||||
"two_year_price": 5000,
|
||||
"three_year_price": 6000,
|
||||
"onetime_price": 7000,
|
||||
"reset_price": 800,
|
||||
"capacity_limit": 100,
|
||||
"transfer_enable": 107374182400,
|
||||
"speed_limit": 100,
|
||||
"device_limit": 3,
|
||||
"show": true,
|
||||
"sell": true,
|
||||
"renew": true,
|
||||
"reset_traffic_method": 0,
|
||||
"sort": 1,
|
||||
"created_at": 1710000000,
|
||||
"updated_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `OrderResource`
|
||||
|
||||
`Order` 原始字段加两个派生字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"user_id": 1,
|
||||
"plan_id": 1,
|
||||
"trade_no": "uuid",
|
||||
"total_amount": 1000,
|
||||
"balance_amount": 0,
|
||||
"status": 0,
|
||||
"type": 1,
|
||||
"period": "month_price",
|
||||
"coupon_id": null,
|
||||
"payment_id": null,
|
||||
"created_at": 1710000000,
|
||||
"updated_at": 1710000000,
|
||||
"plan": "<PlanResource|null>"
|
||||
}
|
||||
```
|
||||
|
||||
### `TicketResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"level": 1,
|
||||
"reply_status": 0,
|
||||
"status": 0,
|
||||
"subject": "主题",
|
||||
"message": [
|
||||
"<MessageResource>"
|
||||
],
|
||||
"created_at": 1710000000,
|
||||
"updated_at": 1710000000,
|
||||
"user_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
### `MessageResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"ticket_id": 1,
|
||||
"is_me": true,
|
||||
"message": "正文",
|
||||
"created_at": 1710000000,
|
||||
"updated_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `KnowledgeResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"category": "分类",
|
||||
"title": "标题",
|
||||
"body": "正文,可选",
|
||||
"updated_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `InviteCodeResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": 1,
|
||||
"code": "ABCDEFGH",
|
||||
"pv": 12,
|
||||
"status": 0,
|
||||
"created_at": 1710000000,
|
||||
"updated_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `CommissionLogResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"order_amount": 1000,
|
||||
"trade_no": "uuid",
|
||||
"get_amount": 100,
|
||||
"created_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `TrafficLogResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"d": 1024,
|
||||
"u": 2048,
|
||||
"record_at": 1710000000,
|
||||
"server_rate": 1,
|
||||
"user_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
### `NodeResource`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"type": "vmess",
|
||||
"version": 2,
|
||||
"name": "香港 01",
|
||||
"rate": 1,
|
||||
"tags": ["hk"],
|
||||
"is_online": true,
|
||||
"cache_key": "hash",
|
||||
"last_check_at": 1710000000
|
||||
}
|
||||
```
|
||||
|
||||
### `NodeConfig`
|
||||
|
||||
节点配置的公共骨架如下,具体字段按协议追加:
|
||||
|
||||
```json
|
||||
{
|
||||
"protocol": "vmess|trojan|vless|shadowsocks|hysteria|tuic|anytls|socks|naive|http|mieru",
|
||||
"listen_ip": "0.0.0.0",
|
||||
"server_port": 443,
|
||||
"network": "tcp|ws|grpc|...",
|
||||
"networkSettings": {},
|
||||
"base_config": {
|
||||
"push_interval": 60,
|
||||
"pull_interval": 60
|
||||
},
|
||||
"routes": [],
|
||||
"custom_outbounds": [],
|
||||
"custom_routes": [],
|
||||
"cert_config": {}
|
||||
}
|
||||
```
|
||||
|
||||
协议常见追加字段:
|
||||
- `shadowsocks`: `cipher`, `plugin`, `plugin_opts`, `server_key`
|
||||
- `vmess`: `tls`, `multiplex`
|
||||
- `trojan`: `host`, `server_name`, `tls`, `tls_settings`, `multiplex`
|
||||
- `vless`: `tls`, `flow`, `decryption`, `tls_settings`, `multiplex`
|
||||
- `hysteria`: `version`, `host`, `server_name`, `up_mbps`, `down_mbps`, `obfs`, `obfs-password`
|
||||
- `tuic`: `version`, `server_name`, `congestion_control`, `tls_settings`, `auth_timeout`, `zero_rtt_handshake`, `heartbeat`
|
||||
- `anytls`: `server_name`, `padding_scheme`
|
||||
|
||||
## V1 Guest
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v1/guest/plan/fetch` | `StandardSuccess<PlanResource[]>` | `StandardFail` |
|
||||
| `POST /api/v1/guest/telegram/webhook` | 空响应体,`200` | `StandardFail`,常见为 `401` |
|
||||
| `GET/POST /api/v1/guest/payment/notify/{method}/{uuid}` | 可能是 `StandardFail`,也可能是纯文本 `"success"`,也可能是支付插件自定义返回 | 失败时通常 `StandardFail` |
|
||||
| `GET /api/v1/guest/comm/config` | `StandardSuccess<{ tos_url, is_email_verify, is_invite_force, email_whitelist_suffix, is_captcha, captcha_type, recaptcha_site_key, recaptcha_v3_site_key, recaptcha_v3_score_threshold, turnstile_site_key, app_description, app_url, logo, is_recaptcha }>` | `StandardFail` |
|
||||
|
||||
## V1 Passport
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `POST /api/v1/passport/auth/register` | `StandardSuccess<AuthData>` | `StandardFail` |
|
||||
| `POST /api/v1/passport/auth/login` | `StandardSuccess<AuthData>` | `StandardFail` |
|
||||
| `GET /api/v1/passport/auth/token2Login` | 分支 1: `302` 跳转;分支 2: `BareData<AuthData>` | 参数错误时 `{"message":"Invalid request"}` 或 `{"message":"Token error"}` |
|
||||
| `POST /api/v1/passport/auth/forget` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/passport/auth/getQuickLoginUrl` | `StandardSuccess<string>` | 未授权时 `401`,格式为 `{"message":[401001,"..."]}` 或 `{"message":[401200,"..."]}` |
|
||||
| `POST /api/v1/passport/auth/loginWithMailLink` | `StandardSuccess<string|object>` | `StandardFail` |
|
||||
| `POST /api/v1/passport/comm/sendEmailVerify` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/passport/comm/pv` | `StandardSuccess<true>` | `StandardFail` |
|
||||
|
||||
## V1 User
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v1/user/resetSecurity` | `StandardSuccess<string>`,即新的订阅地址 | `StandardFail` |
|
||||
| `GET /api/v1/user/info` | `StandardSuccess<{ email, transfer_enable, last_login_at, created_at, banned, remind_expire, remind_traffic, expired_at, balance, commission_balance, plan_id, discount, commission_rate, telegram_id, uuid, avatar_url }>` | `StandardFail` |
|
||||
| `POST /api/v1/user/changePassword` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/user/update` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v1/user/getSubscribe` | `StandardSuccess<{ plan_id, token, expired_at, u, d, transfer_enable, email, uuid, device_limit, speed_limit, next_reset_at, plan?, subscribe_url, reset_day }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/getStat` | `StandardSuccess<[pending_order_count, pending_ticket_count, invite_user_count]>` | `StandardFail` |
|
||||
| `GET /api/v1/user/checkLogin` | `StandardSuccess<{ is_login: true, is_admin?: true }>` | `StandardFail` |
|
||||
| `POST /api/v1/user/transfer` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/user/getQuickLoginUrl` | `StandardSuccess<string>` | `StandardFail` |
|
||||
| `GET /api/v1/user/getActiveSession` | `StandardSuccess<SessionToken[]>` | `StandardFail` |
|
||||
| `POST /api/v1/user/removeActiveSession` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/user/order/save` | `StandardSuccess<string>`,即 `trade_no` | `StandardFail` |
|
||||
| `POST /api/v1/user/order/checkout` | `{"type": -1|0|1|2, "data": true|string|object}` | `StandardFail` |
|
||||
| `GET /api/v1/user/order/check` | `StandardSuccess<number>`,即订单状态码 | `StandardFail` |
|
||||
| `GET /api/v1/user/order/detail` | `StandardSuccess<OrderResource>`,可能附加 `try_out_plan_id`、`surplus_orders` | `StandardFail` |
|
||||
| `GET /api/v1/user/order/fetch` | `StandardSuccess<OrderResource[]>` | `StandardFail` |
|
||||
| `GET /api/v1/user/order/getPaymentMethod` | `StandardSuccess<Array<{ id, name, payment, icon, handling_fee_fixed, handling_fee_percent }>>` | `StandardFail` |
|
||||
| `POST /api/v1/user/order/cancel` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v1/user/plan/fetch` | `StandardSuccess<PlanResource[]|PlanResource>` | `StandardFail` |
|
||||
| `GET /api/v1/user/invite/save` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `GET /api/v1/user/invite/fetch` | `StandardSuccess<{ codes: InviteCodeResource[], stat: [invite_user_count, commission_sum, uncheck_commission_balance, commission_rate, commission_balance] }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/invite/details` | `DataTotal<CommissionLogResource>` | 通常无统一失败壳子 |
|
||||
| `GET /api/v1/user/notice/fetch` | `DataTotal<NoticeModel>` | 通常无统一失败壳子 |
|
||||
| `POST /api/v1/user/ticket/reply` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/user/ticket/close` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/user/ticket/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v1/user/ticket/fetch` | `StandardSuccess<TicketResource[]|TicketResource>` | `StandardFail` |
|
||||
| `POST /api/v1/user/ticket/withdraw` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v1/user/server/fetch` | `{"data": NodeResource[]}`,带 `ETag`,命中时返回 `304` 空体 | 无节点时仍是空数组 |
|
||||
| `POST /api/v1/user/coupon/check` | `StandardSuccess<CouponModel>`,其中 `limit_plan_ids`、`limit_period` 已被格式化 | `StandardFail` |
|
||||
| `POST /api/v1/user/gift-card/check` | `StandardSuccess<{ code_info: { code, template: { name, description, type, type_name, icon, background_image, theme_color }, status, status_name, expires_at, usage_count, max_usage, plan_info? }, reward_preview: object, can_redeem: boolean, reason: string|null }>` | `StandardFail` |
|
||||
| `POST /api/v1/user/gift-card/redeem` | `StandardSuccess<{ message, rewards, invite_rewards, template_name }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/gift-card/history` | `DataPagination<{ id, code, template_name, template_type, template_type_name, rewards_given, invite_rewards, multiplier_applied, created_at }>` | 校验失败时框架默认校验 JSON |
|
||||
| `GET /api/v1/user/gift-card/detail` | `StandardSuccess<{ id, code, template: { name, description, type, type_name, icon, theme_color }, rewards_given, invite_rewards, invite_user, user_level_at_use, plan_id_at_use, multiplier_applied, notes, created_at }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/gift-card/types` | `StandardSuccess<{ types: object }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/telegram/getBotInfo` | `StandardSuccess<{ username: string }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/comm/config` | `StandardSuccess<{ is_telegram, telegram_discuss_link, stripe_pk, withdraw_methods, withdraw_close, currency, currency_symbol, commission_distribution_enable, commission_distribution_l1, commission_distribution_l2, commission_distribution_l3 }>` | `StandardFail` |
|
||||
| `POST /api/v1/user/comm/getStripePublicKey` | `StandardSuccess<string>` | `StandardFail` |
|
||||
| `GET /api/v1/user/knowledge/fetch` | `StandardSuccess<KnowledgeResource|{ [category: string]: KnowledgeResource[] }>` | `StandardFail` |
|
||||
| `GET /api/v1/user/knowledge/getCategory` | 路由存在,但控制器中无该方法 | 实际调用大概率 `500` |
|
||||
| `GET /api/v1/user/stat/getTrafficLog` | `StandardSuccess<TrafficLogResource[]>` | `StandardFail` |
|
||||
|
||||
## V1 Server
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v1/server/UniProxy/config` | `NodeConfig`,带 `ETag`,命中时 `304` 空体 | 非统一壳子 |
|
||||
| `GET /api/v1/server/UniProxy/user` | `{"users":[{ "id":1, "uuid":"...", "speed_limit":100, "device_limit":3 }]}`,带 `ETag` | 非统一壳子 |
|
||||
| `POST /api/v1/server/UniProxy/push` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v1/server/UniProxy/alive` | `{"data": true}` | 解析失败时 `{"error":"Invalid online data"}` |
|
||||
| `GET /api/v1/server/UniProxy/alivelist` | `{"alive": { "uid": ["1.1.1.1"] }}` | 非统一壳子 |
|
||||
| `POST /api/v1/server/UniProxy/status` | `{"data": true, "code": 0, "message": "success"}` | 校验失败时为框架校验 JSON |
|
||||
| `GET /api/v1/server/ShadowsocksTidalab/user` | `{"data":[{ "id":1, "port":443, "cipher":"aes-256-gcm", "secret":"uuid" }]}`,带 `ETag` | 非统一壳子 |
|
||||
| `POST /api/v1/server/ShadowsocksTidalab/submit` | `{"ret":1,"msg":"ok"}` | 非统一壳子 |
|
||||
| `GET /api/v1/server/TrojanTidalab/config` | 原始 JSON 字符串,核心字段为 `run_type/local_addr/local_port/remote_addr/remote_port/password/ssl/api` | 失败时 `StandardFail` |
|
||||
| `GET /api/v1/server/TrojanTidalab/user` | `{"msg":"ok","data":[{...用户原始字段..., "trojan_user":{"password":"uuid"}}]}`,带 `ETag` | 非统一壳子 |
|
||||
| `POST /api/v1/server/TrojanTidalab/submit` | `{"ret":1,"msg":"ok"}` | 非统一壳子 |
|
||||
|
||||
## V1 Client
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v1/client/subscribe` | 非 JSON;返回订阅文本,具体格式取决于客户端协议类 | 不可用时 `403` 空文本 |
|
||||
| `GET /{subscribe_path}/{token}` | 同上 | 同上 |
|
||||
| `GET /api/v1/client/app/getConfig` | 非 JSON;返回 Clash YAML 文本 | 非统一壳子 |
|
||||
| `GET /api/v1/client/app/getVersion` | `StandardSuccess<{ windows_version, windows_download_url, macos_version, macos_download_url, android_version, android_download_url }>`;对旧 UA 会退化为 `{ version, download_url }` | `StandardFail` |
|
||||
|
||||
## V2 Passport / User / Client / Server
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `/api/v2/passport/*` | 与对应 `/api/v1/passport/*` 完全相同 | 同 V1 |
|
||||
| `GET /api/v2/user/resetSecurity` | 与 `/api/v1/user/resetSecurity` 相同 | 同 V1 |
|
||||
| `GET /api/v2/user/info` | 与 `/api/v1/user/info` 相同 | 同 V1 |
|
||||
| `GET /api/v2/client/app/getConfig` | `{"data": { app_info, features, ui_config, business_rules, server_config, security_config, payment_config, notification_config, cache_config, last_updated, config_hash }}` | 非统一壳子 |
|
||||
| `GET /api/v2/client/app/getVersion` | 与 `/api/v1/client/app/getVersion` 相同 | 同 V1 |
|
||||
| `POST /api/v2/server/handshake` | `{"websocket":{"enabled":true,"ws_url":"wss://example.com:8076"}}` 或 `{"websocket":{"enabled":false}}` | 非统一壳子 |
|
||||
| `POST /api/v2/server/report` | `{"data": true}` | 非统一壳子 |
|
||||
| 其余 `/api/v2/server/config|user|push|alive|alivelist|status` | 与对应 `/api/v1/server/UniProxy/*` 相同 | 同 V1 |
|
||||
|
||||
## V2 Admin - Config / Plan / Server
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v2/{admin_secure_path}/config/fetch` | `StandardSuccess<ConfigMappings>`;带 `key` 时仅返回单组 | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/config/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/config/getEmailTemplate` | `StandardSuccess<string[]>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/config/getThemeTemplate` | `StandardSuccess<string[]>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/config/setTelegramWebhook` | `StandardSuccess<{ success: true, webhook_url: string, webhook_base_url: string|null }>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/config/testSendMail` | `{"data": <MailLogModel>}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/plan/fetch` | `StandardSuccess<PlanModel[]>`,每项额外带 `group/users_count/active_users_count` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/plan/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/plan/drop` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/plan/update` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/plan/sort` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/server/group/fetch` | `StandardSuccess<ServerGroupModel[]>`,含 `users_count/server_count` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/group/save` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/group/drop` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/server/route/fetch` | `{"data": <ServerRouteModel[]>}` | 非统一壳子 |
|
||||
| `POST /api/v2/{admin_secure_path}/server/route/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/route/drop` | `{"data": true}` | 失败时 `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/server/manage/getNodes` | `StandardSuccess<ServerModel[]>`,附加 `groups/parent/last_check_at/last_push_at/online/is_online/available_status/cache_key/load_status/metrics/online_conn` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/sort` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/update` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/drop` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/copy` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/batchDelete` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/resetTraffic` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/server/manage/batchResetTraffic` | `StandardSuccess<true>` | `StandardFail` |
|
||||
|
||||
`ConfigMappings` 的顶层 key 为:
|
||||
- `invite`
|
||||
- `site`
|
||||
- `subscribe`
|
||||
- `server`
|
||||
- `email`
|
||||
- `telegram`
|
||||
- `app`
|
||||
- `safe`
|
||||
- `subscribe_template`
|
||||
|
||||
## V2 Admin - Order / User / Stat
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `ANY /api/v2/{admin_secure_path}/order/fetch` | `Paginate<OrderModel>`;每项多出 `plan`,且 `period` 已转换成旧字段名 | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/order/update` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/order/assign` | `StandardSuccess<string>`,即 `trade_no` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/order/paid` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/order/cancel` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/order/detail` | `StandardSuccess<OrderModel>`,含 `user/plan/commission_log/invite_user/surplus_orders/period` | `StandardFail` |
|
||||
| `ANY /api/v2/{admin_secure_path}/user/fetch` | `Paginate<AdminUser>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/update` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/user/getUserInfoById` | `StandardSuccess<UserModel>`,已加载 `invite_user` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/generate` | 单个生成: `StandardSuccess<true>`;批量生成 JSON: `{"code":0,"message":"批量生成成功","data":[{ email, password, expired_at, uuid, created_at, subscribe_url }]}`;也可能返回 CSV 文件 | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/dumpCSV` | 非 JSON;CSV 文件流 | 参数错误时 `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/sendMail` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/ban` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/resetSecret` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/setInviteUser` | 路由存在,但控制器无方法 | 实际调用大概率 `500` |
|
||||
| `POST /api/v2/{admin_secure_path}/user/destroy` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getOverride` | `{"data": { month_income, month_register_total, ticket_pending_total, commission_pending_total, day_income, last_month_income, commission_month_payout, commission_last_month_payout, online_nodes, online_devices, online_users, today_traffic, month_traffic, total_traffic }}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getStats` | `{"data": { todayIncome, dayIncomeGrowth, currentMonthIncome, lastMonthIncome, monthIncomeGrowth, lastMonthIncomeGrowth, currentMonthCommissionPayout, lastMonthCommissionPayout, commissionGrowth, commissionPendingTotal, currentMonthNewUsers, totalUsers, activeUsers, userGrowth, onlineUsers, onlineDevices, ticketPendingTotal, onlineNodes, todayTraffic, monthTraffic, totalTraffic }}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getServerLastRank` | `StandardSuccess<array>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getServerYesterdayRank` | `StandardSuccess<array>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getOrder` | `{"code":0,"message":"success","data":{"list":[...],"summary":{...}}}` | 非统一壳子 |
|
||||
| `ANY /api/v2/{admin_secure_path}/stat/getStatUser` | `{"data":[<StatUserModel>],"total":100}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getRanking` | 路由存在,但控制器无方法 | 实际调用大概率 `500` |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getStatRecord` | `{"data": <service_result>}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/stat/getTrafficRank` | `{"timestamp":"2026-04-18T00:00:00+00:00","data":[{ id, name, value, previousValue, change, timestamp }]}` | 非统一壳子 |
|
||||
|
||||
`AdminUser` 为 `User` 原始字段加:
|
||||
|
||||
```json
|
||||
{
|
||||
"balance": 12.34,
|
||||
"commission_balance": 1.23,
|
||||
"subscribe_url": "https://example.com/s/xxxxx",
|
||||
"plan": {
|
||||
"id": 1,
|
||||
"name": "套餐"
|
||||
},
|
||||
"invite_user": {
|
||||
"id": 2,
|
||||
"email": "a@example.com"
|
||||
},
|
||||
"group": {
|
||||
"id": 1,
|
||||
"name": "默认组"
|
||||
},
|
||||
"total_used": 123456789
|
||||
}
|
||||
```
|
||||
|
||||
## V2 Admin - Notice / Ticket / Coupon / Knowledge
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v2/{admin_secure_path}/notice/fetch` | `StandardSuccess<NoticeModel[]>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/notice/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/notice/update` | 路由存在,但控制器无方法 | 实际调用大概率 `500` |
|
||||
| `POST /api/v2/{admin_secure_path}/notice/drop` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/notice/show` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/notice/sort` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `ANY /api/v2/{admin_secure_path}/ticket/fetch` | 详情模式: `StandardSuccess<TicketModel>`,含 `messages/user`;列表模式: `{"data":[<TicketModel+user>],"total":100}` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/ticket/reply` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/ticket/close` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `ANY /api/v2/{admin_secure_path}/coupon/fetch` | `Paginate<CouponModel>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/coupon/generate` | 单个/编辑时 `StandardSuccess<true>`;批量生成时直接输出 CSV 文本 | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/coupon/drop` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/coupon/show` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/coupon/update` | 源码成功路径未 `return`,实际大概率是 `200` 空响应体 | 失败时 `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/knowledge/fetch` | `StandardSuccess<KnowledgeModel[]|KnowledgeModel>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/knowledge/getCategory` | `StandardSuccess<string[]>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/knowledge/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/knowledge/show` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/knowledge/drop` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/knowledge/sort` | `StandardSuccess<true>` | `StandardFail` |
|
||||
|
||||
## V2 Admin - Gift Card / Payment
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `ANY /api/v2/{admin_secure_path}/gift-card/templates` | `Paginate<GiftCardTemplateModel>`;源码中自定义映射结果未真正返回 | 校验失败时为框架校验 JSON |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/create-template` | `StandardSuccess<GiftCardTemplateModel>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/update-template` | `StandardSuccess<GiftCardTemplateModel>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/delete-template` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/generate-codes` | JSON 模式: `StandardSuccess<{ batch_id, count, message }>`;导出模式: CSV 文件流 | `StandardFail` |
|
||||
| `ANY /api/v2/{admin_secure_path}/gift-card/codes` | `Paginate<GiftCardCodeModel>`;源码中自定义映射结果未真正返回 | 校验失败时为框架校验 JSON |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/toggle-code` | `StandardSuccess<{ message }>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/gift-card/export-codes` | 非 JSON;纯文本下载,每行一个 code | 校验失败时为框架校验 JSON |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/update-code` | `StandardSuccess<GiftCardCodeModel>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/gift-card/delete-code` | `StandardSuccess<{ message }>` | `StandardFail` |
|
||||
| `ANY /api/v2/{admin_secure_path}/gift-card/usages` | `Paginate<GiftCardUsageModel|mapped_item>` | 校验失败时为框架校验 JSON |
|
||||
| `ANY /api/v2/{admin_secure_path}/gift-card/statistics` | `StandardSuccess<{ total_stats, daily_usages, type_stats }>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/gift-card/types` | `StandardSuccess<object>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/payment/fetch` | `StandardSuccess<PaymentModel[]>`,每项附加 `notify_url` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/payment/getPaymentMethods` | `StandardSuccess<string[]>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/payment/getPaymentForm` | `StandardSuccess<array>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/payment/save` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/payment/drop` | `StandardSuccess<boolean>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/payment/show` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/payment/sort` | `StandardSuccess<true>` | `StandardFail` |
|
||||
|
||||
## V2 Admin - System / Theme / Plugin / Traffic Reset
|
||||
|
||||
| 接口 | 成功返回 | 失败/特殊返回 |
|
||||
| --- | --- | --- |
|
||||
| `GET /api/v2/{admin_secure_path}/system/getSystemStatus` | `StandardSuccess<{ schedule: boolean, horizon: boolean, schedule_last_runtime: mixed }>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/system/getQueueStats` | `StandardSuccess<{ failedJobs, jobsPerMinute, pausedMasters, periods, processes, queueWithMaxRuntime, queueWithMaxThroughput, recentJobs, status, wait }>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/system/getQueueWorkload` | `StandardSuccess<array>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/system/getQueueMasters` | 返回体由 Laravel Horizon 原生控制器决定;`reference/Xboard` 中未定义 | 无法仅凭仓库精确静态还原 |
|
||||
| `GET /api/v2/{admin_secure_path}/system/getHorizonFailedJobs` | `{"data":[...],"total":100,"current":1,"page_size":20}` | 非统一壳子 |
|
||||
| `ANY /api/v2/{admin_secure_path}/system/getAuditLog` | `{"data":[<AdminAuditLogModel>],"total":100}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/theme/getThemes` | `StandardSuccess<{ themes: string[], active: string }>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/theme/upload` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/theme/delete` | `StandardSuccess<true>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/theme/saveThemeConfig` | `StandardSuccess<object>` | `StandardFail` |
|
||||
| `POST /api/v2/{admin_secure_path}/theme/getThemeConfig` | `StandardSuccess<object>` | `StandardFail` |
|
||||
| `GET /api/v2/{admin_secure_path}/plugin/types` | `{"data":[{ value, label, description, icon }]}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/plugin/getPlugins` | `{"data":[{ code, name, version, description, author, type, is_installed, is_enabled, is_protected, can_be_deleted, config, readme, need_upgrade }]}` | 非统一壳子 |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/upload` | `{"message":"插件上传成功"}` | 失败时 `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/delete` | `{"message":"插件删除成功"}` | `400/403 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/install` | `{"message":"插件安装成功"}` | `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/uninstall` | `{"message":"插件卸载成功"}` | `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/enable` | `{"message":"插件启用成功"}` | `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/disable` | `{"message":"插件禁用成功"}` | 通常无统一失败壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/plugin/config` | `{"data": { ...plugin_config }}` | `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/config` | `{"message":"配置更新成功"}` | `400 {"message":"..."}` |
|
||||
| `POST /api/v2/{admin_secure_path}/plugin/upgrade` | `{"message":"插件升级成功"}` | `400 {"message":"..."}` |
|
||||
| `GET /api/v2/{admin_secure_path}/traffic-reset/logs` | `DataPagination<{ id, user_id, user_email, reset_type, reset_type_name, reset_time, old_traffic, new_traffic, trigger_source, trigger_source_name, metadata, created_at }>` | 校验失败时为框架校验 JSON |
|
||||
| `GET /api/v2/{admin_secure_path}/traffic-reset/stats` | `{"data": { total_resets, auto_resets, manual_resets, cron_resets }}` | 非统一壳子 |
|
||||
| `GET /api/v2/{admin_secure_path}/traffic-reset/user/{userId}/history` | `{"data": { user: { id, email, reset_count, last_reset_at, next_reset_at }, history: [{ id, reset_type, reset_type_name, reset_time, old_traffic, trigger_source, trigger_source_name, metadata }] }}` | 非统一壳子 |
|
||||
| `POST /api/v2/{admin_secure_path}/traffic-reset/reset-user` | `{"message":"...","data": { user_id, email, reset_time, next_reset_at }}` | 失败时 `400/500 {"message":"..."}` |
|
||||
|
||||
## 已知源码级异常点
|
||||
|
||||
| 接口 | 源码现状 | 影响 |
|
||||
| --- | --- | --- |
|
||||
| `/api/v1/user/knowledge/getCategory` | 路由存在,控制器无方法 | 实际调用大概率 500 |
|
||||
| `/api/v2/{admin_secure_path}/user/setInviteUser` | 路由存在,控制器无方法 | 实际调用大概率 500 |
|
||||
| `/api/v2/{admin_secure_path}/stat/getRanking` | 路由存在,控制器无方法 | 实际调用大概率 500 |
|
||||
| `/api/v2/{admin_secure_path}/notice/update` | 路由存在,控制器无方法 | 实际调用大概率 500 |
|
||||
| `/api/v2/{admin_secure_path}/coupon/update` | 成功路径没有显式 `return` | 可能返回 `200` 空响应体 |
|
||||
| `/api/v2/{admin_secure_path}/gift-card/templates` | 代码构造了映射后的 `$data`,但最终返回的是原始 paginator | 文档按“原始模型分页”处理 |
|
||||
| `/api/v2/{admin_secure_path}/gift-card/codes` | 同上 | 文档按“原始模型分页”处理 |
|
||||
| `/api/v2/{admin_secure_path}/system/getQueueMasters` | 指向 Horizon 外部控制器 | 仅能标记为“仓库外定义” |
|
||||
274
docs/api-list.md
Normal file
274
docs/api-list.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# Xboard API 清单
|
||||
|
||||
基于 `reference/Xboard` 中的路由定义与控制器源码静态整理。
|
||||
|
||||
说明:
|
||||
- `admin_secure_path` 表示后台安全路径,对应实际路由前缀 `/api/v2/{secure_path}`。
|
||||
- `subscribe_path` 表示订阅短链路径,对应实际路由前缀 `/{subscribe_path}/{token}`。
|
||||
- `ANY` 表示路由声明为 `any/match`,即接受多个 HTTP 方法。
|
||||
- “控制器缺失”表示路由已注册,但在 `reference/Xboard` 中未找到对应方法。
|
||||
|
||||
## V1 Guest
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v1/guest/plan/fetch` | 公开 | `V1\Guest\PlanController@fetch` | 获取可售套餐 |
|
||||
| POST | `/api/v1/guest/telegram/webhook` | 公开 | `V1\Guest\TelegramController@webhook` | Telegram Webhook |
|
||||
| GET/POST | `/api/v1/guest/payment/notify/{method}/{uuid}` | 公开 | `V1\Guest\PaymentController@notify` | 支付回调 |
|
||||
| GET | `/api/v1/guest/comm/config` | 公开 | `V1\Guest\CommController@config` | 前台公共配置 |
|
||||
|
||||
## V1 Passport
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| POST | `/api/v1/passport/auth/register` | 公开 | `V1\Passport\AuthController@register` | 注册 |
|
||||
| POST | `/api/v1/passport/auth/login` | 公开 | `V1\Passport\AuthController@login` | 登录 |
|
||||
| GET | `/api/v1/passport/auth/token2Login` | 公开 | `V1\Passport\AuthController@token2Login` | 邮件/Token 快登 |
|
||||
| POST | `/api/v1/passport/auth/forget` | 公开 | `V1\Passport\AuthController@forget` | 重置密码 |
|
||||
| POST | `/api/v1/passport/auth/getQuickLoginUrl` | 公开 | `V1\Passport\AuthController@getQuickLoginUrl` | 生成快登链接 |
|
||||
| POST | `/api/v1/passport/auth/loginWithMailLink` | 公开 | `V1\Passport\AuthController@loginWithMailLink` | 发送邮件登录链接 |
|
||||
| POST | `/api/v1/passport/comm/sendEmailVerify` | 公开 | `V1\Passport\CommController@sendEmailVerify` | 发送邮箱验证码 |
|
||||
| POST | `/api/v1/passport/comm/pv` | 公开 | `V1\Passport\CommController@pv` | 邀请码访问计数 |
|
||||
|
||||
## V1 User
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v1/user/resetSecurity` | `user` | `V1\User\UserController@resetSecurity` | 重置订阅密钥 |
|
||||
| GET | `/api/v1/user/info` | `user` | `V1\User\UserController@info` | 当前用户概要 |
|
||||
| POST | `/api/v1/user/changePassword` | `user` | `V1\User\UserController@changePassword` | 修改密码 |
|
||||
| POST | `/api/v1/user/update` | `user` | `V1\User\UserController@update` | 更新提醒设置 |
|
||||
| GET | `/api/v1/user/getSubscribe` | `user` | `V1\User\UserController@getSubscribe` | 订阅信息 |
|
||||
| GET | `/api/v1/user/getStat` | `user` | `V1\User\UserController@getStat` | 用户统计 |
|
||||
| GET | `/api/v1/user/checkLogin` | `user` | `V1\User\UserController@checkLogin` | 登录态检查 |
|
||||
| POST | `/api/v1/user/transfer` | `user` | `V1\User\UserController@transfer` | 佣金转余额 |
|
||||
| POST | `/api/v1/user/getQuickLoginUrl` | `user` | `V1\User\UserController@getQuickLoginUrl` | 生成快登链接 |
|
||||
| GET | `/api/v1/user/getActiveSession` | `user` | `V1\User\UserController@getActiveSession` | 获取活跃会话 |
|
||||
| POST | `/api/v1/user/removeActiveSession` | `user` | `V1\User\UserController@removeActiveSession` | 删除活跃会话 |
|
||||
| POST | `/api/v1/user/order/save` | `user` | `V1\User\OrderController@save` | 创建订单 |
|
||||
| POST | `/api/v1/user/order/checkout` | `user` | `V1\User\OrderController@checkout` | 订单支付 |
|
||||
| GET | `/api/v1/user/order/check` | `user` | `V1\User\OrderController@check` | 查询订单状态 |
|
||||
| GET | `/api/v1/user/order/detail` | `user` | `V1\User\OrderController@detail` | 订单详情 |
|
||||
| GET | `/api/v1/user/order/fetch` | `user` | `V1\User\OrderController@fetch` | 订单列表 |
|
||||
| GET | `/api/v1/user/order/getPaymentMethod` | `user` | `V1\User\OrderController@getPaymentMethod` | 支付方式列表 |
|
||||
| POST | `/api/v1/user/order/cancel` | `user` | `V1\User\OrderController@cancel` | 取消订单 |
|
||||
| GET | `/api/v1/user/plan/fetch` | `user` | `V1\User\PlanController@fetch` | 套餐列表/详情 |
|
||||
| GET | `/api/v1/user/invite/save` | `user` | `V1\User\InviteController@save` | 创建邀请码 |
|
||||
| GET | `/api/v1/user/invite/fetch` | `user` | `V1\User\InviteController@fetch` | 邀请概览 |
|
||||
| GET | `/api/v1/user/invite/details` | `user` | `V1\User\InviteController@details` | 邀请返佣明细 |
|
||||
| GET | `/api/v1/user/notice/fetch` | `user` | `V1\User\NoticeController@fetch` | 公告列表 |
|
||||
| POST | `/api/v1/user/ticket/reply` | `user` | `V1\User\TicketController@reply` | 回复工单 |
|
||||
| POST | `/api/v1/user/ticket/close` | `user` | `V1\User\TicketController@close` | 关闭工单 |
|
||||
| POST | `/api/v1/user/ticket/save` | `user` | `V1\User\TicketController@save` | 创建工单 |
|
||||
| GET | `/api/v1/user/ticket/fetch` | `user` | `V1\User\TicketController@fetch` | 工单列表/详情 |
|
||||
| POST | `/api/v1/user/ticket/withdraw` | `user` | `V1\User\TicketController@withdraw` | 佣金提现工单 |
|
||||
| GET | `/api/v1/user/server/fetch` | `user` | `V1\User\ServerController@fetch` | 可用节点列表 |
|
||||
| POST | `/api/v1/user/coupon/check` | `user` | `V1\User\CouponController@check` | 校验优惠券 |
|
||||
| POST | `/api/v1/user/gift-card/check` | `user` | `V1\User\GiftCardController@check` | 预检礼品卡 |
|
||||
| POST | `/api/v1/user/gift-card/redeem` | `user` | `V1\User\GiftCardController@redeem` | 兑换礼品卡 |
|
||||
| GET | `/api/v1/user/gift-card/history` | `user` | `V1\User\GiftCardController@history` | 礼品卡使用历史 |
|
||||
| GET | `/api/v1/user/gift-card/detail` | `user` | `V1\User\GiftCardController@detail` | 礼品卡记录详情 |
|
||||
| GET | `/api/v1/user/gift-card/types` | `user` | `V1\User\GiftCardController@types` | 礼品卡类型映射 |
|
||||
| GET | `/api/v1/user/telegram/getBotInfo` | `user` | `V1\User\TelegramController@getBotInfo` | Telegram Bot 信息 |
|
||||
| GET | `/api/v1/user/comm/config` | `user` | `V1\User\CommController@config` | 用户公共配置 |
|
||||
| POST | `/api/v1/user/comm/getStripePublicKey` | `user` | `V1\User\CommController@getStripePublicKey` | Stripe 公钥 |
|
||||
| GET | `/api/v1/user/knowledge/fetch` | `user` | `V1\User\KnowledgeController@fetch` | 知识库列表/详情 |
|
||||
| GET | `/api/v1/user/knowledge/getCategory` | `user` | `V1\User\KnowledgeController@getCategory` | 路由已注册,但控制器缺失 |
|
||||
| GET | `/api/v1/user/stat/getTrafficLog` | `user` | `V1\User\StatController@getTrafficLog` | 流量日志 |
|
||||
|
||||
## V1 Server
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v1/server/UniProxy/config` | `server` | `V1\Server\UniProxyController@config` | 节点配置 |
|
||||
| GET | `/api/v1/server/UniProxy/user` | `server` | `V1\Server\UniProxyController@user` | 节点用户列表 |
|
||||
| POST | `/api/v1/server/UniProxy/push` | `server` | `V1\Server\UniProxyController@push` | 上报流量 |
|
||||
| POST | `/api/v1/server/UniProxy/alive` | `server` | `V1\Server\UniProxyController@alive` | 上报在线设备 |
|
||||
| GET | `/api/v1/server/UniProxy/alivelist` | `server` | `V1\Server\UniProxyController@alivelist` | 获取在线设备 |
|
||||
| POST | `/api/v1/server/UniProxy/status` | `server` | `V1\Server\UniProxyController@status` | 上报负载状态 |
|
||||
| GET | `/api/v1/server/ShadowsocksTidalab/user` | `server:shadowsocks` | `V1\Server\ShadowsocksTidalabController@user` | Shadowsocks 用户 |
|
||||
| POST | `/api/v1/server/ShadowsocksTidalab/submit` | `server:shadowsocks` | `V1\Server\ShadowsocksTidalabController@submit` | Shadowsocks 流量上报 |
|
||||
| GET | `/api/v1/server/TrojanTidalab/config` | `server:trojan` | `V1\Server\TrojanTidalabController@config` | Trojan 配置 |
|
||||
| GET | `/api/v1/server/TrojanTidalab/user` | `server:trojan` | `V1\Server\TrojanTidalabController@user` | Trojan 用户 |
|
||||
| POST | `/api/v1/server/TrojanTidalab/submit` | `server:trojan` | `V1\Server\TrojanTidalabController@submit` | Trojan 流量上报 |
|
||||
|
||||
## V1 Client
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v1/client/subscribe` | `client` | `V1\Client\ClientController@subscribe` | 旧版订阅入口 |
|
||||
| GET | `/api/v1/client/app/getConfig` | `client` | `V1\Client\AppController@getConfig` | Clash YAML 配置 |
|
||||
| GET | `/api/v1/client/app/getVersion` | `client` | `V1\Client\AppController@getVersion` | 客户端版本信息 |
|
||||
| GET | `/{subscribe_path}/{token}` | `client` | `V1\Client\ClientController@subscribe` | 短链订阅入口 |
|
||||
|
||||
## V2 Passport
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| POST | `/api/v2/passport/auth/register` | 公开 | `V1\Passport\AuthController@register` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/auth/login` | 公开 | `V1\Passport\AuthController@login` | 与 V1 相同 |
|
||||
| GET | `/api/v2/passport/auth/token2Login` | 公开 | `V1\Passport\AuthController@token2Login` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/auth/forget` | 公开 | `V1\Passport\AuthController@forget` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/auth/getQuickLoginUrl` | 公开 | `V1\Passport\AuthController@getQuickLoginUrl` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/auth/loginWithMailLink` | 公开 | `V1\Passport\AuthController@loginWithMailLink` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/comm/sendEmailVerify` | 公开 | `V1\Passport\CommController@sendEmailVerify` | 与 V1 相同 |
|
||||
| POST | `/api/v2/passport/comm/pv` | 公开 | `V1\Passport\CommController@pv` | 与 V1 相同 |
|
||||
|
||||
## V2 User / Client / Server
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v2/user/resetSecurity` | `user` | `V1\User\UserController@resetSecurity` | 与 V1 相同 |
|
||||
| GET | `/api/v2/user/info` | `user` | `V1\User\UserController@info` | 与 V1 相同 |
|
||||
| GET | `/api/v2/client/app/getConfig` | `client` | `V2\Client\AppController@getConfig` | 新客户端配置 JSON |
|
||||
| GET | `/api/v2/client/app/getVersion` | `client` | `V2\Client\AppController@getVersion` | 与 V1 相同 |
|
||||
| POST | `/api/v2/server/handshake` | `server` | `V2\Server\ServerController@handshake` | 节点握手 |
|
||||
| POST | `/api/v2/server/report` | `server` | `V2\Server\ServerController@report` | 合并上报 |
|
||||
| GET | `/api/v2/server/config` | `server` | `V1\Server\UniProxyController@config` | 与 V1 UniProxy 相同 |
|
||||
| GET | `/api/v2/server/user` | `server` | `V1\Server\UniProxyController@user` | 与 V1 UniProxy 相同 |
|
||||
| POST | `/api/v2/server/push` | `server` | `V1\Server\UniProxyController@push` | 与 V1 UniProxy 相同 |
|
||||
| POST | `/api/v2/server/alive` | `server` | `V1\Server\UniProxyController@alive` | 与 V1 UniProxy 相同 |
|
||||
| GET | `/api/v2/server/alivelist` | `server` | `V1\Server\UniProxyController@alivelist` | 与 V1 UniProxy 相同 |
|
||||
| POST | `/api/v2/server/status` | `server` | `V1\Server\UniProxyController@status` | 与 V1 UniProxy 相同 |
|
||||
|
||||
## V2 Admin - Config / Plan / Server
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v2/{admin_secure_path}/config/fetch` | `admin` | `V2\Admin\ConfigController@fetch` | 后台配置 |
|
||||
| POST | `/api/v2/{admin_secure_path}/config/save` | `admin` | `V2\Admin\ConfigController@save` | 保存配置 |
|
||||
| GET | `/api/v2/{admin_secure_path}/config/getEmailTemplate` | `admin` | `V2\Admin\ConfigController@getEmailTemplate` | 邮件模板目录 |
|
||||
| GET | `/api/v2/{admin_secure_path}/config/getThemeTemplate` | `admin` | `V2\Admin\ConfigController@getThemeTemplate` | 主题目录 |
|
||||
| POST | `/api/v2/{admin_secure_path}/config/setTelegramWebhook` | `admin` | `V2\Admin\ConfigController@setTelegramWebhook` | 设置 Telegram Webhook |
|
||||
| POST | `/api/v2/{admin_secure_path}/config/testSendMail` | `admin` | `V2\Admin\ConfigController@testSendMail` | 测试发信 |
|
||||
| GET | `/api/v2/{admin_secure_path}/plan/fetch` | `admin` | `V2\Admin\PlanController@fetch` | 套餐列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plan/save` | `admin` | `V2\Admin\PlanController@save` | 创建/更新套餐 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plan/drop` | `admin` | `V2\Admin\PlanController@drop` | 删除套餐 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plan/update` | `admin` | `V2\Admin\PlanController@update` | 更新开关字段 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plan/sort` | `admin` | `V2\Admin\PlanController@sort` | 套餐排序 |
|
||||
| GET | `/api/v2/{admin_secure_path}/server/group/fetch` | `admin` | `V2\Admin\Server\GroupController@fetch` | 节点分组列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/group/save` | `admin` | `V2\Admin\Server\GroupController@save` | 创建/更新分组 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/group/drop` | `admin` | `V2\Admin\Server\GroupController@drop` | 删除分组 |
|
||||
| GET | `/api/v2/{admin_secure_path}/server/route/fetch` | `admin` | `V2\Admin\Server\RouteController@fetch` | 路由规则列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/route/save` | `admin` | `V2\Admin\Server\RouteController@save` | 创建/更新路由规则 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/route/drop` | `admin` | `V2\Admin\Server\RouteController@drop` | 删除路由规则 |
|
||||
| GET | `/api/v2/{admin_secure_path}/server/manage/getNodes` | `admin` | `V2\Admin\Server\ManageController@getNodes` | 节点列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/sort` | `admin` | `V2\Admin\Server\ManageController@sort` | 节点排序 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/update` | `admin` | `V2\Admin\Server\ManageController@update` | 节点开关 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/save` | `admin` | `V2\Admin\Server\ManageController@save` | 创建/更新节点 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/drop` | `admin` | `V2\Admin\Server\ManageController@drop` | 删除节点 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/copy` | `admin` | `V2\Admin\Server\ManageController@copy` | 复制节点 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/batchDelete` | `admin` | `V2\Admin\Server\ManageController@batchDelete` | 批量删除节点 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/resetTraffic` | `admin` | `V2\Admin\Server\ManageController@resetTraffic` | 重置单节点流量 |
|
||||
| POST | `/api/v2/{admin_secure_path}/server/manage/batchResetTraffic` | `admin` | `V2\Admin\Server\ManageController@batchResetTraffic` | 批量重置节点流量 |
|
||||
|
||||
## V2 Admin - Order / User / Stat
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ANY | `/api/v2/{admin_secure_path}/order/fetch` | `admin` | `V2\Admin\OrderController@fetch` | 订单分页列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/order/update` | `admin` | `V2\Admin\OrderController@update` | 更新订单佣金状态 |
|
||||
| POST | `/api/v2/{admin_secure_path}/order/assign` | `admin` | `V2\Admin\OrderController@assign` | 指派订单 |
|
||||
| POST | `/api/v2/{admin_secure_path}/order/paid` | `admin` | `V2\Admin\OrderController@paid` | 手动标记已支付 |
|
||||
| POST | `/api/v2/{admin_secure_path}/order/cancel` | `admin` | `V2\Admin\OrderController@cancel` | 取消订单 |
|
||||
| POST | `/api/v2/{admin_secure_path}/order/detail` | `admin` | `V2\Admin\OrderController@detail` | 订单详情 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/user/fetch` | `admin` | `V2\Admin\UserController@fetch` | 用户分页列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/update` | `admin` | `V2\Admin\UserController@update` | 更新用户 |
|
||||
| GET | `/api/v2/{admin_secure_path}/user/getUserInfoById` | `admin` | `V2\Admin\UserController@getUserInfoById` | 用户详情 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/generate` | `admin` | `V2\Admin\UserController@generate` | 生成用户 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/dumpCSV` | `admin` | `V2\Admin\UserController@dumpCSV` | 导出 CSV |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/sendMail` | `admin` | `V2\Admin\UserController@sendMail` | 批量发信 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/ban` | `admin` | `V2\Admin\UserController@ban` | 批量封禁 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/resetSecret` | `admin` | `V2\Admin\UserController@resetSecret` | 重置用户订阅密钥 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/setInviteUser` | `admin` | `V2\Admin\UserController@setInviteUser` | 路由已注册,但控制器缺失 |
|
||||
| POST | `/api/v2/{admin_secure_path}/user/destroy` | `admin` | `V2\Admin\UserController@destroy` | 删除用户 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getOverride` | `admin` | `V2\Admin\StatController@getOverride` | 概览统计 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getStats` | `admin` | `V2\Admin\StatController@getStats` | 综合统计 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getServerLastRank` | `admin` | `V2\Admin\StatController@getServerLastRank` | 当日节点排行 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getServerYesterdayRank` | `admin` | `V2\Admin\StatController@getServerYesterdayRank` | 昨日节点排行 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getOrder` | `admin` | `V2\Admin\StatController@getOrder` | 订单统计 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/stat/getStatUser` | `admin` | `V2\Admin\StatController@getStatUser` | 用户统计明细 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getRanking` | `admin` | `V2\Admin\StatController@getRanking` | 路由已注册,但控制器缺失 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getStatRecord` | `admin` | `V2\Admin\StatController@getStatRecord` | 统计记录 |
|
||||
| GET | `/api/v2/{admin_secure_path}/stat/getTrafficRank` | `admin` | `V2\Admin\StatController@getTrafficRank` | 流量排行 |
|
||||
|
||||
## V2 Admin - Notice / Ticket / Coupon / Knowledge
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v2/{admin_secure_path}/notice/fetch` | `admin` | `V2\Admin\NoticeController@fetch` | 公告列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/notice/save` | `admin` | `V2\Admin\NoticeController@save` | 创建/更新公告 |
|
||||
| POST | `/api/v2/{admin_secure_path}/notice/update` | `admin` | `V2\Admin\NoticeController@update` | 路由已注册,但控制器缺失 |
|
||||
| POST | `/api/v2/{admin_secure_path}/notice/drop` | `admin` | `V2\Admin\NoticeController@drop` | 删除公告 |
|
||||
| POST | `/api/v2/{admin_secure_path}/notice/show` | `admin` | `V2\Admin\NoticeController@show` | 切换显示状态 |
|
||||
| POST | `/api/v2/{admin_secure_path}/notice/sort` | `admin` | `V2\Admin\NoticeController@sort` | 公告排序 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/ticket/fetch` | `admin` | `V2\Admin\TicketController@fetch` | 工单分页/详情 |
|
||||
| POST | `/api/v2/{admin_secure_path}/ticket/reply` | `admin` | `V2\Admin\TicketController@reply` | 回复工单 |
|
||||
| POST | `/api/v2/{admin_secure_path}/ticket/close` | `admin` | `V2\Admin\TicketController@close` | 关闭工单 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/coupon/fetch` | `admin` | `V2\Admin\CouponController@fetch` | 优惠券分页列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/coupon/generate` | `admin` | `V2\Admin\CouponController@generate` | 创建/批量生成优惠券 |
|
||||
| POST | `/api/v2/{admin_secure_path}/coupon/drop` | `admin` | `V2\Admin\CouponController@drop` | 删除优惠券 |
|
||||
| POST | `/api/v2/{admin_secure_path}/coupon/show` | `admin` | `V2\Admin\CouponController@show` | 切换显示状态 |
|
||||
| POST | `/api/v2/{admin_secure_path}/coupon/update` | `admin` | `V2\Admin\CouponController@update` | 源码成功路径未显式返回 |
|
||||
| GET | `/api/v2/{admin_secure_path}/knowledge/fetch` | `admin` | `V2\Admin\KnowledgeController@fetch` | 知识库列表/详情 |
|
||||
| GET | `/api/v2/{admin_secure_path}/knowledge/getCategory` | `admin` | `V2\Admin\KnowledgeController@getCategory` | 分类列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/knowledge/save` | `admin` | `V2\Admin\KnowledgeController@save` | 创建/更新知识库 |
|
||||
| POST | `/api/v2/{admin_secure_path}/knowledge/show` | `admin` | `V2\Admin\KnowledgeController@show` | 切换显示状态 |
|
||||
| POST | `/api/v2/{admin_secure_path}/knowledge/drop` | `admin` | `V2\Admin\KnowledgeController@drop` | 删除知识库 |
|
||||
| POST | `/api/v2/{admin_secure_path}/knowledge/sort` | `admin` | `V2\Admin\KnowledgeController@sort` | 排序 |
|
||||
|
||||
## V2 Admin - Gift Card / Payment
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| ANY | `/api/v2/{admin_secure_path}/gift-card/templates` | `admin` | `V2\Admin\GiftCardController@templates` | 模板分页列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/create-template` | `admin` | `V2\Admin\GiftCardController@createTemplate` | 创建模板 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/update-template` | `admin` | `V2\Admin\GiftCardController@updateTemplate` | 更新模板 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/delete-template` | `admin` | `V2\Admin\GiftCardController@deleteTemplate` | 删除模板 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/generate-codes` | `admin` | `V2\Admin\GiftCardController@generateCodes` | 批量生成兑换码 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/gift-card/codes` | `admin` | `V2\Admin\GiftCardController@codes` | 兑换码分页列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/toggle-code` | `admin` | `V2\Admin\GiftCardController@toggleCode` | 启用/禁用兑换码 |
|
||||
| GET | `/api/v2/{admin_secure_path}/gift-card/export-codes` | `admin` | `V2\Admin\GiftCardController@exportCodes` | 导出兑换码文本 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/update-code` | `admin` | `V2\Admin\GiftCardController@updateCode` | 更新兑换码 |
|
||||
| POST | `/api/v2/{admin_secure_path}/gift-card/delete-code` | `admin` | `V2\Admin\GiftCardController@deleteCode` | 删除兑换码 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/gift-card/usages` | `admin` | `V2\Admin\GiftCardController@usages` | 使用记录分页列表 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/gift-card/statistics` | `admin` | `V2\Admin\GiftCardController@statistics` | 礼品卡统计 |
|
||||
| GET | `/api/v2/{admin_secure_path}/gift-card/types` | `admin` | `V2\Admin\GiftCardController@types` | 礼品卡类型映射 |
|
||||
| GET | `/api/v2/{admin_secure_path}/payment/fetch` | `admin` | `V2\Admin\PaymentController@fetch` | 支付方式列表 |
|
||||
| GET | `/api/v2/{admin_secure_path}/payment/getPaymentMethods` | `admin` | `V2\Admin\PaymentController@getPaymentMethods` | 支付插件类型 |
|
||||
| POST | `/api/v2/{admin_secure_path}/payment/getPaymentForm` | `admin` | `V2\Admin\PaymentController@getPaymentForm` | 支付表单定义 |
|
||||
| POST | `/api/v2/{admin_secure_path}/payment/save` | `admin` | `V2\Admin\PaymentController@save` | 创建/更新支付方式 |
|
||||
| POST | `/api/v2/{admin_secure_path}/payment/drop` | `admin` | `V2\Admin\PaymentController@drop` | 删除支付方式 |
|
||||
| POST | `/api/v2/{admin_secure_path}/payment/show` | `admin` | `V2\Admin\PaymentController@show` | 切换支付方式状态 |
|
||||
| POST | `/api/v2/{admin_secure_path}/payment/sort` | `admin` | `V2\Admin\PaymentController@sort` | 排序 |
|
||||
|
||||
## V2 Admin - System / Theme / Plugin / Traffic Reset
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 控制器 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| GET | `/api/v2/{admin_secure_path}/system/getSystemStatus` | `admin` | `V2\Admin\SystemController@getSystemStatus` | 系统状态 |
|
||||
| GET | `/api/v2/{admin_secure_path}/system/getQueueStats` | `admin` | `V2\Admin\SystemController@getQueueStats` | Horizon 队列统计 |
|
||||
| GET | `/api/v2/{admin_secure_path}/system/getQueueWorkload` | `admin` | `V2\Admin\SystemController@getQueueWorkload` | 队列负载 |
|
||||
| GET | `/api/v2/{admin_secure_path}/system/getQueueMasters` | `admin` | `Laravel\Horizon\Http\Controllers\MasterSupervisorController@index` | 外部 Horizon 控制器 |
|
||||
| GET | `/api/v2/{admin_secure_path}/system/getHorizonFailedJobs` | `admin` | `V2\Admin\SystemController@getHorizonFailedJobs` | Horizon 失败任务分页 |
|
||||
| ANY | `/api/v2/{admin_secure_path}/system/getAuditLog` | `admin` | `V2\Admin\SystemController@getAuditLog` | 后台审计日志 |
|
||||
| GET | `/api/v2/{admin_secure_path}/theme/getThemes` | `admin` | `V2\Admin\ThemeController@getThemes` | 主题列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/theme/upload` | `admin` | `V2\Admin\ThemeController@upload` | 上传主题 |
|
||||
| POST | `/api/v2/{admin_secure_path}/theme/delete` | `admin` | `V2\Admin\ThemeController@delete` | 删除主题 |
|
||||
| POST | `/api/v2/{admin_secure_path}/theme/saveThemeConfig` | `admin` | `V2\Admin\ThemeController@saveThemeConfig` | 保存主题配置 |
|
||||
| POST | `/api/v2/{admin_secure_path}/theme/getThemeConfig` | `admin` | `V2\Admin\ThemeController@getThemeConfig` | 获取主题配置 |
|
||||
| GET | `/api/v2/{admin_secure_path}/plugin/types` | `admin` | `V2\Admin\PluginController@types` | 插件类型 |
|
||||
| GET | `/api/v2/{admin_secure_path}/plugin/getPlugins` | `admin` | `V2\Admin\PluginController@index` | 插件列表 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/upload` | `admin` | `V2\Admin\PluginController@upload` | 上传插件 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/delete` | `admin` | `V2\Admin\PluginController@delete` | 删除插件 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/install` | `admin` | `V2\Admin\PluginController@install` | 安装插件 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/uninstall` | `admin` | `V2\Admin\PluginController@uninstall` | 卸载插件 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/enable` | `admin` | `V2\Admin\PluginController@enable` | 启用插件 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/disable` | `admin` | `V2\Admin\PluginController@disable` | 禁用插件 |
|
||||
| GET | `/api/v2/{admin_secure_path}/plugin/config` | `admin` | `V2\Admin\PluginController@getConfig` | 插件配置 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/config` | `admin` | `V2\Admin\PluginController@updateConfig` | 更新插件配置 |
|
||||
| POST | `/api/v2/{admin_secure_path}/plugin/upgrade` | `admin` | `V2\Admin\PluginController@upgrade` | 升级插件 |
|
||||
| GET | `/api/v2/{admin_secure_path}/traffic-reset/logs` | `admin` | `V2\Admin\TrafficResetController@logs` | 流量重置日志 |
|
||||
| GET | `/api/v2/{admin_secure_path}/traffic-reset/stats` | `admin` | `V2\Admin\TrafficResetController@stats` | 流量重置统计 |
|
||||
| GET | `/api/v2/{admin_secure_path}/traffic-reset/user/{userId}/history` | `admin` | `V2\Admin\TrafficResetController@userHistory` | 用户流量重置历史 |
|
||||
| POST | `/api/v2/{admin_secure_path}/traffic-reset/reset-user` | `admin` | `V2\Admin\TrafficResetController@resetUser` | 手动重置用户流量 |
|
||||
@@ -270090,7 +270090,8 @@ function bGt() {
|
||||
children: e("site.form.saving"),
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
type: "submit",
|
||||
type: "button",
|
||||
onClick: l,
|
||||
loading: t,
|
||||
children: e("common.save", "保存"),
|
||||
}),
|
||||
@@ -270799,7 +270800,8 @@ function CGt() {
|
||||
children: e("safe.form.saving"),
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
type: "submit",
|
||||
type: "button",
|
||||
onClick: o,
|
||||
loading: t,
|
||||
children: e("common.save", "Save"),
|
||||
}),
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"beautify": "node scripts/beautify-bundle.cjs",
|
||||
"inspect": "node scripts/inspect-bundle.cjs"
|
||||
"inspect": "node scripts/inspect-bundle.cjs",
|
||||
"normalize": "node scripts/normalize-bundle.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.27.5",
|
||||
|
||||
90
frontend/admin/reverse/scripts/normalize-bundle.cjs
Normal file
90
frontend/admin/reverse/scripts/normalize-bundle.cjs
Normal file
@@ -0,0 +1,90 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const parser = require("@babel/parser");
|
||||
const traverse = require("@babel/traverse").default;
|
||||
const generate = require("@babel/generator").default;
|
||||
const t = require("@babel/types");
|
||||
const prettier = require("prettier");
|
||||
|
||||
const projectRoot = path.resolve(__dirname, "..", "..");
|
||||
const outputRoot = path.resolve(__dirname, "..", "output");
|
||||
const inputPath = path.join(outputRoot, "index-CO3BwsT2.pretty.js");
|
||||
const outputPath = path.join(outputRoot, "index-CO3BwsT2.normalized.js");
|
||||
|
||||
async function main() {
|
||||
console.log("Reading file...");
|
||||
const source = fs.readFileSync(inputPath, "utf8");
|
||||
|
||||
console.log("Parsing AST...");
|
||||
const ast = parser.parse(source, {
|
||||
sourceType: "module",
|
||||
plugins: ["jsx"],
|
||||
});
|
||||
|
||||
console.log("Normalizing patterns...");
|
||||
traverse(ast, {
|
||||
// Convert !0 -> true, !1 -> false
|
||||
UnaryExpression(path) {
|
||||
if (path.node.operator === "!" && path.node.argument.type === "NumericLiteral") {
|
||||
if (path.node.argument.value === 0) {
|
||||
path.replaceWith(t.booleanLiteral(true));
|
||||
} else if (path.node.argument.value === 1) {
|
||||
path.replaceWith(t.booleanLiteral(false));
|
||||
}
|
||||
}
|
||||
// Convert void 0 -> undefined
|
||||
if (path.node.operator === "void" && path.node.argument.type === "NumericLiteral" && path.node.argument.value === 0) {
|
||||
path.replaceWith(t.identifier("undefined"));
|
||||
}
|
||||
},
|
||||
// Simplify numeric literals (e.g., 1e3 -> 1000)
|
||||
NumericLiteral(path) {
|
||||
if (path.node.extra && path.node.extra.raw && path.node.extra.raw.includes('e')) {
|
||||
delete path.node.extra;
|
||||
}
|
||||
},
|
||||
// identified React Hook aliasing (heuristic)
|
||||
VariableDeclarator(path) {
|
||||
// Look for: const t = n.useState;
|
||||
if (
|
||||
path.node.init &&
|
||||
path.node.init.type === "MemberExpression" &&
|
||||
path.node.init.property.type === "Identifier" &&
|
||||
path.node.init.property.name.startsWith("use") &&
|
||||
path.node.id.type === "Identifier" &&
|
||||
path.node.id.name.length <= 2 // minified name
|
||||
) {
|
||||
const hookName = path.node.init.property.name;
|
||||
const oldName = path.node.id.name;
|
||||
const scope = path.scope;
|
||||
|
||||
// Rename oldName to hookName in this scope
|
||||
// scope.rename(oldName, hookName); // Dangerous if hookName is already in use
|
||||
// For now, let's just log it or be very careful
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Generating code...");
|
||||
const { code } = generate(ast, {
|
||||
retainLines: true,
|
||||
compact: false,
|
||||
});
|
||||
|
||||
console.log("Formatting with Prettier...");
|
||||
const formatted = await prettier.format(code, {
|
||||
parser: "babel",
|
||||
printWidth: 100,
|
||||
trailingComma: "all",
|
||||
singleQuote: false,
|
||||
});
|
||||
|
||||
console.log(`Writing output to ${outputPath}...`);
|
||||
fs.writeFileSync(outputPath, formatted, "utf8");
|
||||
console.log("Normalization complete!");
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
const theme = window.NEBULA_THEME || {};
|
||||
const app = document.getElementById('app');
|
||||
const loader = document.getElementById('nebula-loader');
|
||||
let loader = document.getElementById('nebula-loader');
|
||||
const themeMediaQuery = getThemeMediaQuery();
|
||||
|
||||
if (!app) {
|
||||
@@ -73,7 +73,7 @@
|
||||
}
|
||||
|
||||
if (state.authToken) {
|
||||
var loaded = await loadDashboard();
|
||||
const loaded = await loadDashboard();
|
||||
if (!loaded) {
|
||||
state.loading = false;
|
||||
}
|
||||
@@ -652,40 +652,64 @@
|
||||
|
||||
function findNodeLinkByName(links, name) {
|
||||
if (!name) return null;
|
||||
var target = name.trim();
|
||||
const target = name.trim();
|
||||
const targetLower = target.toLowerCase();
|
||||
|
||||
console.log("Nebula: Searching for node '" + name + "' among " + links.length + " links (Strict Match)");
|
||||
console.log('Nebula: Searching for node \'' + name + '\' among ' + links.length + ' links');
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var link = links[i].trim();
|
||||
var remark = "";
|
||||
let fuzzyMatch = null;
|
||||
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
const link = links[i].trim();
|
||||
let remark = '';
|
||||
|
||||
if (link.indexOf("#") !== -1) {
|
||||
var parts = link.split("#");
|
||||
var rawRemark = parts[parts.length - 1];
|
||||
if (link.indexOf('#') !== -1) {
|
||||
const parts = link.split('#');
|
||||
const rawRemark = parts[parts.length - 1];
|
||||
try {
|
||||
remark = decodeURIComponent(rawRemark.replace(/\+/g, "%20"));
|
||||
remark = decodeURIComponent(rawRemark.replace(/\+/g, '%20'));
|
||||
} catch (e) {
|
||||
remark = rawRemark;
|
||||
}
|
||||
} else if (link.indexOf("vmess://") === 0) {
|
||||
} else if (link.indexOf('vmess://') === 0) {
|
||||
try {
|
||||
var jsonStr = utf8Base64Decode(link.slice(8));
|
||||
var json = JSON.parse(jsonStr);
|
||||
remark = json.ps || "";
|
||||
const jsonStr = utf8Base64Decode(link.slice(8));
|
||||
const json = JSON.parse(jsonStr);
|
||||
remark = json.ps || '';
|
||||
} catch (e) {}
|
||||
} else if (link.indexOf("name:") !== -1) {
|
||||
var yamlMatch = link.match(/name:\s*["']?([^"']+)["']?/);
|
||||
} else if (link.indexOf('name:') !== -1) {
|
||||
const yamlMatch = link.match(/name:\s*["']?([^"']+)["']?/);
|
||||
if (yamlMatch) remark = yamlMatch[1];
|
||||
}
|
||||
|
||||
// Strict exact match after trimming
|
||||
if ((remark || "").trim() === target) {
|
||||
const normalizedRemark = (remark || '').trim();
|
||||
const normalizedLower = normalizedRemark.toLowerCase();
|
||||
|
||||
// Exact match
|
||||
if (normalizedRemark === target) {
|
||||
return link;
|
||||
}
|
||||
|
||||
// Case-insensitive match as candidate
|
||||
if (!fuzzyMatch && normalizedLower === targetLower) {
|
||||
fuzzyMatch = link;
|
||||
}
|
||||
|
||||
// If one contains the other (very common with emojis or plan prefixes)
|
||||
if (!fuzzyMatch && (normalizedLower.indexOf(targetLower) !== -1 || targetLower.indexOf(normalizedLower) !== -1)) {
|
||||
// Only use this if it's a "strong" enough match (at least 50% length overlap)
|
||||
if (Math.abs(normalizedLower.length - targetLower.length) < Math.max(normalizedLower.length, targetLower.length) * 0.4) {
|
||||
fuzzyMatch = link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.warn("Nebula: No exact match found for node '" + name + "'");
|
||||
if (fuzzyMatch) {
|
||||
console.log('Nebula: Using fuzzy match for node \'' + name + '\'');
|
||||
return fuzzyMatch;
|
||||
}
|
||||
|
||||
console.warn('Nebula: No match found for node \'' + name + '\'');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2635,13 +2659,42 @@
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
navigator.clipboard.writeText(value).then(function () {
|
||||
showMessage(successMessage || "内容已复制到剪贴板", "success");
|
||||
|
||||
const resolve = () => {
|
||||
showMessage(successMessage || '内容已复制到剪贴板', 'success');
|
||||
render();
|
||||
}).catch(function () {
|
||||
showMessage("复制失败,请尝试手动复制", "error");
|
||||
};
|
||||
|
||||
const reject = () => {
|
||||
showMessage('复制失败,请尝试手动复制', 'error');
|
||||
render();
|
||||
});
|
||||
};
|
||||
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(value).then(resolve).catch(reject);
|
||||
} else {
|
||||
// Fallback for non-secure contexts or unsupported browsers
|
||||
try {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = value;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-9999px';
|
||||
textArea.style.top = '0';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
const successful = document.execCommand('copy');
|
||||
document.body.removeChild(textArea);
|
||||
if (successful) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Fallback copy failed', err);
|
||||
reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatTraffic(value) {
|
||||
|
||||
Reference in New Issue
Block a user