From 33f3b37be06ab1a7914dcf2fed0d34ef375bfd38 Mon Sep 17 00:00:00 2001 From: luo Date: Mon, 26 Oct 2026 14:24:59 +0800 Subject: [PATCH] fix: some --- components/UserInfoCard.vue | 4 +- ...6-轮询按运营商账户限流-前端接口变更说明.md | 1754 +++++++++++++++++ 2 files changed, 1756 insertions(+), 2 deletions(-) create mode 100644 docs/2026-10-26-轮询按运营商账户限流-前端接口变更说明.md diff --git a/components/UserInfoCard.vue b/components/UserInfoCard.vue index d9ccb0a..2853c66 100644 --- a/components/UserInfoCard.vue +++ b/components/UserInfoCard.vue @@ -23,8 +23,8 @@ {{ networkStatus == 1 ? '正常' : '停机' }} - 立即续费 + diff --git a/docs/2026-10-26-轮询按运营商账户限流-前端接口变更说明.md b/docs/2026-10-26-轮询按运营商账户限流-前端接口变更说明.md new file mode 100644 index 0000000..ad376ce --- /dev/null +++ b/docs/2026-10-26-轮询按运营商账户限流-前端接口变更说明.md @@ -0,0 +1,1754 @@ +# 轮询按运营商账户限流:前端接口变更说明 + +更新日期:2026-10-26 +适用分支:`Iteration/8-11`(测试环境已部署) +对应方案:`docs/engineering/轮询按运营商账户限流技术方案.md` 第五部分第 3 节的 7 个提案 + +本文给前端工程师用:列出这次方案新增、改动和废弃的后台接口,以及每个页面要改什么。字段级定义以接口文档(`/api/admin` 的 OpenAPI)为准,本文附录列出了全部新增接口的字段表,由接口文档直接生成。 + +- 新增接口 46 个,删除 0 个,改动 16 个(与方案开始前的代码逐接口对比得出)。 +- 所有接口都要登录。列表接口分页参数统一为 `page`、`page_size`(最大 100),返回 `items`、`total`、`page`、`size`。 +- "仅超级管理员" 的修改接口,其他账号调用返回 403;"仅平台账号" 指超级管理员与平台账号可用。 +- 枚举优先从 `GET /polling-options` 取;不在其中的(见第 9 节)以本文与接口文档的说明为准。 + +--- + +## 1. 需要新增和改造的页面一览 + +| 页面 | 类型 | 主要接口 | 对应章节 | +|---|---|---|---| +| 网关限流组 | 新增 | `/polling-rate-limit-groups` | 2.1 | +| 上游错误分类规则(含测试) | 新增 | `/gateway-error-classifications` | 2.2 | +| 停复机记录 | 新增 | `/card-stop-resume-records`、`/iot-cards/:id/stop-resume-records` | 2.3 | +| 网关调用监控(按运营商账户) | 新增 | `/polling-stats/carriers`、`/polling-stats/carriers/:carrier_id/trend` | 2.4 | +| 轮询配置 | 改造 | `/polling-configs` 及匹配预览、优先级、重算到期 | 3 | +| 分层与重置日前统计 | 新增 | `/polling-stats/tiers`、`/polling-stats/pre-reset` | 3.4 | +| 资产详情(后台与 C 端) | 改造 | 去掉保护期展示 | 4 | +| 停复机规则演练 | 新增 | `/stop-resume-rule/dry-run` | 5 | +| 运营商账户调度参数 | 新增 | `/polling-carrier-params` | 6.1 | +| 请求检查场景 | 新增 | `/polling-check-scenes` | 6.2 | +| 失败告警(含账户汇总、停机被拒视图) | 新增 | `/polling-failure-alerts` | 6.3、8.5 | +| 按账户轮询队列监控 | 新增 | `/polling-stats/carrier-queues` | 6.4、7 | +| 单卡轮询状态(排查用) | 新增 | `/iot-cards/:id/polling-state` | 6.5、7 | +| 系统配置 | 改造 | `/system-configs` 增加 `polling` 模块 | 9 | +| 不轮询清单 | 新增 | `/card-polling-pauses` | 8.3 | +| 轮询开关文件导入 | 新增 | `/polling-status-imports` | 8.2 | +| 卡列表、设备列表 | 改造 | 是否轮询筛选与列、批量开关轮询 | 8.1、8.4 | +| 轮询并发配置 | 保留、加提示 | `/polling-concurrency` | 6.6 | + +--- + +## 2. 网关限流与停复机记录(第 1 个提案) + +### 2.1 网关限流组页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-rate-limit-groups` | 列表 | +| `GET /polling-rate-limit-groups/:id` | 详情 | +| `POST /polling-rate-limit-groups` | 新建(仅超级管理员) | +| `PUT /polling-rate-limit-groups/:id` | 修改(仅超级管理员) | +| `PUT /polling-rate-limit-groups/:id/status` | 启停(仅超级管理员),`status`:1 启用、0 停用 | +| `DELETE /polling-rate-limit-groups/:id` | 删除(仅超级管理员) | + +- `carrier_id` 为空表示全局组(各账户合计);有值表示该运营商账户的组。 +- `operations` 取值见 `GET /polling-options` 的 `gateway_operations`(查流量、查状态、查实名、停机、复机)。 +- 限流是否真正拦截由系统配置 `polling.gateway.rate_limit_mode` 决定(`observe` 只统计、`enforce` 拦截,见第 9 节),页面上建议展示当前模式。 + +### 2.2 上游错误分类规则页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /gateway-error-classifications` | 列表 | +| `POST /gateway-error-classifications` | 新建(仅超级管理员) | +| `PUT /gateway-error-classifications/:id` | 修改(仅超级管理员) | +| `PUT /gateway-error-classifications/:id/status` | 启停(仅超级管理员) | +| `DELETE /gateway-error-classifications/:id` | 删除(仅超级管理员) | +| `POST /gateway-error-classifications/test` | 测试:输入操作与上游返回信息,返回命中的分类,不写数据 | + +- 类别(`category`)取值见 `GET /polling-options` 的 `error_categories`;匹配方式见 `match_types`。 +- "自动关闭轮询"只对终态类别生效。 + +### 2.3 停复机记录页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /card-stop-resume-records` | 全部记录,时间范围必填,跨度不超过 31 天 | +| `GET /iot-cards/:id/stop-resume-records` | 单卡历史(可放在卡详情或告警详情里,用于查看最近停复机记录) | + +- 结果、动作取值见 `GET /polling-options` 的 `stop_resume_results`、`stop_resume_actions`。 + +### 2.4 网关调用监控(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-stats/carriers` | 按运营商账户汇总最近若干分钟的网关调用(成功率、QPS、耗时、错误类别) | +| `GET /polling-stats/carriers/:carrier_id/trend` | 单个账户的分钟级趋势 | +| `GET /polling-options` | 本方案后台页面用的枚举(操作、错误类别、匹配方式、限流模式、豁免来源、停复机结果与动作) | + +--- + +## 3. 轮询配置改造(第 2 个提案:分层轮询) + +### 3.1 字段变化:`POST /polling-configs`、`PUT /polling-configs/:id`、列表与详情 + +| 变化 | 字段 | 说明 | +|---|---|---| +| 新增 | `asset_status` | 资产状态匹配(1 在库、2 已销售、3 已换货、4 已停用),为空不限 | +| 新增 | `package_state` | 套餐状态匹配(`active` 有生效套餐、`depleted` 已用完、`pending` 只有待生效、`none` 无套餐),为空不限 | +| 新增 | `pre_reset_window`、`pre_reset_carddata_interval` | 重置日前加密:窗口长度与窗口内流量检查间隔(秒),两者同时配置才生效 | +| 新增(仅修改接口) | `clear_fields` | 要清空为空值的字段名列表:间隔清空即改为继承,匹配条件清空即不限 | +| 新增(返回) | `warnings` | 保存提示(如与其他配置优先级相同且条件可能重叠),不影响保存结果,页面应展示 | +| **删除** | `protect_check_interval` | 保护期已下线,请求与返回都不再有该字段,页面去掉该输入项 | +| 含义变化 | 四个检查间隔 `*_check_interval` | 三态:正数按间隔;`0` 不检查且不再继承;不传或为空继承优先级更低的配置。页面要能区分"0"和"空" | + +### 3.2 匹配预览(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-configs/match-preview?iccid=` | 按当前已保存配置,预览某张卡命中哪些配置、各检查类型的最终间隔 | +| `POST /polling-configs/match-preview` | 同上,但可带未保存的修改(`overrides`),用于编辑弹窗里"保存前预览",不写数据 | + +### 3.3 优先级与重算到期(新增) + +| 接口 | 说明 | +|---|---| +| `PUT /polling-configs/priorities` | 整体调整优先级(拖拽排序后提交 `ordered_ids`),仅超级管理员 | +| `POST /polling-configs/recalculate-due` | 立即重算轮询到期时间(可按运营商账户),异步,只提前不推后,仅超级管理员;返回 `task_id` | +| `GET /polling-configs/recalculate-due/:task_id` | 查询重算进度 | + +### 3.4 统计(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-stats/tiers` | 各层卡数、漏配告警卡数(结果缓存 5 分钟) | +| `GET /polling-stats/pre-reset` | 重置日前加密效果:按账户统计窗口内未查到流量的卡数、最后一次查询距重置时刻分布 | + +--- + +## 4. 保护期下线(第 3 个提案) + +- `device_protect_status` 字段**保留但已废弃**,固定返回 `none`,涉及: + - `GET /assets/resolve/:identifier` + - `GET /assets/:identifier/realtime-status` + - `POST /assets/:identifier/refresh` + - C 端 `GET /api/c/v1/asset/info` +- 前端:后台资产详情与 C 端去掉保护期状态的展示;轮询配置去掉保护期间隔(见 3.1)。 + +--- + +## 5. 停复机规则演练(第 4 个提案) + +| 接口 | 说明 | +|---|---| +| `GET /stop-resume-rule/dry-run` | 对全部卡按停复机新规则只判断不执行:按运营商账户 × 当前停机原因 × 判断结果的汇总,加分页明细;可传"假设的实名管控配置"预演;仅平台账号 | +| `POST /stop-resume-rule/dry-run/export` | 导出明细(导出场景 `stop_resume_rule_dry_run`),筛选与假设配置同演练接口 | + +- 运营商账户的"实名管控"开关(`realname_control_enabled`)在运营商账户编辑里(`PUT /carriers/:id`)。从 0 改为 1 时必须带 `realname_control_confirm=true`,否则接口返回提示文案(含将被停机的卡数),前端应把这段提示作为二次确认展示,确认后带上参数重新提交。 + +--- + +## 6. 按运营商账户调度(第 5 个提案) + +### 6.1 运营商账户调度参数页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-carrier-params` | 全部运营商账户的生效参数;未单独配置的账户返回全局默认并标记 `is_default` | +| `GET /polling-carrier-params/:carrier_id` | 单个账户 | +| `PUT /polling-carrier-params/:carrier_id` | 保存(仅超级管理员)。字段为空表示该项用全局默认;执行上限不得大于订阅进程 `max_in_flight` 之和,超出会被拒绝 | +| `DELETE /polling-carrier-params/:carrier_id` | 删除,恢复全局默认(仅超级管理员) | + +字段:`inflight_limit`、`card_max_in_flight`(卡任务执行上限与每进程并发),`sr_inflight_limit`、`stop_resume_max_in_flight`(停复机执行上限与每进程并发),`priority_max_ratio`(优先队列最大占比),`stop_resume_min_interval`(单卡两次停复机调用最小间隔,秒),`stop_resume_confirm_delay`(停复机结果未知后的确认延迟,秒)。 + +### 6.2 请求检查场景页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-check-scenes` | 全部场景(代码预置 8 个:订单支付、套餐激活、停复机成功、设备操作、自动续费购包、C 端资产详情、后台资产实时状态、实名链接) | +| `PUT /polling-check-scenes/:scene` | 修改(仅超级管理员):只可改检查类型、延迟确认序列(递增)与冷却时长 | + +### 6.3 失败告警页面(新增) + +| 接口 | 说明 | +|---|---| +| `GET /polling-failure-alerts` | 列表,可按运营商账户、检查类型、错误类别、状态、告警级别、ICCID、时间筛选;`view=stop_refused` 见 8.5 | +| `GET /polling-failure-alerts/summary` | 未处理告警按运营商账户 × 错误类别汇总(账户汇总视图) | +| `GET /polling-failure-alerts/:id` | 详情;需要看该卡最近的停复机记录时调 `GET /iot-cards/:id/stop-resume-records` | +| `PUT /polling-failure-alerts/:id/status` | 标记已处理(只有未处理的告警可以标记) | +| `POST /polling-failure-alerts/close-polling` | 勾选告警批量关闭对应卡的轮询,见 8.5 | + +- 告警级别:`card` 卡级、`carrier` 账户级(窗口内同账户告警数超过阈值时产生,`card_id` 为 0)。 +- 检查类型:`card_status`、`carddata`、`realname`、`package`、`stop_resume`(停复机,第 6 个提案新增)、`all`(账户级)。 +- 状态:1 未处理、2 已恢复(首次成功后自动转入)、3 已关闭轮询、4 已处理。 + +### 6.4 按账户轮询队列监控(新增) + +`GET /polling-stats/carrier-queues`:调度模式、新结构初始化状态,以及每个运营商账户的队列长度、已到期、执行中、执行上限、上一分钟 QPS、限流等待与拒绝、近 1 小时处理中标记到期次数、未处理告警数(含按错误类别)。停复机相关字段见第 7 节。 + +### 6.5 单卡轮询状态(新增,排查用) + +`GET /iot-cards/:id/polling-state`:卡所在队列、下次可领取时间、是否执行中、各检查类型的下次到期、最近成功、连续失败与最近错误、待执行的延迟确认。停复机相关字段见第 7 节。建议放在卡详情的"轮询"页签。 + +### 6.6 轮询并发配置页面(保留) + +`/polling-concurrency` 仍然存在,但**只对旧分片调度(`polling.scheduler.mode = legacy`)生效**,新调度下修改没有效果。页面上请加提示:"仅旧调度生效,按运营商账户调度时请使用运营商账户调度参数"。该页面会在旧调度代码下线时一并删除。 + +### 6.7 调度模式切换 + +通过系统配置 `polling.scheduler.mode`(`legacy` / `carrier`)切换,`GET /polling-stats/init-progress`(原有接口)查看新结构初始化进度。 + +--- + +## 7. 停复机指令队列(第 6 个提案) + +没有新增接口,只在已有接口上加字段: + +- **全局开关**:系统配置 `polling.stop_resume.queue_enabled`(默认关闭)。开启后自动停复机经指令队列执行;关闭即回到各入口当场执行。 +- `GET /polling-stats/carrier-queues` 每个账户新增: + +| 字段 | 说明 | +|---|---| +| `stop_resume_queue_length` | 停复机指令队列长度 | +| `stop_resume_due` | 已到期指令数 | +| `stop_resume_running` | 执行中指令数 | +| `stop_resume_pending` | 结果未知待确认的指令数(按队列前 500 条统计) | +| `stop_resume_success_1h`、`stop_resume_failed_1h`、`stop_resume_retry_1h`、`stop_resume_unknown_1h` | 近 1 小时成功、失败、推后重试、结果未知次数 | + +- `GET /iot-cards/:id/polling-state` 新增: + +| 字段 | 说明 | +|---|---| +| `stop_resume_queue_enabled` | 停复机出口开关是否开启 | +| `stop_resume_command` | 当前停复机指令,没有时为 `null`:`action`(`stop` / `start`)、`reason`、`scenes`、`source`、`version`、`fail_count`、`last_error`、`pending`(结果未知待确认)、`unknown`、`written_at`、`next_at`(下次可执行时间,受单卡最小间隔约束) | +| `last_stop_resume_call_at` | 最近一次停复机网关调用时间 | + +- 失败告警的检查类型新增 `stop_resume`(见 6.3)。 + +--- + +## 8. 不轮询清单与批量开关轮询(第 7 个提案) + +### 8.1 卡列表、设备列表:批量开关轮询(新增) + +| 接口 | 说明 | +|---|---| +| `POST /iot-cards/batch-update-polling-status` | 勾选卡批量开关轮询 | +| `POST /devices/batch-update-polling-status` | 勾选设备批量开关轮询(级联到设备下各卡) | + +请求:`asset_ids`(1~500 个,不能重复)、`enable_polling`(true 开启、false 关闭)、`reason`(必填,写入不轮询清单)。 + +返回:`success_count`、`skip_count`、`fail_count`、`items`(逐项结果)、`impact`(本次目标状态的影响说明)。逐项 `status`: + +| 值 | 含义 | 典型 `reason` | +|---|---|---| +| 1 | 成功 | | +| 2 | 跳过 | "已是目标状态"、"已销户,不能开启轮询"、"风险停机,不能开启轮询" | +| 3 | 失败 | 具体错误信息 | +| 4 | 无权限或资产不存在 | "无权限操作该资产或资产不存在" | + +- 部分成功不会回滚,请把逐项结果展示给用户(例如结果弹窗按状态分组)。 +- 企业账号调用返回 403;代理账号只能操作本店及下级店铺的资产。 +- 超过 500 个或 ID 重复直接返回参数错误。 + +### 8.2 轮询开关文件导入(新增,仅平台账号) + +流程: + +1. `POST /storage/upload-url`,`purpose` 传 **`polling_status_import`**(新增用途),文件名用 `.csv`,拿到 `upload_url` 和 `file_key`。 +2. 用 `PUT` 把 CSV 传到 `upload_url`。CSV 格式:**首行为表头**,**首列**为 ICCID(卡,19 位或 20 位都可以)或 IMEI/虚拟号(设备),空行忽略,最多 50000 行。 +3. `POST /polling-status-imports`:`file_key`(必须以 `polling-status-imports/` 开头)、`asset_type`(`iot_card` / `device`)、`enable_polling`、`reason`。返回任务(状态 1 待处理)。 +4. `GET /polling-status-imports` 看任务列表与进度(状态:1 待处理、2 处理中、3 已完成、4 失败);`GET /polling-status-imports/:id` 看逐行结果 `items`(`line`、`identifier`、`asset_id`、`status`、`status_name`、`reason`,状态取值同 8.1)。 + +- 逐行处理规则与勾选批量相同,每行独立,部分成功不回滚;任务级失败(文件不是 CSV、编码无法识别、没有数据行等)看 `error_message`。 + +### 8.3 不轮询清单页面(新增,仅平台账号) + +`GET /card-polling-pauses`,筛选参数: + +| 参数 | 说明 | +|---|---| +| `asset_type` | `iot_card` / `device` | +| `carrier_id` | 卡所属运营商账户 | +| `source` | 关闭来源,取值见下表 | +| `status` | 1 已关闭、2 已恢复 | +| `identifier` | ICCID 或 IMEI(精确) | +| `operator_id` | 关闭操作人账号 ID | +| `start_time`、`end_time` | 关闭时间范围(带时区的 RFC3339 秒级时间) | + +返回每条记录:资产类型与 ID、`identifier`、运营商账户(`carrier_id`、`carrier_name`)、资产当前 `enable_polling`、卡当前 `gateway_extend`、`status`/`status_name`、`close_source`/`close_source_name`、`close_reason`、`closed_by`/`closed_by_name`、`closed_at`、`import_task_id`、`restore_source`/`restore_source_name`、`restore_reason`、`restored_by`/`restored_by_name`、`restored_at`。系统操作时操作人为 0(展示"系统")。 + +来源取值(关闭来源与恢复来源共用): + +| 值 | 名称 | +|---|---| +| `single` | 单资产接口 | +| `batch` | 勾选批量 | +| `import` | 文件导入 | +| `risk_auto` | 风险停机或已销户自动关闭 | +| `cascade` | 设备级联 | +| `order` | 支付或下单生效(自动恢复) | +| `expiry_change` | 改有效期(自动恢复) | +| `alert` | 停机被拒告警处理 | +| `history` | 历史数据(上线时补写的存量) | + +- 每个资产同时只有一条"已关闭"记录;恢复后该记录标为"已恢复"并保留,再次关闭会新增一条,所以同一资产可能有多条历史。 +- 列表勾选批量开启:直接复用 8.1 的批量接口(`enable_polling=true`)。 +- 导出:统一导出任务,场景 `polling_pause`,`query.filters` 与本接口筛选参数相同。 + +### 8.4 卡列表、设备列表的改动 + +| 接口 | 变化 | +|---|---| +| `GET /iot-cards/standalone` | 新增筛选参数 `enable_polling`(true 轮询中、false 已关闭,不传不过滤);返回原本就有 `enable_polling` | +| `GET /devices` | 新增筛选参数 `enable_polling`;**返回新增字段 `enable_polling`** | +| 卡导出(场景 `iot_card`)、设备导出(场景 `device`) | 支持 `enable_polling` 筛选;导出文件**最后一列新增「是否轮询」** | +| `PATCH /assets/:identifier/polling-status`(单资产开关,原有) | 行为变化:网关扩展状态为风险停机或已销户的卡**不能开启**,返回 403;开关会写入不轮询清单(来源"单资产接口") | + +### 8.5 失败告警:停机被拒视图与批量关闭轮询(新增) + +- `GET /polling-failure-alerts?view=stop_refused`:停复机方向为停机,且错误类型为终态或业务错误、或停机失败次数达到阈值的告警。 + - 这个视图只认 `carrier_id`、`status`、`iccid`、`start_time`、`end_time` 筛选,**会忽略** `check_type`、`error_category`、`alert_level`,页面切到该视图时请隐藏这三个筛选项。 + - 额外返回:`device_id`(所属设备)、`network_status`、`stop_reason`、`enable_polling`(是否已关闭轮询)、`has_package`(是否有生效套餐)、`handled_by_name`。上游返回信息在 `last_error` 中。 + - 导出:统一导出任务,场景 `polling_stop_refused_alert`,`query.filters` 为 `carrier_id`、`status`、`iccid`、`start_time`、`end_time`。 +- `POST /polling-failure-alerts/close-polling`(仅平台账号):`alert_ids`(1~500)、`reason`。关闭告警对应**卡本身**的轮询(清单来源"停机被拒告警处理"),成功或已关闭的告警状态改为"已关闭轮询"。返回格式同 8.1;不存在或不是卡级告警的 ID 以 `asset_id=0`、状态 4 返回。 + +### 8.6 开关轮询的确认框文案 + +`GET /polling-status/impact` 返回 `disable`(关闭的影响)与 `enable`(开启的影响)两组文案,前端在关闭、开启轮询的确认框中直接展示,不要写死。批量接口的返回 `impact` 是同一份内容。 + +关闭的影响(当前内容):不再查询上游;流量用完、实名不满足不自动停机,套餐激活、流量重置后不自动复机;套餐到期、退款后无可用套餐仍会停机;订单套餐生效、后台改有效期后有生效套餐会自动恢复轮询并按规则复机;人工停复机照常;设备关闭时设备下所有卡同样适用。 + +### 8.7 自动恢复轮询(无接口变化,影响页面展示) + +以下操作会自动把已关闭轮询的卡或设备恢复轮询(风险停机、已销户的卡除外),清单里能看到对应的恢复来源,页面不需要额外处理: + +- 订单套餐生效:客户支付成功、后台下单、批量下单、OpenAPI 钱包下单(来源 `order`); +- 后台修改套餐有效期后资产有未到期的生效套餐(来源 `expiry_change`)。 + +--- + +## 9. 系统配置(`/system-configs`)新增 `polling` 模块 + +`GET /system-configs?module=polling` 可列出以下配置,修改用 `PUT /system-configs/:key`(JSON 类配置会做结构校验,非法时返回错误说明)。 + +| 配置键 | 类型 | 默认 | 说明 | +|---|---|---|---| +| `polling.gateway.rate_limit_mode` | string | `observe` | 网关限流模式:`observe` 只统计不拦截,`enforce` 拦截 | +| `polling.gateway.default_qps` | int | 10 | 未被启用限流组覆盖的卡网关操作的默认每秒请求上限 | +| `polling.gateway.rate_limited_retry_delay_seconds` | int | 5 | 任务遇限流后的固定重试延迟(秒) | +| `polling.gateway.rate_limit_defer_alert_seconds` | int | 600 | 同一任务因限流累计推迟超过该时长时写告警 | +| `polling.stop_resume_record.retention_months` | int | 6 | 停复机记录保留月数 | +| `polling.stop_resume_record.premake_months` | int | 3 | 停复机记录提前创建未来分区的月数 | +| `polling.scheduler.mode` | string | `legacy` | 调度模式:`legacy` 旧分片调度,`carrier` 按运营商账户调度 | +| `polling.scheduler.step_order` | json | `["card_status","carddata","realname","package"]` | 卡任务步骤顺序 | +| `polling.scheduler.step_timeout_seconds` | json | `{"card_status":15,"carddata":15,"realname":15,"package":20}` | 各检查类型单步超时(秒) | +| `polling.scheduler.task_timeout_margin_seconds` | int | 10 | 卡任务总超时余量(秒) | +| `polling.scheduler.skip_package_after_flow` | bool | true | 同轮流量步骤已触发停复机评估时跳过套餐步骤 | +| `polling.failure.backoff_seconds` | json | `{"default":[60,300,900,1800,3600]}` | 失败退避序列(秒,递增),可按检查类型覆盖 | +| `polling.failure.alert_fail_count` | json | `{"default":5}` | 连续失败告警阈值,可按检查类型覆盖 | +| `polling.failure.alert_fail_duration_seconds` | int | 21600 | 持续失败时长告警阈值(秒) | +| `polling.failure.immediate_alert_categories` | json | `["account_config"]` | 首次出现即告警的错误类别 | +| `polling.failure.account_alert_window_seconds` | int | 600 | 账户级告警统计窗口(秒) | +| `polling.failure.account_alert_threshold` | int | 50 | 账户级告警阈值 | +| `polling.stop_resume.queue_enabled` | bool | false | 自动停复机经停复机指令队列执行(全局开关) | +| `polling.stop_resume.unknown_alert_threshold` | int | 3 | 停复机连续结果未知告警阈值 | +| `polling.stop_resume.backoff_seconds` | json | `[600,900,1800,3600]` | 停复机失败退避序列(秒,递增) | +| `polling.stop_resume.alert_fail_count` | int | 5 | 停复机连续失败告警阈值 | + +`module` 参数和返回的 `module` 枚举新增 `polling`。 + +--- + +## 10. 导出场景汇总 + +`POST /export-tasks` 的 `scene`、`GET /export-tasks` 的 `scene` 筛选新增: + +| 场景 | 说明 | `query.filters` | +|---|---|---| +| `polling_pause` | 不轮询清单(仅平台账号) | 同 `GET /card-polling-pauses` | +| `polling_stop_refused_alert` | 停机被拒告警(仅平台账号) | `carrier_id`、`status`、`iccid`、`start_time`、`end_time` | +| `stop_resume_rule_dry_run` | 停复机规则演练明细(第 4 个提案,建议走 `POST /stop-resume-rule/dry-run/export`) | 同演练接口 | + +原有场景 `iot_card`、`device` 支持 `enable_polling` 筛选,导出最后一列新增「是否轮询」。历史导出任务重新导出时列不变。 + +--- + +## 11. 前端改动清单(按优先级) + +1. 轮询配置页:去掉保护期间隔;加资产状态、套餐状态、重置日前两个字段;间隔支持"0"与"空"两种;修改时支持 `clear_fields`;展示 `warnings`;匹配预览与优先级拖拽;重算到期。(第 2 个提案上线即需要) +2. 资产详情(后台与 C 端):去掉保护期状态展示。(第 3 个提案) +3. 运营商账户编辑:实名管控开关与 0→1 二次确认。(第 4 个提案) +4. 系统配置页:支持 `polling` 模块与 JSON 类配置的编辑。 +5. 新增页面:网关限流组、错误分类规则(含测试)、停复机记录、网关调用监控、停复机规则演练、运营商账户调度参数、请求检查场景、失败告警(含账户汇总)、按账户队列监控、单卡轮询状态。 +6. 卡列表、设备列表:是否轮询筛选与列、批量开关轮询(含逐项结果展示和确认框文案)。 +7. 不轮询清单页(筛选、导出、勾选批量开启)与文件导入页(上传、任务列表、逐行结果)。 +8. 失败告警页:停机被拒视图(切换时隐藏三个筛选项)、导出、勾选批量关闭轮询。 +9. 轮询并发配置页:加"仅旧调度生效"提示。 + +--- + +## 附录:新增接口字段表(由接口文档生成) + +以下路径省略前缀 `/api/admin`。字段说明与接口文档一致;如有出入,以测试环境接口文档为准。 + +#### `DELETE /gateway-error-classifications/{id}` 删除上游错误分类规则(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | ID | + +#### `DELETE /polling-carrier-params/{carrier_id}` 删除运营商账户调度参数(恢复全局默认,仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `carrier_id` | integer | 是 | 运营商账户ID | + +#### `DELETE /polling-rate-limit-groups/{id}` 删除网关限流组(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | ID | + +#### `GET /card-polling-pauses` 查询不轮询清单(仅平台账号) + +每个资产只有一条已关闭记录,恢复后保留历史;导出使用统一导出任务,场景 polling_pause,筛选参数同本接口。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `asset_type` | string | | 资产类型 (iot_card:卡, device:设备) | +| query | `carrier_id` | integer | | 卡所属运营商账户ID | +| query | `source` | string | | 关闭来源 (single:单资产接口, batch:勾选批量, import:文件导入, risk_auto:风险停机或已销户自动关闭, cascade:设备级联, order:支付或下单生效, expiry_change:改有效期, alert:停机被拒告警处理, history:历史数据) | +| query | `status` | integer | | 状态 (1:已关闭, 2:已恢复) | +| query | `identifier` | string | | ICCID 或 IMEI(精确) | +| query | `operator_id` | integer | | 关闭操作人账号ID | +| query | `start_time` | string | | 关闭时间起始(带时区的 RFC3339 秒级时间) | +| query | `end_time` | string | | 关闭时间结束(带时区的 RFC3339 秒级时间) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 清单记录 | +| `items[].asset_id` | integer | 资产ID | +| `items[].asset_type` | string | 资产类型 (iot_card:卡, device:设备) | +| `items[].carrier_id` | integer | 卡所属运营商账户ID(设备为 0) | +| `items[].carrier_name` | string | 运营商账户名称 | +| `items[].close_reason` | string | 关闭原因 | +| `items[].close_source` | string | 关闭来源 | +| `items[].close_source_name` | string | 关闭来源名称 | +| `items[].closed_at` | string | 关闭时间 | +| `items[].closed_by` | integer | 关闭操作人账号ID(系统为 0) | +| `items[].closed_by_name` | string | 关闭操作人 | +| `items[].enable_polling` | boolean | 资产当前轮询开关 | +| `items[].gateway_extend` | string | 卡当前网关扩展状态(设备为空) | +| `items[].id` | integer | 记录ID | +| `items[].identifier` | string | ICCID 或 IMEI | +| `items[].import_task_id` | integer | 文件导入任务ID(非导入为 0) | +| `items[].restore_reason` | string | 恢复原因 | +| `items[].restore_source` | string | 恢复来源 | +| `items[].restore_source_name` | string | 恢复来源名称 | +| `items[].restored_at` | string | 恢复时间 | +| `items[].restored_by` | integer | 恢复操作人账号ID(系统为 0) | +| `items[].restored_by_name` | string | 恢复操作人 | +| `items[].status` | integer | 状态 (1:已关闭, 2:已恢复) | +| `items[].status_name` | string | 状态名称 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /card-stop-resume-records` 查询停复机记录(时间范围必填,跨度不超过 31 天) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `iccid` | string | | ICCID | +| query | `carrier_id` | integer | | 运营商账户ID | +| query | `action` | string | | 动作 (stop:停机, start:复机) | +| query | `source` | string | | 来源 | +| query | `result` | string | | 结果 (success:成功, failed:失败, unknown:结果未知, already_target:已是目标状态, skipped:跳过) | +| query | `error_category` | string | | 错误类别 | +| query | `start_time` | string | 是 | 开始时间(必填,RFC3339) | +| query | `end_time` | string | 是 | 结束时间(必填,RFC3339,跨度不超过 31 天) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 记录列表 | +| `items[].action` | string | 动作 (stop:停机, start:复机) | +| `items[].action_name` | string | 动作名称 | +| `items[].attempt` | integer | 尝试序号 | +| `items[].card_id` | integer | IoT卡ID | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].command_id` | string | 停复机命令标识,同一命令的多次尝试相同 | +| `items[].created_at` | string | 记录时间 | +| `items[].duration_ms` | integer | 耗时(毫秒) | +| `items[].error_category` | string | 错误类别 | +| `items[].error_category_name` | string | 错误类别名称 | +| `items[].iccid` | string | ICCID | +| `items[].id` | integer | 记录ID | +| `items[].provider_code` | string | 上游返回码 | +| `items[].provider_message` | string | 上游返回信息(已截断) | +| `items[].reason` | string | 停机原因 | +| `items[].result` | string | 结果 (success:成功, failed:失败, unknown:结果未知, already_target:已是目标状态, skipped:跳过) | +| `items[].scene` | string | 场景 | +| `items[].source` | string | 来源 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /gateway-error-classifications` 查询上游错误分类规则列表 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `category` | string | | 类别筛选 (rate_limited_upstream:上游频率限制, terminal:终态不可操作, already_target:已是目标状态, transient:临时故障, business:业务错误, account_config:账户配置错误) | +| query | `status` | integer | | 状态 (0:停用, 1:启用) | +| query | `keyword` | string | | 关键字模糊搜索 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 规则列表 | +| `items[].auto_disable_polling` | boolean | 命中后自动关闭该卡轮询 | +| `items[].category` | string | 类别 | +| `items[].category_name` | string | 类别名称 | +| `items[].created_at` | string | 创建时间 | +| `items[].id` | integer | 规则ID | +| `items[].keyword` | string | 匹配关键字或正则 | +| `items[].match_type` | string | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `items[].maybe_accepted` | boolean | 上游可能已受理 | +| `items[].operations` | array | 适用操作,为空表示全部 | +| `items[].priority` | integer | 匹配优先级 | +| `items[].remark` | string | 备注 | +| `items[].status` | integer | 状态 (0:停用, 1:启用) | +| `items[].updated_at` | string | 更新时间 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /iot-cards/{id}/polling-state` 查询单卡轮询状态 + +各检查类型下次到期、最近成功、连续失败与最近错误、是否执行中;停复机出口开关、当前停复机指令(动作、原因、场景、版本、失败次数、待确认、下次可执行时间)与最近一次停复机调用时间;只读。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 卡ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `card_id` | integer | 卡ID | +| `carrier_id` | integer | 运营商账户ID | +| `claim_expire_at` | string | 处理中标记到期时间 | +| `enable_polling` | boolean | 卡轮询开关 | +| `iccid` | string | ICCID | +| `last_stop_resume_call_at` | string | 最近一次停复机网关调用时间(单卡最小重试间隔依据) | +| `priority_mark` | boolean | 执行中收到请求检查,收尾后进入优先队列 | +| `queue` | string | 所在队列 (priority:优先, queue:普通, none:不在轮询中) | +| `queue_score_at` | string | 队列中下次可领取时间 | +| `running` | boolean | 是否执行中 | +| `scheduler_mode` | string | 当前调度模式 (legacy:旧分片调度, carrier:按运营商账户调度) | +| `stop_resume_command` | object | | +| `stop_resume_command.action` | string | 动作 (stop:停机, start:复机) | +| `stop_resume_command.fail_count` | integer | 连续失败次数 | +| `stop_resume_command.last_error` | string | 最近错误(类别/信息) | +| `stop_resume_command.next_at` | string | 下次可执行时间(空表示不在队列中) | +| `stop_resume_command.pending` | boolean | 结果未知,待确认 | +| `stop_resume_command.reason` | string | 停机原因 | +| `stop_resume_command.scenes` | array | 触发场景 | +| `stop_resume_command.source` | string | 请求来源 | +| `stop_resume_command.unknown` | integer | 连续结果未知次数 | +| `stop_resume_command.version` | integer | 指令版本 | +| `stop_resume_command.written_at` | string | 最近写入时间 | +| `stop_resume_queue_enabled` | boolean | 停复机出口开关是否开启 | +| `types` | array | 各检查类型状态 | +| `types[].check_type` | string | 检查类型 | +| `types[].check_type_name` | string | 检查类型名称 | +| `types[].fail_count` | integer | 连续失败次数 | +| `types[].first_failed_at` | string | 首次失败时间 | +| `types[].last_error` | string | 最近错误(类别/信息) | +| `types[].last_success_at` | string | 最近一次成功时间 | +| `types[].next_due_at` | string | 下次到期时间 | +| `types[].pending_confirm` | array | 待执行的延迟确认(秒) | + +#### `GET /iot-cards/{id}/stop-resume-records` 查询单卡停复机历史 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `start_time` | string | | 开始时间(RFC3339),为空取最近 31 天 | +| query | `end_time` | string | | 结束时间(RFC3339),为空取当前 | +| path | `id` | integer | 是 | IoT卡ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 记录列表 | +| `items[].action` | string | 动作 (stop:停机, start:复机) | +| `items[].action_name` | string | 动作名称 | +| `items[].attempt` | integer | 尝试序号 | +| `items[].card_id` | integer | IoT卡ID | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].command_id` | string | 停复机命令标识,同一命令的多次尝试相同 | +| `items[].created_at` | string | 记录时间 | +| `items[].duration_ms` | integer | 耗时(毫秒) | +| `items[].error_category` | string | 错误类别 | +| `items[].error_category_name` | string | 错误类别名称 | +| `items[].iccid` | string | ICCID | +| `items[].id` | integer | 记录ID | +| `items[].provider_code` | string | 上游返回码 | +| `items[].provider_message` | string | 上游返回信息(已截断) | +| `items[].reason` | string | 停机原因 | +| `items[].result` | string | 结果 (success:成功, failed:失败, unknown:结果未知, already_target:已是目标状态, skipped:跳过) | +| `items[].scene` | string | 场景 | +| `items[].source` | string | 来源 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /polling-carrier-params` 查询运营商账户调度参数列表 + +未单独配置的账户返回全局默认并标记 is_default。 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `default_card_max_in_flight` | integer | 全局默认每进程 max_in_flight | +| `default_inflight_limit` | integer | 全局默认执行上限 | +| `items` | array | 各运营商账户调度参数 | +| `items[].card_max_in_flight` | integer | 生效的每进程卡任务 max_in_flight | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].carrier_name` | string | 运营商账户名称 | +| `items[].configured_card_max_in_flight` | integer | 单独配置的每进程 max_in_flight,空表示使用默认 | +| `items[].configured_inflight_limit` | integer | 单独配置的执行上限,空表示使用默认 | +| `items[].consume_capacity` | integer | 当前订阅进程 max_in_flight 之和(执行上限不应超过该值) | +| `items[].inflight_limit` | integer | 生效的执行上限(跨 Worker 实例同时执行卡任务数) | +| `items[].is_default` | boolean | 是否未单独配置、全部使用全局默认 | +| `items[].priority_max_ratio` | number | 优先队列每轮最大占比(0~1),空表示不限 | +| `items[].sr_inflight_limit` | integer | 停复机执行上限(停复机指令队列使用),空表示默认 | +| `items[].stop_resume_confirm_delay` | integer | 停复机结果未知后确认延迟(秒),空表示默认 | +| `items[].stop_resume_max_in_flight` | integer | 每进程停复机 max_in_flight(停复机指令队列使用),空表示默认 | +| `items[].stop_resume_min_interval` | integer | 单卡两次停复机调用最小间隔(秒),空表示默认 | +| `subscriber_processes` | integer | 订阅卡任务的 Worker 进程数 | + +#### `GET /polling-carrier-params/{carrier_id}` 查询运营商账户调度参数 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `carrier_id` | integer | 是 | 运营商账户ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `card_max_in_flight` | integer | 生效的每进程卡任务 max_in_flight | +| `carrier_id` | integer | 运营商账户ID | +| `carrier_name` | string | 运营商账户名称 | +| `configured_card_max_in_flight` | integer | 单独配置的每进程 max_in_flight,空表示使用默认 | +| `configured_inflight_limit` | integer | 单独配置的执行上限,空表示使用默认 | +| `consume_capacity` | integer | 当前订阅进程 max_in_flight 之和(执行上限不应超过该值) | +| `inflight_limit` | integer | 生效的执行上限(跨 Worker 实例同时执行卡任务数) | +| `is_default` | boolean | 是否未单独配置、全部使用全局默认 | +| `priority_max_ratio` | number | 优先队列每轮最大占比(0~1),空表示不限 | +| `sr_inflight_limit` | integer | 停复机执行上限(停复机指令队列使用),空表示默认 | +| `stop_resume_confirm_delay` | integer | 停复机结果未知后确认延迟(秒),空表示默认 | +| `stop_resume_max_in_flight` | integer | 每进程停复机 max_in_flight(停复机指令队列使用),空表示默认 | +| `stop_resume_min_interval` | integer | 单卡两次停复机调用最小间隔(秒),空表示默认 | + +#### `GET /polling-check-scenes` 查询请求检查场景 + +业务事件与读入口在按运营商账户调度时按场景请求检查;场景由代码预置。 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `[].check_types` | array | 检查类型 (card_status:卡状态, carddata:流量, realname:实名) | +| `[].confirm_delays` | array | 延迟确认序列(秒),空表示只立即检查一次 | +| `[].cooldown` | integer | 冷却时长(秒),最近一次成功检查未超过该时长则不请求;空表示不冷却 | +| `[].scene` | string | 场景编码 (order_paid:订单支付, package_activated:套餐激活, stop_resume_succeeded:停复机成功, device_operation:设备操作, auto_renewal_purchase:自动续费购包, client_asset_detail:C 端资产详情, admin_asset_realtime:后台资产实时状态, realname_link:实名链接) | +| `[].scene_name` | string | 场景名称 | +| `[].updated_at` | string | 更新时间 | + +#### `GET /polling-configs/match-preview` 预览卡的轮询配置匹配结果(按当前配置) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `iccid` | string | 是 | 要预览的卡 ICCID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `card` | object | | +| `card.asset_status` | integer | 资产状态 (1:在库, 2:已销售, 3:已换货, 4:已停用) | +| `card.card_category` | string | 卡业务类型 (normal:普通卡, industry:行业卡) | +| `card.card_condition` | string | 卡状态条件 (not_real_name:未实名, activated:已激活, suspended:已停用) | +| `card.card_id` | integer | IoT卡ID | +| `card.carrier_id` | integer | 运营商账户ID | +| `card.enable_polling` | boolean | 是否开启轮询 | +| `card.iccid` | string | ICCID | +| `card.package_state` | string | 套餐状态 (active:有生效套餐, depleted:套餐已用完, pending:只有待生效套餐, none:无套餐),解析失败为空 | +| `card.package_state_name` | string | 套餐状态名称 | +| `intervals` | array | 各检查类型最终结果 | +| `intervals[].config_id` | integer | 给出取值的配置ID | +| `intervals[].config_name` | string | 给出取值的配置名称 | +| `intervals[].inherited` | boolean | 是否继承自非首个命中的配置(首个命中配置该项为空) | +| `intervals[].interval` | integer | 间隔(秒),仅 mode=interval 时有值 | +| `intervals[].mode` | string | 结果 (interval:按间隔检查, disabled:不检查, unmatched:没有任何配置给出取值,不检查) | +| `intervals[].task_type` | string | 检查类型 (polling:realname:实名, polling:carddata:流量, polling:package:套餐, polling:card_status:卡状态) | +| `intervals[].task_type_name` | string | 检查类型名称 | +| `matched` | array | 命中的配置(按优先级、ID 升序) | +| `matched[].config_name` | string | 配置名称 | +| `matched[].draft` | boolean | 是否为预览中的未保存配置 | +| `matched[].id` | integer | 配置ID | +| `matched[].priority` | integer | 优先级 | + +#### `GET /polling-configs/recalculate-due/{task_id}` 查询重算轮询到期时间任务进度 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `task_id` | string | 是 | 重算任务ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `advanced` | integer | 被提前的检查项数 | +| `carrier_id` | string | 限定的运营商账户ID,为空表示全部 | +| `created_at` | string | 创建时间 | +| `error` | string | 失败原因 | +| `finished_at` | string | 结束时间 | +| `processed` | integer | 已处理的卡数 | +| `started_at` | string | 开始时间 | +| `status` | string | 状态 (pending:已入队, running:执行中, completed:已完成, failed:失败) | +| `task_id` | string | 重算任务ID | +| `total` | integer | 需处理的卡数 | + +#### `GET /polling-failure-alerts` 查询卡轮询失败告警列表 + +view=stop_refused 为停机被拒视图:停复机方向为停机,且错误类型为终态或业务错误、或停机失败次数达到停复机告警阈值;该视图只按 carrier_id、status、iccid、start_time、end_time 筛选(忽略 check_type、error_category、alert_level),并额外返回 device_id、network_status、stop_reason、enable_polling、has_package、handled_by_name。导出使用统一导出任务,场景 polling_stop_refused_alert。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `carrier_id` | integer | | 运营商账户ID | +| query | `check_type` | string | | 检查类型 (card_status:卡状态, carddata:流量, realname:实名, package:套餐, stop_resume:停复机, all:账户级) | +| query | `view` | string | | 视图 (stop_refused:停机被拒:停复机方向为停机,且错误类型为终态或业务错误、或停机失败次数达到阈值) | +| query | `error_category` | string | | 错误类别 | +| query | `status` | integer | | 状态 (1:未处理, 2:已恢复, 3:已关闭轮询, 4:已处理) | +| query | `alert_level` | string | | 告警级别 (card:卡级, carrier:账户级) | +| query | `iccid` | string | | ICCID(精确) | +| query | `start_time` | string | | 最近失败时间起始(带时区的 RFC3339 秒级时间) | +| query | `end_time` | string | | 最近失败时间结束(带时区的 RFC3339 秒级时间) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 告警列表 | +| `items[].alert_level` | string | 告警级别 (card:卡级, carrier:账户级) | +| `items[].card_id` | integer | 卡ID,账户级为 0 | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].carrier_name` | string | 运营商账户名称 | +| `items[].check_type` | string | 检查类型 | +| `items[].check_type_name` | string | 检查类型名称 | +| `items[].created_at` | string | 创建时间 | +| `items[].device_id` | integer | 卡绑定的设备ID(停机被拒视图) | +| `items[].enable_polling` | boolean | 卡当前是否轮询(停机被拒视图) | +| `items[].error_category` | string | 最近错误类别 | +| `items[].fail_count` | integer | 连续失败次数;账户级为窗口内告警数 | +| `items[].first_failed_at` | string | 首次失败时间 | +| `items[].handle_remark` | string | 处理备注 | +| `items[].handled_at` | string | 处理时间 | +| `items[].handled_by` | integer | 处理人 | +| `items[].handled_by_name` | string | 处理人(停机被拒视图) | +| `items[].has_package` | boolean | 资产是否有生效中主套餐(停机被拒视图) | +| `items[].iccid` | string | ICCID | +| `items[].id` | integer | 告警ID | +| `items[].last_error` | string | 最近错误 | +| `items[].last_failed_at` | string | 最近失败时间 | +| `items[].network_status` | integer | 卡当前网络状态 (0:停机, 1:开机)(停机被拒视图) | +| `items[].recovered_at` | string | 自动恢复时间 | +| `items[].status` | integer | 状态 (1:未处理, 2:已恢复, 3:已关闭轮询, 4:已处理) | +| `items[].status_name` | string | 状态名称 | +| `items[].stop_reason` | string | 卡当前停机原因(停机被拒视图) | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /polling-failure-alerts/summary` 未处理卡轮询失败告警按运营商账户与错误类别汇总 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `[].carrier_id` | integer | 运营商账户ID | +| `[].carrier_name` | string | 运营商账户名称 | +| `[].error_category` | string | 错误类别 | +| `[].open_count` | integer | 未处理卡级告警数 | + +#### `GET /polling-failure-alerts/{id}` 查询卡轮询失败告警详情 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 告警ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `alert_level` | string | 告警级别 (card:卡级, carrier:账户级) | +| `card_id` | integer | 卡ID,账户级为 0 | +| `carrier_id` | integer | 运营商账户ID | +| `carrier_name` | string | 运营商账户名称 | +| `check_type` | string | 检查类型 | +| `check_type_name` | string | 检查类型名称 | +| `created_at` | string | 创建时间 | +| `device_id` | integer | 卡绑定的设备ID(停机被拒视图) | +| `enable_polling` | boolean | 卡当前是否轮询(停机被拒视图) | +| `error_category` | string | 最近错误类别 | +| `fail_count` | integer | 连续失败次数;账户级为窗口内告警数 | +| `first_failed_at` | string | 首次失败时间 | +| `handle_remark` | string | 处理备注 | +| `handled_at` | string | 处理时间 | +| `handled_by` | integer | 处理人 | +| `handled_by_name` | string | 处理人(停机被拒视图) | +| `has_package` | boolean | 资产是否有生效中主套餐(停机被拒视图) | +| `iccid` | string | ICCID | +| `id` | integer | 告警ID | +| `last_error` | string | 最近错误 | +| `last_failed_at` | string | 最近失败时间 | +| `network_status` | integer | 卡当前网络状态 (0:停机, 1:开机)(停机被拒视图) | +| `recovered_at` | string | 自动恢复时间 | +| `status` | integer | 状态 (1:未处理, 2:已恢复, 3:已关闭轮询, 4:已处理) | +| `status_name` | string | 状态名称 | +| `stop_reason` | string | 卡当前停机原因(停机被拒视图) | + +#### `GET /polling-options` 查询轮询与网关限流枚举 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `error_categories` | array | 上游错误分类类别 | +| `error_categories[].label` | string | 中文名称 | +| `error_categories[].value` | string | 取值 | +| `exempt_sources` | array | 限流豁免来源 | +| `exempt_sources[].label` | string | 中文名称 | +| `exempt_sources[].value` | string | 取值 | +| `gateway_operations` | array | 卡网关操作 | +| `gateway_operations[].label` | string | 中文名称 | +| `gateway_operations[].value` | string | 取值 | +| `match_types` | array | 错误分类匹配方式 | +| `match_types[].label` | string | 中文名称 | +| `match_types[].value` | string | 取值 | +| `rate_limit_modes` | array | 限流模式 | +| `rate_limit_modes[].label` | string | 中文名称 | +| `rate_limit_modes[].value` | string | 取值 | +| `stop_resume_actions` | array | 停复机动作 | +| `stop_resume_actions[].label` | string | 中文名称 | +| `stop_resume_actions[].value` | string | 取值 | +| `stop_resume_results` | array | 停复机记录结果 | +| `stop_resume_results[].label` | string | 中文名称 | +| `stop_resume_results[].value` | string | 取值 | + +#### `GET /polling-rate-limit-groups` 查询网关限流组列表 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `carrier_id` | integer | | 运营商账户ID筛选 | +| query | `only_global` | boolean | | 只看全局组 | +| query | `status` | integer | | 状态 (0:停用, 1:启用) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 限流组列表 | +| `items[].carrier_id` | integer | 运营商账户ID,为空表示全局组 | +| `items[].carrier_name` | string | 运营商账户名称,全局组为空 | +| `items[].created_at` | string | 创建时间 | +| `items[].group_code` | string | 组标识 | +| `items[].group_name` | string | 组名称 | +| `items[].high_priority_operations` | array | 高优先级操作 | +| `items[].id` | integer | 限流组ID | +| `items[].max_qps` | integer | 每秒请求上限 | +| `items[].operations` | array | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `items[].reserved_qps` | integer | 预留给高优先级操作的额度 | +| `items[].status` | integer | 状态 (0:停用, 1:启用) | +| `items[].status_name` | string | 状态名称 | +| `items[].updated_at` | string | 更新时间 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /polling-rate-limit-groups/{id}` 查询网关限流组详情 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carrier_id` | integer | 运营商账户ID,为空表示全局组 | +| `carrier_name` | string | 运营商账户名称,全局组为空 | +| `created_at` | string | 创建时间 | +| `group_code` | string | 组标识 | +| `group_name` | string | 组名称 | +| `high_priority_operations` | array | 高优先级操作 | +| `id` | integer | 限流组ID | +| `max_qps` | integer | 每秒请求上限 | +| `operations` | array | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `reserved_qps` | integer | 预留给高优先级操作的额度 | +| `status` | integer | 状态 (0:停用, 1:启用) | +| `status_name` | string | 状态名称 | +| `updated_at` | string | 更新时间 | + +#### `GET /polling-stats/carrier-queues` 按运营商账户的轮询队列与执行监控 + +按运营商账户调度的各账户队列长度、已到期数、执行中、上一分钟 QPS、限流等待与拒绝、处理中标记到期、未处理告警;停复机指令队列长度、已到期、执行中、待确认,近 1 小时停复机成功、失败、重试、结果未知数。 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `init_state` | string | 新结构初始化状态 (running / done,空表示未初始化) | +| `items` | array | 各运营商账户监控 | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].carrier_name` | string | 运营商账户名称 | +| `items[].due_count` | integer | 已到期卡数(优先 + 普通) | +| `items[].expired_claims_1h` | integer | 近 1 小时处理中标记到期次数(执行崩溃或超时) | +| `items[].inflight_limit` | integer | 执行上限 | +| `items[].open_alerts` | integer | 未处理卡级失败告警数 | +| `items[].open_alerts_by_category` | object | 未处理卡级失败告警数(按错误类别) | +| `items[].priority_length` | integer | 优先队列长度 | +| `items[].qps_last_minute` | number | 上一分钟实际网关调用 QPS(查询类) | +| `items[].queue_length` | integer | 普通队列长度 | +| `items[].rate_limit_waits` | integer | 上一分钟限流等待次数 | +| `items[].rate_limited` | integer | 上一分钟限流拒绝或等待超时次数 | +| `items[].running` | integer | 执行中卡任务数 | +| `items[].stop_resume_due` | integer | 已到期停复机指令数 | +| `items[].stop_resume_failed_1h` | integer | 近 1 小时停复机失败数(计入连续失败或终态) | +| `items[].stop_resume_pending` | integer | 结果未知待确认的停复机指令数(按队列前 500 条统计) | +| `items[].stop_resume_queue_length` | integer | 停复机指令队列长度 | +| `items[].stop_resume_retry_1h` | integer | 近 1 小时停复机推后重试数(限流、频率限制、最小间隔) | +| `items[].stop_resume_running` | integer | 执行中停复机指令数 | +| `items[].stop_resume_success_1h` | integer | 近 1 小时停复机成功数 | +| `items[].stop_resume_unknown_1h` | integer | 近 1 小时停复机结果未知数 | +| `scheduler_mode` | string | 当前调度模式 | + +#### `GET /polling-stats/carriers` 按运营商账户汇总网关调用 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `minutes` | integer | | 统计最近多少分钟,默认 15,最大 60 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carriers` | array | 有调用的运营商账户汇总 | +| `carriers[].carrier_id` | integer | 运营商账户ID(0 表示无法解析账户的卡) | +| `carriers[].carrier_name` | string | 运营商账户名称 | +| `carriers[].operations` | array | 各操作汇总 | +| `carriers[].operations[].attempts` | integer | 实际发出的请求数 | +| `carriers[].operations[].avg_duration_ms` | number | 平均耗时(毫秒) | +| `carriers[].operations[].avg_qps` | number | 平均每秒请求数 | +| `carriers[].operations[].exempt` | object | 按豁免来源的调用量 (manual_click/channel_threshold/auto_renewal/manual_refresh) | +| `carriers[].operations[].failures` | object | 按错误类别的失败数(network/timeout/http/invalid_response/upstream:<类别>) | +| `carriers[].operations[].operation` | string | 操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `carriers[].operations[].operation_name` | string | 操作名称 | +| `carriers[].operations[].p95_duration_ms` | integer | p95 耗时上界(毫秒,按分桶近似),-1 表示超过最大分桶 | +| `carriers[].operations[].peak_minute_qps` | number | 峰值分钟的平均每秒请求数 | +| `carriers[].operations[].rate_limited` | integer | 被限流拒绝的次数(拦截模式) | +| `carriers[].operations[].success` | integer | 成功数 | +| `carriers[].operations[].success_rate` | number | 成功率(0~1) | +| `carriers[].operations[].would_limit` | integer | 超过限流组上限的次数(只统计模式下为本应被限流次数) | +| `minutes` | integer | 统计窗口(分钟) | +| `mode` | string | 当前限流模式 (observe:只统计, enforce:拦截) | + +#### `GET /polling-stats/carriers/{carrier_id}/trend` 查询单个运营商账户的网关调用趋势 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `minutes` | integer | | 统计最近多少分钟,默认 60,最大 10080(7 天) | +| query | `bucket_minutes` | integer | | 聚合粒度(分钟),默认 1 | +| path | `carrier_id` | integer | 是 | 运营商账户ID(0 表示无法解析账户的卡) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carrier_id` | integer | 运营商账户ID | +| `points` | array | 时间桶列表 | +| `points[].operations` | array | 各操作在该时间桶的汇总 | +| `points[].operations[].attempts` | integer | 实际发出的请求数 | +| `points[].operations[].avg_duration_ms` | number | 平均耗时(毫秒) | +| `points[].operations[].avg_qps` | number | 平均每秒请求数 | +| `points[].operations[].exempt` | object | 按豁免来源的调用量 (manual_click/channel_threshold/auto_renewal/manual_refresh) | +| `points[].operations[].failures` | object | 按错误类别的失败数(network/timeout/http/invalid_response/upstream:<类别>) | +| `points[].operations[].operation` | string | 操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `points[].operations[].operation_name` | string | 操作名称 | +| `points[].operations[].p95_duration_ms` | integer | p95 耗时上界(毫秒,按分桶近似),-1 表示超过最大分桶 | +| `points[].operations[].peak_minute_qps` | number | 峰值分钟的平均每秒请求数 | +| `points[].operations[].rate_limited` | integer | 被限流拒绝的次数(拦截模式) | +| `points[].operations[].success` | integer | 成功数 | +| `points[].operations[].success_rate` | number | 成功率(0~1) | +| `points[].operations[].would_limit` | integer | 超过限流组上限的次数(只统计模式下为本应被限流次数) | +| `points[].time` | string | 时间桶起点(上海时区,yyyy-MM-dd HH:mm) | + +#### `GET /polling-stats/pre-reset` 重置日前加密查流量效果统计 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carriers` | array | 有开启轮询卡的运营商账户 | +| `carriers[].carrier_id` | integer | 运营商账户ID | +| `carriers[].carrier_name` | string | 运营商账户名称 | +| `carriers[].previous` | object | | +| `carriers[].previous.active_package_cards` | integer | 当前有生效套餐的轮询卡数 | +| `carriers[].previous.checked_in_window` | integer | 窗口内查到过流量的卡数(近似去重计数) | +| `carriers[].previous.last_offset_buckets` | object | 每张卡窗口内最后一次查询距重置时刻的分布(分钟):le_5/le_15/le_30/le_60/gt_60 | +| `carriers[].previous.not_checked_in_window` | integer | 有生效套餐但窗口内未查到流量的卡数(近似,最小为 0) | +| `carriers[].previous.reset_at` | string | 重置时刻(上海时区) | +| `carriers[].upcoming` | object | | +| `carriers[].upcoming.active_package_cards` | integer | 当前有生效套餐的轮询卡数 | +| `carriers[].upcoming.checked_in_window` | integer | 窗口内查到过流量的卡数(近似去重计数) | +| `carriers[].upcoming.last_offset_buckets` | object | 每张卡窗口内最后一次查询距重置时刻的分布(分钟):le_5/le_15/le_30/le_60/gt_60 | +| `carriers[].upcoming.not_checked_in_window` | integer | 有生效套餐但窗口内未查到流量的卡数(近似,最小为 0) | +| `carriers[].upcoming.reset_at` | string | 重置时刻(上海时区) | + +#### `GET /polling-stats/tiers` 分层轮询统计(结果缓存 5 分钟) + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `by_config` | array | 按首个命中配置统计 | +| `by_config[].cards` | integer | 卡数 | +| `by_config[].config_id` | integer | 首个命中的配置ID,0 表示未匹配任何配置 | +| `by_config[].config_name` | string | 首个命中的配置名称 | +| `by_package_state` | object | 按套餐状态统计 (active/depleted/pending/none/unknown) | +| `computed_at` | string | 统计时间(结果缓存 5 分钟) | +| `total_cards` | integer | 开启轮询的卡数 | +| `unmatched_in_stock` | integer | 未匹配任何配置的在库卡数(应告警) | +| `unmatched_sold_no_package` | integer | 未匹配任何配置的已销售无套餐卡数(应告警) | + +#### `GET /polling-status-imports` 查询轮询开关导入任务 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `page` | integer | | 页码 | +| query | `page_size` | integer | | 每页数量 | +| query | `status` | integer | | 任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 任务列表 | +| `items[].asset_type` | string | 资产类型 (iot_card:卡, device:设备) | +| `items[].completed_at` | string | 完成时间 | +| `items[].created_at` | string | 创建时间 | +| `items[].creator_name` | string | 创建人 | +| `items[].enable_polling` | boolean | 目标状态 | +| `items[].error_message` | string | 任务级失败原因 | +| `items[].fail_count` | integer | 失败行数 | +| `items[].file_name` | string | 文件名 | +| `items[].id` | integer | 任务ID | +| `items[].reason` | string | 原因 | +| `items[].skip_count` | integer | 跳过行数 | +| `items[].started_at` | string | 开始处理时间 | +| `items[].status` | integer | 任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败) | +| `items[].status_name` | string | 任务状态名称 | +| `items[].success_count` | integer | 成功行数 | +| `items[].task_no` | string | 任务编号 | +| `items[].total_count` | integer | 数据行数 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `total` | integer | 总数 | + +#### `GET /polling-status-imports/{id}` 查询轮询开关导入任务详情(含逐行结果) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 导入任务ID | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `asset_type` | string | 资产类型 (iot_card:卡, device:设备) | +| `completed_at` | string | 完成时间 | +| `created_at` | string | 创建时间 | +| `creator_name` | string | 创建人 | +| `enable_polling` | boolean | 目标状态 | +| `error_message` | string | 任务级失败原因 | +| `fail_count` | integer | 失败行数 | +| `file_name` | string | 文件名 | +| `id` | integer | 任务ID | +| `items` | array | 逐行结果 | +| `items[].asset_id` | integer | 资产ID(未找到为 0) | +| `items[].identifier` | string | ICCID 或 IMEI | +| `items[].line` | integer | 行号(自数据首行起计) | +| `items[].reason` | string | 跳过或失败原因 | +| `items[].status` | integer | 结果 (1:成功, 2:跳过, 3:失败, 4:无权限或资产不存在) | +| `items[].status_name` | string | 结果名称 | +| `reason` | string | 原因 | +| `skip_count` | integer | 跳过行数 | +| `started_at` | string | 开始处理时间 | +| `status` | integer | 任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败) | +| `status_name` | string | 任务状态名称 | +| `success_count` | integer | 成功行数 | +| `task_no` | string | 任务编号 | +| `total_count` | integer | 数据行数 | + +#### `GET /polling-status/impact` 开关轮询影响说明 + +供前端关闭与开启轮询的确认框展示。 + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `disable` | array | 关闭轮询的影响 | +| `enable` | array | 开启轮询的影响 | + +#### `GET /stop-resume-rule/dry-run` 停复机规则演练 + +对全部开机与停机卡按停复机新规则只判断不执行(不调用网关、不写任何状态),不受停复机总开关影响。返回按运营商账户 × 当前停机原因 × 判断结果 × 原因的汇总,以及按卡ID升序的分页明细;可按运营商账户与停机原因筛选,可用 assume_control_on / assume_control_off 假设通道实名管控配置预演。全量扫描较慢,生产使用请按运营商账户筛选或使用导出。仅超级管理员与平台账号可用。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| query | `carrier_id` | integer | | 运营商账户ID,不传为全部 | +| query | `stop_reason` | string | | 停机原因筛选:传停机原因编码(如 not_realname、carrier_stopped、manual),传 none 表示停机原因为空,不传为全部 | +| query | `assume_control_on` | string | | 假设开启实名管控的运营商账户ID,逗号分隔;只用于预演,不改实际配置 | +| query | `assume_control_off` | string | | 假设关闭实名管控的运营商账户ID,逗号分隔;只用于预演,不改实际配置 | +| query | `result` | string | | 明细按判断结果筛选 (will_resume:将复机, will_stop:将停机, no_action:不动作),汇总不受影响 | +| query | `page` | integer | | 明细页码,默认1 | +| query | `page_size` | integer | | 明细每页数量,默认20,最大500 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `items` | array | 明细(按卡ID升序分页) | +| `items[].card_category` | string | 卡类别 | +| `items[].card_id` | integer | 卡ID | +| `items[].carrier_id` | integer | 运营商账户ID | +| `items[].carrier_name` | string | 运营商账户名称 | +| `items[].device_id` | integer | 有效绑定设备ID,独立卡为 0 | +| `items[].iccid` | string | ICCID | +| `items[].network_status` | integer | 当前网络状态 (0:停机, 1:开机) | +| `items[].realname_ok` | boolean | 按(假设的)通道实名管控是否满足实名条件 | +| `items[].reason` | string | 将停机时为目标停机原因,不动作时为不动作原因 | +| `items[].reason_name` | string | 原因名称 | +| `items[].result` | string | 判断结果 | +| `items[].result_name` | string | 判断结果名称 | +| `items[].stop_reason` | string | 当前停机原因 | +| `items[].stop_reason_name` | string | 当前停机原因名称 | +| `page` | integer | 当前页 | +| `size` | integer | 每页数量 | +| `summary` | array | 按运营商账户 × 当前停机原因 × 判断结果 × 原因汇总 | +| `summary[].carrier_id` | integer | 运营商账户ID | +| `summary[].carrier_name` | string | 运营商账户名称 | +| `summary[].count` | integer | 卡数 | +| `summary[].reason` | string | 将停机时为目标停机原因,不动作时为不动作原因 (polling_suspended:暂停轮询, conditions_met:满足开机条件, no_package:无套餐, traffic_exhausted:流量已用完, not_realname:未实名, threshold_locked:持通道阈值锁, carrier_missing:所属通道不存在) | +| `summary[].reason_name` | string | 原因名称 | +| `summary[].result` | string | 判断结果 (will_resume:将复机, will_stop:将停机, no_action:不动作) | +| `summary[].result_name` | string | 判断结果名称 | +| `summary[].stop_reason` | string | 当前停机原因,空表示无 | +| `summary[].stop_reason_name` | string | 当前停机原因名称 | +| `total` | integer | 明细总数(按 result 筛选后) | +| `totals` | object | | +| `totals.no_action` | integer | 不动作卡数 | +| `totals.total` | integer | 参与演练的开机与停机卡数 | +| `totals.will_resume` | integer | 将复机卡数 | +| `totals.will_stop` | integer | 将停机卡数 | + +#### `POST /devices/batch-update-polling-status` 勾选批量开关设备轮询 + +单次最多500个;设备沿用级联到设备下各卡(开启时跳过风险停机、已销户的卡)。 + +**关闭轮询的影响**:关闭后不再查询上游卡状态、流量与实名;流量用完、实名不满足时不自动停机,套餐激活、流量重置后不自动复机; +套餐到期、退款后无可用套餐时仍会自动停机;订单套餐生效、后台修改有效期后资产有生效套餐时会自动恢复轮询并按规则复机;人工停复机照常;设备关闭时设备下所有卡同样适用。 + +**开启轮询的影响**:按轮询配置查询上游并按规则自动停复机,人工停机不享有豁免;网关扩展状态为风险停机或已销户的卡不能开启轮询(逐项返回跳过原因,不提供强制参数)。 + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `asset_ids` | array | | 资产ID列表(卡ID或设备ID),单次最多500个,不能重复 | +| `enable_polling` | boolean | | 目标状态 (true:开启轮询, false:关闭轮询) | +| `reason` | string | | 原因,写入不轮询清单 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `fail_count` | integer | 失败数(含无权限或资产不存在) | +| `impact` | array | 本次目标状态的影响说明 | +| `items` | array | 逐项结果 | +| `items[].asset_id` | integer | 资产ID | +| `items[].identifier` | string | 资产标识(卡为 ICCID,设备为 IMEI 或虚拟号) | +| `items[].reason` | string | 跳过或失败原因 | +| `items[].status` | integer | 结果 (1:成功, 2:跳过, 3:失败, 4:无权限或资产不存在) | +| `items[].status_name` | string | 结果名称 | +| `skip_count` | integer | 跳过数(已是目标状态、风险停机或已销户不能开启) | +| `success_count` | integer | 成功数 | + +#### `POST /gateway-error-classifications` 新建上游错误分类规则(仅超级管理员) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `auto_disable_polling` | boolean | | 命中后自动关闭该卡轮询(停复机不重试、回写网关扩展状态),仅类别为 terminal 时可勾选;更新时不传保留原值 | +| `category` | string | 是 | 类别 (rate_limited_upstream:上游频率限制, terminal:终态不可操作, already_target:已是目标状态, transient:临时故障, business:业务错误, account_config:账户配置错误) | +| `keyword` | string | 是 | 匹配关键字或正则 | +| `match_type` | string | 是 | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `maybe_accepted` | boolean | | 上游可能已受理(如返回含调用成功、操作进行中、请求被合并) | +| `operations` | array | | 适用操作,为空表示全部 | +| `priority` | integer | | 匹配优先级,越小越先匹配 | +| `remark` | string | | 备注 | +| `status` | integer | | 状态 (0:停用, 1:启用),新建默认启用 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `auto_disable_polling` | boolean | 命中后自动关闭该卡轮询 | +| `category` | string | 类别 | +| `category_name` | string | 类别名称 | +| `created_at` | string | 创建时间 | +| `id` | integer | 规则ID | +| `keyword` | string | 匹配关键字或正则 | +| `match_type` | string | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `maybe_accepted` | boolean | 上游可能已受理 | +| `operations` | array | 适用操作,为空表示全部 | +| `priority` | integer | 匹配优先级 | +| `remark` | string | 备注 | +| `status` | integer | 状态 (0:停用, 1:启用) | +| `updated_at` | string | 更新时间 | + +#### `POST /gateway-error-classifications/test` 测试上游错误分类(不写数据) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `draft` | object | | | +| `draft.auto_disable_polling` | boolean | | 命中后自动关闭该卡轮询(停复机不重试、回写网关扩展状态),仅类别为 terminal 时可勾选;更新时不传保留原值 | +| `draft.category` | string | 是 | 类别 (rate_limited_upstream:上游频率限制, terminal:终态不可操作, already_target:已是目标状态, transient:临时故障, business:业务错误, account_config:账户配置错误) | +| `draft.keyword` | string | 是 | 匹配关键字或正则 | +| `draft.match_type` | string | 是 | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `draft.maybe_accepted` | boolean | | 上游可能已受理(如返回含调用成功、操作进行中、请求被合并) | +| `draft.operations` | array | | 适用操作,为空表示全部 | +| `draft.priority` | integer | | 匹配优先级,越小越先匹配 | +| `draft.remark` | string | | 备注 | +| `draft.status` | integer | | 状态 (0:停用, 1:启用),新建默认启用 | +| `message` | string | 是 | 上游返回信息 | +| `operation` | string | 是 | 操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `auto_disable_polling` | boolean | 命中后自动关闭该卡轮询 | +| `category` | string | 命中类别 | +| `category_name` | string | 命中类别名称 | +| `keyword` | string | 命中关键字,未命中为空 | +| `matched` | boolean | 是否命中规则;未命中时按业务错误处理 | +| `maybe_accepted` | boolean | 上游可能已受理 | +| `rule_id` | integer | 命中规则ID,未命中或命中草稿为 0 | + +#### `POST /iot-cards/batch-update-polling-status` 勾选批量开关卡轮询 + +单次最多500个;按数据权限逐项处理并返回结果,每项同事务写轮询开关、不轮询清单与审计。 + +**关闭轮询的影响**:关闭后不再查询上游卡状态、流量与实名;流量用完、实名不满足时不自动停机,套餐激活、流量重置后不自动复机; +套餐到期、退款后无可用套餐时仍会自动停机;订单套餐生效、后台修改有效期后资产有生效套餐时会自动恢复轮询并按规则复机;人工停复机照常;设备关闭时设备下所有卡同样适用。 + +**开启轮询的影响**:按轮询配置查询上游并按规则自动停复机,人工停机不享有豁免;网关扩展状态为风险停机或已销户的卡不能开启轮询(逐项返回跳过原因,不提供强制参数)。 + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `asset_ids` | array | | 资产ID列表(卡ID或设备ID),单次最多500个,不能重复 | +| `enable_polling` | boolean | | 目标状态 (true:开启轮询, false:关闭轮询) | +| `reason` | string | | 原因,写入不轮询清单 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `fail_count` | integer | 失败数(含无权限或资产不存在) | +| `impact` | array | 本次目标状态的影响说明 | +| `items` | array | 逐项结果 | +| `items[].asset_id` | integer | 资产ID | +| `items[].identifier` | string | 资产标识(卡为 ICCID,设备为 IMEI 或虚拟号) | +| `items[].reason` | string | 跳过或失败原因 | +| `items[].status` | integer | 结果 (1:成功, 2:跳过, 3:失败, 4:无权限或资产不存在) | +| `items[].status_name` | string | 结果名称 | +| `skip_count` | integer | 跳过数(已是目标状态、风险停机或已销户不能开启) | +| `success_count` | integer | 成功数 | + +#### `POST /polling-configs/match-preview` 预览卡的轮询配置匹配结果(可带未保存修改,不写数据) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `iccid` | string | 是 | 要预览的卡 ICCID | +| `overrides` | array | | 未保存的修改,不写任何数据 | +| `overrides[].asset_status` | integer | | 资产状态匹配 (1:在库, 2:已销售, 3:已换货, 4:已停用),为空不限 | +| `overrides[].card_category` | string | | 卡业务类型 (normal:普通卡, industry:行业卡),为空不限 | +| `overrides[].card_condition` | string | | 卡状态条件 (not_real_name:未实名, activated:已激活, suspended:已停用),为空不限 | +| `overrides[].card_status_check_interval` | integer | | 卡状态检查间隔(秒),正数按间隔、0 不检查、空继承 | +| `overrides[].carddata_check_interval` | integer | | 流量检查间隔(秒),正数按间隔、0 不检查、空继承 | +| `overrides[].carrier_id` | integer | | 运营商账户ID,为空不限 | +| `overrides[].config_name` | string | | 草稿配置名称 | +| `overrides[].disabled` | boolean | | 假设该配置停用(不参与匹配),为 true 时其余字段忽略 | +| `overrides[].id` | integer | | 要覆盖的配置 ID,0 表示新增一条草稿配置 | +| `overrides[].package_check_interval` | integer | | 套餐检查间隔(秒),正数按间隔、0 不检查、空继承 | +| `overrides[].package_state` | string | | 套餐状态匹配 (active:有生效套餐, depleted:套餐已用完, pending:只有待生效套餐, none:无套餐),为空不限 | +| `overrides[].pre_reset_carddata_interval` | integer | | 重置日前窗口内的流量检查间隔(秒),与窗口长度同时配置才生效 | +| `overrides[].pre_reset_window` | integer | | 重置日前加密窗口长度(秒),与窗口内流量间隔同时配置才生效 | +| `overrides[].priority` | integer | | 优先级(数字越小越优先;与已有配置相同时排在已有配置之后) | +| `overrides[].realname_check_interval` | integer | | 实名检查间隔(秒),正数按间隔、0 不检查、空继承 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `card` | object | | +| `card.asset_status` | integer | 资产状态 (1:在库, 2:已销售, 3:已换货, 4:已停用) | +| `card.card_category` | string | 卡业务类型 (normal:普通卡, industry:行业卡) | +| `card.card_condition` | string | 卡状态条件 (not_real_name:未实名, activated:已激活, suspended:已停用) | +| `card.card_id` | integer | IoT卡ID | +| `card.carrier_id` | integer | 运营商账户ID | +| `card.enable_polling` | boolean | 是否开启轮询 | +| `card.iccid` | string | ICCID | +| `card.package_state` | string | 套餐状态 (active:有生效套餐, depleted:套餐已用完, pending:只有待生效套餐, none:无套餐),解析失败为空 | +| `card.package_state_name` | string | 套餐状态名称 | +| `intervals` | array | 各检查类型最终结果 | +| `intervals[].config_id` | integer | 给出取值的配置ID | +| `intervals[].config_name` | string | 给出取值的配置名称 | +| `intervals[].inherited` | boolean | 是否继承自非首个命中的配置(首个命中配置该项为空) | +| `intervals[].interval` | integer | 间隔(秒),仅 mode=interval 时有值 | +| `intervals[].mode` | string | 结果 (interval:按间隔检查, disabled:不检查, unmatched:没有任何配置给出取值,不检查) | +| `intervals[].task_type` | string | 检查类型 (polling:realname:实名, polling:carddata:流量, polling:package:套餐, polling:card_status:卡状态) | +| `intervals[].task_type_name` | string | 检查类型名称 | +| `matched` | array | 命中的配置(按优先级、ID 升序) | +| `matched[].config_name` | string | 配置名称 | +| `matched[].draft` | boolean | 是否为预览中的未保存配置 | +| `matched[].id` | integer | 配置ID | +| `matched[].priority` | integer | 优先级 | + +#### `POST /polling-configs/recalculate-due` 立即重算轮询到期时间(异步,只提前不推后,仅超级管理员) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `carrier_id` | integer | | 只处理该运营商账户的卡,为空处理全部开启轮询的卡 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `advanced` | integer | 被提前的检查项数 | +| `carrier_id` | string | 限定的运营商账户ID,为空表示全部 | +| `created_at` | string | 创建时间 | +| `error` | string | 失败原因 | +| `finished_at` | string | 结束时间 | +| `processed` | integer | 已处理的卡数 | +| `started_at` | string | 开始时间 | +| `status` | string | 状态 (pending:已入队, running:执行中, completed:已完成, failed:失败) | +| `task_id` | string | 重算任务ID | +| `total` | integer | 需处理的卡数 | + +#### `POST /polling-failure-alerts/close-polling` 告警页勾选批量关闭轮询(仅平台账号) + +单次最多500条;关闭告警对应卡的轮询,清单来源记"停机被拒告警处理",告警状态改为已关闭轮询。停机被拒视图:GET /polling-failure-alerts?view=stop_refused,导出场景 polling_stop_refused_alert。 + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `alert_ids` | array | | 告警ID列表,单次最多500个 | +| `reason` | string | | 原因,写入不轮询清单 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `fail_count` | integer | 失败数(含无权限或资产不存在) | +| `impact` | array | 本次目标状态的影响说明 | +| `items` | array | 逐项结果 | +| `items[].asset_id` | integer | 资产ID | +| `items[].identifier` | string | 资产标识(卡为 ICCID,设备为 IMEI 或虚拟号) | +| `items[].reason` | string | 跳过或失败原因 | +| `items[].status` | integer | 结果 (1:成功, 2:跳过, 3:失败, 4:无权限或资产不存在) | +| `items[].status_name` | string | 结果名称 | +| `skip_count` | integer | 跳过数(已是目标状态、风险停机或已销户不能开启) | +| `success_count` | integer | 成功数 | + +#### `POST /polling-rate-limit-groups` 新建网关限流组(仅超级管理员) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `carrier_id` | integer | | 运营商账户ID,为空表示全局组 | +| `group_code` | string | 是 | 组标识,同一账户内唯一 | +| `group_name` | string | 是 | 组名称 | +| `high_priority_operations` | array | | 高优先级操作,必须属于组内操作,设置预留额度时必填 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `max_qps` | integer | 是 | 每秒请求上限 | +| `operations` | array | 是 | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `reserved_qps` | integer | | 预留给高优先级操作的额度,须小于每秒请求上限 | +| `status` | integer | | 状态 (0:停用, 1:启用),新建默认启用 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carrier_id` | integer | 运营商账户ID,为空表示全局组 | +| `carrier_name` | string | 运营商账户名称,全局组为空 | +| `created_at` | string | 创建时间 | +| `group_code` | string | 组标识 | +| `group_name` | string | 组名称 | +| `high_priority_operations` | array | 高优先级操作 | +| `id` | integer | 限流组ID | +| `max_qps` | integer | 每秒请求上限 | +| `operations` | array | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `reserved_qps` | integer | 预留给高优先级操作的额度 | +| `status` | integer | 状态 (0:停用, 1:启用) | +| `status_name` | string | 状态名称 | +| `updated_at` | string | 更新时间 | + +#### `POST /polling-status-imports` 创建轮询开关文件导入任务(仅平台账号) + +先调用 POST /api/admin/storage/upload-url(purpose 传 polling_status_import)上传 CSV;首行为表头,首列为 ICCID(卡)或 IMEI/虚拟号(设备)。异步逐行处理,规则同勾选批量,部分成功不回滚。 + +**关闭轮询的影响**:关闭后不再查询上游卡状态、流量与实名;流量用完、实名不满足时不自动停机,套餐激活、流量重置后不自动复机; +套餐到期、退款后无可用套餐时仍会自动停机;订单套餐生效、后台修改有效期后资产有生效套餐时会自动恢复轮询并按规则复机;人工停复机照常;设备关闭时设备下所有卡同样适用。 + +**开启轮询的影响**:按轮询配置查询上游并按规则自动停复机,人工停机不享有豁免;网关扩展状态为风险停机或已销户的卡不能开启轮询(逐项返回跳过原因,不提供强制参数)。 + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `asset_type` | string | | 资产类型 (iot_card:按 ICCID, device:按 IMEI 或虚拟号) | +| `enable_polling` | boolean | | 目标状态 (true:开启轮询, false:关闭轮询) | +| `file_key` | string | | 已上传的 CSV 文件 Key(必须以 polling-status-imports/ 开头);首列为 ICCID(卡)或 IMEI/虚拟号(设备),首行为表头 | +| `reason` | string | | 原因,写入不轮询清单 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `asset_type` | string | 资产类型 (iot_card:卡, device:设备) | +| `completed_at` | string | 完成时间 | +| `created_at` | string | 创建时间 | +| `creator_name` | string | 创建人 | +| `enable_polling` | boolean | 目标状态 | +| `error_message` | string | 任务级失败原因 | +| `fail_count` | integer | 失败行数 | +| `file_name` | string | 文件名 | +| `id` | integer | 任务ID | +| `reason` | string | 原因 | +| `skip_count` | integer | 跳过行数 | +| `started_at` | string | 开始处理时间 | +| `status` | integer | 任务状态 (1:待处理, 2:处理中, 3:已完成, 4:失败) | +| `status_name` | string | 任务状态名称 | +| `success_count` | integer | 成功行数 | +| `task_no` | string | 任务编号 | +| `total_count` | integer | 数据行数 | + +#### `POST /stop-resume-rule/dry-run/export` 导出停复机规则演练明细 + +创建异步导出任务(场景 stop_resume_rule_dry_run),一行对应一张卡的判断结果;筛选与假设配置同演练接口。仅超级管理员与平台账号可用。 + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `assume_control_off` | string | | 假设关闭实名管控的运营商账户ID,逗号分隔 | +| `assume_control_on` | string | | 假设开启实名管控的运营商账户ID,逗号分隔 | +| `carrier_id` | integer | | 运营商账户ID,不传为全部 | +| `format` | string | | 导出格式 (xlsx:Excel, csv:CSV),默认 xlsx | +| `stop_reason` | string | | 停机原因筛选,none 表示停机原因为空 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `message` | string | 提示信息 | +| `status` | integer | 任务状态 (1:待处理, 2:处理中, 3:已完成, 4:已失败, 5:已取消) | +| `status_name` | string | 任务状态名称(中文) | +| `task_id` | integer | 导出任务ID | +| `task_no` | string | 任务编号 | + +#### `PUT /gateway-error-classifications/{id}` 修改上游错误分类规则(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `auto_disable_polling` | boolean | | 命中后自动关闭该卡轮询(停复机不重试、回写网关扩展状态),仅类别为 terminal 时可勾选;更新时不传保留原值 | +| `category` | string | 是 | 类别 (rate_limited_upstream:上游频率限制, terminal:终态不可操作, already_target:已是目标状态, transient:临时故障, business:业务错误, account_config:账户配置错误) | +| `keyword` | string | 是 | 匹配关键字或正则 | +| `match_type` | string | 是 | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `maybe_accepted` | boolean | | 上游可能已受理(如返回含调用成功、操作进行中、请求被合并) | +| `operations` | array | | 适用操作,为空表示全部 | +| `priority` | integer | | 匹配优先级,越小越先匹配 | +| `remark` | string | | 备注 | +| `status` | integer | | 状态 (0:停用, 1:启用),新建默认启用 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `auto_disable_polling` | boolean | 命中后自动关闭该卡轮询 | +| `category` | string | 类别 | +| `category_name` | string | 类别名称 | +| `created_at` | string | 创建时间 | +| `id` | integer | 规则ID | +| `keyword` | string | 匹配关键字或正则 | +| `match_type` | string | 匹配方式 (contains:包含, prefix:前缀, regex:正则) | +| `maybe_accepted` | boolean | 上游可能已受理 | +| `operations` | array | 适用操作,为空表示全部 | +| `priority` | integer | 匹配优先级 | +| `remark` | string | 备注 | +| `status` | integer | 状态 (0:停用, 1:启用) | +| `updated_at` | string | 更新时间 | + +#### `PUT /gateway-error-classifications/{id}/status` 启停上游错误分类规则(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 规则ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `status` | integer | 是 | 状态 (0:停用, 1:启用) | + +#### `PUT /polling-carrier-params/{carrier_id}` 保存运营商账户调度参数(仅超级管理员) + +字段为空表示该项使用全局默认;执行上限不得大于当前订阅进程 max_in_flight 之和;下一轮调度生效并写统一审计。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `carrier_id` | integer | 是 | 运营商账户ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `card_max_in_flight` | integer | | 每进程卡任务 max_in_flight,空表示默认 | +| `inflight_limit` | integer | | 执行上限,空表示默认 | +| `priority_max_ratio` | number | | 优先队列每轮最大占比(0~1],空表示不限 | +| `sr_inflight_limit` | integer | | 停复机执行上限,空表示默认 | +| `stop_resume_confirm_delay` | integer | | 停复机结果未知确认延迟(秒),空表示默认 | +| `stop_resume_max_in_flight` | integer | | 每进程停复机 max_in_flight,空表示默认 | +| `stop_resume_min_interval` | integer | | 单卡停复机最小间隔(秒),空表示默认 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `card_max_in_flight` | integer | 生效的每进程卡任务 max_in_flight | +| `carrier_id` | integer | 运营商账户ID | +| `carrier_name` | string | 运营商账户名称 | +| `configured_card_max_in_flight` | integer | 单独配置的每进程 max_in_flight,空表示使用默认 | +| `configured_inflight_limit` | integer | 单独配置的执行上限,空表示使用默认 | +| `consume_capacity` | integer | 当前订阅进程 max_in_flight 之和(执行上限不应超过该值) | +| `inflight_limit` | integer | 生效的执行上限(跨 Worker 实例同时执行卡任务数) | +| `is_default` | boolean | 是否未单独配置、全部使用全局默认 | +| `priority_max_ratio` | number | 优先队列每轮最大占比(0~1),空表示不限 | +| `sr_inflight_limit` | integer | 停复机执行上限(停复机指令队列使用),空表示默认 | +| `stop_resume_confirm_delay` | integer | 停复机结果未知后确认延迟(秒),空表示默认 | +| `stop_resume_max_in_flight` | integer | 每进程停复机 max_in_flight(停复机指令队列使用),空表示默认 | +| `stop_resume_min_interval` | integer | 单卡两次停复机调用最小间隔(秒),空表示默认 | + +#### `PUT /polling-check-scenes/{scene}` 修改请求检查场景(仅超级管理员) + +只可修改检查类型、延迟确认序列(递增)与冷却时长。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `scene` | string | 是 | 场景编码 | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `check_types` | array | 是 | 检查类型 (card_status:卡状态, carddata:流量, realname:实名) | +| `confirm_delays` | array | | 延迟确认序列(秒,递增),空表示只立即检查一次 | +| `cooldown` | integer | | 冷却时长(秒),空表示不冷却 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `check_types` | array | 检查类型 (card_status:卡状态, carddata:流量, realname:实名) | +| `confirm_delays` | array | 延迟确认序列(秒),空表示只立即检查一次 | +| `cooldown` | integer | 冷却时长(秒),最近一次成功检查未超过该时长则不请求;空表示不冷却 | +| `scene` | string | 场景编码 (order_paid:订单支付, package_activated:套餐激活, stop_resume_succeeded:停复机成功, device_operation:设备操作, auto_renewal_purchase:自动续费购包, client_asset_detail:C 端资产详情, admin_asset_realtime:后台资产实时状态, realname_link:实名链接) | +| `scene_name` | string | 场景名称 | +| `updated_at` | string | 更新时间 | + +#### `PUT /polling-configs/priorities` 整体调整轮询配置优先级(仅超级管理员) + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `ordered_ids` | array | 是 | 按期望生效顺序排列的配置 ID 列表(排在前面的优先级更高);ID 须为正整数且不重复;系统按顺序把优先级重排为 1、2、3…,未列出的配置保持原优先级 | + +#### `PUT /polling-failure-alerts/{id}/status` 标记卡轮询失败告警已处理 + +只有未处理告警可标记;需要关闭对应卡的轮询时使用 POST /polling-failure-alerts/close-polling(告警状态自动改为已关闭轮询)。 + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 告警ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `remark` | string | | 处理备注 | +| `status` | integer | 是 | 目标状态 (4:已处理);关闭轮询请使用资产轮询开关接口 | + +#### `PUT /polling-rate-limit-groups/{id}` 修改网关限流组(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `carrier_id` | integer | | 运营商账户ID,为空表示全局组 | +| `group_code` | string | 是 | 组标识,同一账户内唯一 | +| `group_name` | string | 是 | 组名称 | +| `high_priority_operations` | array | | 高优先级操作,必须属于组内操作,设置预留额度时必填 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `max_qps` | integer | 是 | 每秒请求上限 | +| `operations` | array | 是 | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `reserved_qps` | integer | | 预留给高优先级操作的额度,须小于每秒请求上限 | +| `status` | integer | | 状态 (0:停用, 1:启用),新建默认启用 | + +返回 `data`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `carrier_id` | integer | 运营商账户ID,为空表示全局组 | +| `carrier_name` | string | 运营商账户名称,全局组为空 | +| `created_at` | string | 创建时间 | +| `group_code` | string | 组标识 | +| `group_name` | string | 组名称 | +| `high_priority_operations` | array | 高优先级操作 | +| `id` | integer | 限流组ID | +| `max_qps` | integer | 每秒请求上限 | +| `operations` | array | 组内操作 (query_flow:查流量, query_status:查状态, query_realname:查实名, stop:停机, start:复机) | +| `reserved_qps` | integer | 预留给高优先级操作的额度 | +| `status` | integer | 状态 (0:停用, 1:启用) | +| `status_name` | string | 状态名称 | +| `updated_at` | string | 更新时间 | + +#### `PUT /polling-rate-limit-groups/{id}/status` 启停网关限流组(仅超级管理员) + +参数: + +| 位置 | 名称 | 类型 | 必填 | 说明 | +|---|---|---|---|---| +| path | `id` | integer | 是 | 限流组ID | + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `status` | integer | 是 | 状态 (0:停用, 1:启用);停用后组内操作回落为默认每秒请求上限 | +