feat(gateway): 渠道事件查询面 + 面板「渠道事件」页(design/26 E6)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 两个只读端点:GET /admin/channels/events(列表,8 个过滤条件 + 分页钳制)与 .../events/counters(逐类计数,恒带 approx:true 如实标「近似」)
- 诚实边界:>90 天窗口 ⇒ 400(不静默裁剪);未知 platform/档位 ⇒ 400;**未接线 ⇒ 500 channel_events_unavailable**(绝不回空 200 假装「没有事件」);微信平台的空如实说明「该渠道不提供非消息事件」而不借别平台顶替
- 面板:新 section「渠道事件」(计数卡 + 事件行 + 过滤条 + 30s 静默刷新),空/错误态分开且失败显示错误不显示 0
- 组合根接线(主会话补):wire_frontend.go 的 Deps 注入 EventStore: a.channelEventStore()(未接线时为真 nil ⇒ 保留诚实 500)
- 契约不升版(查询面 v0.67 已登记):就地改「未实现 → 已实现 + 端点路径」,并补登记 5 处原先留白的落地值(camelCase / 通用 bad_request / RBAC owner|admin / data.approx / total 语义)
- 顺带把 §5 三个 CHANNEL_EVENT_* env 键由「尚未实现」改「已接线」(E4)
- 变异实测:去掉 90 天上限 ⇒ status 200 want 400;未接线回空 200 ⇒ status 200 want 500
- 债务登记:events.Filter 无 AccountID 列 ⇒ 服务端暂不能按账号筛(列表仍如实下发 accountId),要加需先改 internal/runtime/events
This commit is contained in:
AskaEth committed 2026-10-05 14:38:37 +08:00
1 parent a0abf0199a
commit c8053b1f36
21 files changed
+1805 -30

No files matched your search

@@ -0,0 +1,45 @@
import type { AdminChannelEventCounters, AdminChannelEventList } from "../types";
import { request } from "./core";
/** `GET /api/v1/admin/channels/events` 的查询条件(全部可选;空串 = 不过滤)。
*
* 与后端 `channelEventsListFilter` 逐项对应:后端**不注入**缺省时间窗
* (没给 `since`/`until` 就是不加时间条件),因此这里也绝不替调用方补一个 ——
* 面板自己显式传它想看的窗口,界面上才不会出现「我以为是全部,其实是最近一天」。 */
export interface ChannelEventQuery {
platform?: string;
tier?: string;
category?: string;
channelId?: string;
/** RFC3339(`toISOString()`);跨度上限 90 天,超了后端回 400。 */
since?: string;
until?: string;
limit?: number;
offset?: number;
}
/** 渠道事件列表(倒序)。只读;不含正文 / URL / 凭据。 */
export function adminChannelEvents(query: ChannelEventQuery = {}): Promise<AdminChannelEventList> {
const params = new URLSearchParams();
const add = (key: string, value: string | undefined): void => {
const trimmed = value?.trim();
if (trimmed) params.set(key, trimmed);
};
add("platform", query.platform);
add("tier", query.tier);
add("category", query.category);
add("channelId", query.channelId);
add("since", query.since);
add("until", query.until);
if (query.limit && query.limit > 0) params.set("limit", String(query.limit));
if (query.offset && query.offset > 0) params.set("offset", String(query.offset));
const qs = params.toString();
return request<AdminChannelEventList>(`/admin/channels/events${qs ? `?${qs}` : ""}`);
}
/** 逐类计数汇总(近似值,响应带 `approx`)。`platform` 空 = 全部平台。 */
export function adminChannelEventCounters(platform?: string): Promise<AdminChannelEventCounters> {
const trimmed = platform?.trim();
const qs = trimmed ? `?platform=${encodeURIComponent(trimmed)}` : "";
return request<AdminChannelEventCounters>(`/admin/channels/events/counters${qs}`);
}