feat(moderation): resource-centric reported comments/events pages

Rework 内容审核 pages around reported resources instead of individual
reports, matching the new backend endpoints: rows group all reports on
one comment/event, with a slide-over listing report details and
per-row actions 通过并屏蔽 (approve) / 驳回举报 (reject) / 撤销屏蔽
(revert). Filters: 待处理 / 已屏蔽 / 全部.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-07-11 14:20:37 +08:00
co-authored by Claude Fable 5
parent 999d5353fd
commit f5a7249969
9 changed files with 532 additions and 381 deletions
+245 -173
View File
@@ -218,30 +218,33 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/admin/v1/comments/reports": {
"/api/admin/v1/comments/reported": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** [评论举报] 获取举报列表 */
/**
* [评论审核] 被举报评论列表
* @description 按被举报的评论分组列出举报,附带举报明细与屏蔽状态。
*/
get: {
parameters: {
query?: {
/**
* @description optional Filter by status: open, resolved, dismissed.
* @example open
* @description 可选。按状态过滤: pending(有待处理举报), blocked(已屏蔽), all(默认)。 示例: pending
* @example architecto
*/
status?: string;
/**
* @description optional Page number.
* @example 1
* @description 可选。页码。 示例: 1
* @example 16
*/
page?: number;
/**
* @description optional Page size (max 100).
* @example 20
* @description 可选。每页数量,最大100。 示例: 20
* @example 16
*/
page_size?: number;
};
@@ -253,10 +256,10 @@ export interface paths {
content: {
"application/json": {
/**
* @example resolved
* @example pending
* @enum {string|null}
*/
status?: "open" | "resolved" | "dismissed" | null;
status?: "pending" | "blocked" | "all" | null;
/**
* @description Must be at least 1.
* @example 16
@@ -282,54 +285,103 @@ export interface paths {
/**
* @example [
* {
* "id": 1,
* "comment_id": 10,
* "reason": "spam",
* "message": "Contains spam links",
* "status": "open",
* "created_at": "2025-12-01T10:10:00Z",
* "handled_at": null,
* "handled_by": null,
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* "kind": "reported_comment",
* "id": 10,
* "body": "这条评论包含垃圾推广链接",
* "body_format": "markdown",
* "status": "active",
* "is_blocked": false,
* "blocked_at": null,
* "blocked_by_uid": null,
* "author": {
* "uid": "01HYYYY",
* "display_name": "Bob"
* },
* "comment": {
* "id": 10,
* "body": "Root comment"
* }
* "open_reports_count": 2,
* "latest_report_at": "2026-07-11T10:10:00Z",
* "reports": [
* {
* "id": 1,
* "reason": "spam",
* "message": "含有垃圾推广链接",
* "status": "open",
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* },
* "created_at": "2026-07-11T10:10:00Z",
* "handled_at": null
* }
* ],
* "created_at": "2026-07-10T09:00:00Z"
* }
* ]
*/
data?: {
/** @example 1 */
id?: number;
/** @example reported_comment */
kind?: string;
/** @example 10 */
comment_id?: number;
/** @example spam */
reason?: string;
/** @example Contains spam links */
message?: string;
/** @example open */
id?: number;
/** @example 这条评论包含垃圾推广链接 */
body?: string;
/** @example markdown */
body_format?: string;
/** @example active */
status?: string;
/** @example 2025-12-01T10:10:00Z */
created_at?: string;
/** @example false */
is_blocked?: boolean;
/** @example null */
handled_at?: string;
blocked_at?: string;
/** @example null */
handled_by?: string;
reporter?: {
/** @example 01HXXXX */
blocked_by_uid?: string;
author?: {
/** @example 01HYYYY */
uid?: string;
/** @example Alice */
/** @example Bob */
display_name?: string;
};
comment?: {
/** @example 10 */
/** @example 2 */
open_reports_count?: number;
/** @example 2026-07-11T10:10:00Z */
latest_report_at?: string;
/**
* @example [
* {
* "id": 1,
* "reason": "spam",
* "message": "含有垃圾推广链接",
* "status": "open",
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* },
* "created_at": "2026-07-11T10:10:00Z",
* "handled_at": null
* }
* ]
*/
reports?: {
/** @example 1 */
id?: number;
/** @example Root comment */
body?: string;
};
/** @example spam */
reason?: string;
/** @example 含有垃圾推广链接 */
message?: string;
/** @example open */
status?: string;
reporter?: {
/** @example 01HXXXX */
uid?: string;
/** @example Alice */
display_name?: string;
};
/** @example 2026-07-11T10:10:00Z */
created_at?: string;
/** @example null */
handled_at?: string;
}[];
/** @example 2026-07-10T09:00:00Z */
created_at?: string;
}[];
pagination?: {
/** @example 1 */
@@ -378,31 +430,6 @@ export interface paths {
};
};
};
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example false */
success?: boolean;
/** @example VALIDATION_ERROR */
code?: string;
/** @example The given data was invalid. */
message?: string;
data?: {
errors?: {
/**
* @example [
* "The selected status is invalid."
* ]
*/
status?: string[];
};
};
};
};
};
};
};
put?: never;
@@ -413,21 +440,16 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/admin/v1/comments/reports/{report_id}": {
"/api/admin/v1/comments/reported/{comment}": {
parameters: {
query?: never;
header?: never;
path: {
/**
* @description The ID of the report.
* @example 3
* @description 评论 ID。
* @example 10
*/
report_id: number;
/**
* @description Report ID.
* @example 1
*/
report: number;
comment: number;
};
cookie?: never;
};
@@ -437,22 +459,22 @@ export interface paths {
delete?: never;
options?: never;
head?: never;
/** [评论举报] 处理举报 */
/**
* [评论审核] 处理被举报评论
* @description approve: 举报成立,屏蔽评论并将其全部待处理举报标记已处理;
* reject: 举报不成立,驳回全部待处理举报;
* revert: 撤销屏蔽(仅对已屏蔽评论有效),举报记录保留。
*/
patch: {
parameters: {
query?: never;
header?: never;
path: {
/**
* @description The ID of the report.
* @example 3
* @description 评论 ID。
* @example 10
*/
report_id: number;
/**
* @description Report ID.
* @example 1
*/
report: number;
comment: number;
};
cookie?: never;
};
@@ -460,8 +482,8 @@ export interface paths {
content: {
"application/json": {
/**
* @description Action to take: hide, delete, dismiss.
* @example hide
* @description 处理动作: approve, reject, revert。
* @example approve
*/
action: string;
};
@@ -477,16 +499,20 @@ export interface paths {
/** @example true */
success?: boolean;
data?: {
/** @example 1 */
/** @example reported_comment */
kind?: string;
/** @example 10 */
id?: number;
/** @example resolved */
status?: string;
/** @example 2025-12-01T10:20:00Z */
handled_at?: string;
/** @example true */
is_blocked?: boolean;
/** @example 2026-07-11T10:20:00Z */
blocked_at?: string;
/** @example 01HXXXX */
handled_by_uid?: string;
blocked_by_uid?: string;
/** @example 0 */
open_reports_count?: number;
};
/** @example Report handled */
/** @example Moderation applied */
message?: string;
};
};
@@ -521,21 +547,6 @@ export interface paths {
};
};
};
404: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
/** @example false */
success?: boolean;
/** @example NOT_FOUND */
code?: string;
/** @example 举报不存在 */
message?: string;
};
};
};
422: {
headers: {
[name: string]: unknown;
@@ -552,7 +563,7 @@ export interface paths {
errors?: {
/**
* @example [
* "The selected action is invalid."
* "Comment is not blocked."
* ]
*/
action?: string[];
@@ -881,11 +892,11 @@ export interface paths {
content: {
"application/json": {
/**
* @example ios
* @example android
* @enum {string|null}
*/
platform?: "ios" | "android" | "web" | "desktop" | null;
/** @example false */
/** @example true */
is_online?: boolean | null;
/**
* @description Must be at least 1.
@@ -1311,19 +1322,22 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/admin/v1/file-x/event-reports": {
"/api/admin/v1/file-x/reported-events": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** [事件举报] 获取举报列表 */
/**
* [事件审核] 被举报事件列表
* @description 按被举报的事件分组列出举报,附带举报明细与屏蔽状态。
*/
get: {
parameters: {
query?: {
/**
* @description 可选。按状态过滤: open, resolved, dismissed。 示例: open
* @description 可选。按状态过滤: pending(有待处理举报), blocked(已屏蔽), all(默认)。 示例: pending
* @example architecto
*/
status?: string;
@@ -1346,10 +1360,10 @@ export interface paths {
content: {
"application/json": {
/**
* @example open
* @example blocked
* @enum {string|null}
*/
status?: "open" | "resolved" | "dismissed" | null;
status?: "pending" | "blocked" | "all" | null;
/**
* @description Must be at least 1.
* @example 16
@@ -1375,47 +1389,100 @@ export interface paths {
/**
* @example [
* {
* "id": 1,
* "kind": "filex_event_report",
* "event_id": 25,
* "reason": "spam",
* "message": "含有大量垃圾推广链接",
* "status": "open",
* "created_at": "2026-06-06T10:00:00Z",
* "handled_at": null,
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* "kind": "reported_event",
* "id": 25,
* "title": "空调清洗上门服务记录",
* "visibility": "public",
* "is_blocked": false,
* "blocked_at": null,
* "blocked_by_uid": null,
* "author": {
* "uid": "01HYYYY",
* "display_name": "Bob"
* },
* "handled_by": null
* "open_reports_count": 2,
* "latest_report_at": "2026-07-11T10:10:00Z",
* "reports": [
* {
* "id": 1,
* "reason": "spam",
* "message": "疑似虚假事迹",
* "status": "open",
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* },
* "created_at": "2026-07-11T10:10:00Z",
* "handled_at": null
* }
* ],
* "created_at": "2026-07-10T09:00:00Z"
* }
* ]
*/
data?: {
/** @example 1 */
id?: number;
/** @example filex_event_report */
/** @example reported_event */
kind?: string;
/** @example 25 */
event_id?: number;
/** @example spam */
reason?: string;
/** @example 含有大量垃圾推广链接 */
message?: string;
/** @example open */
status?: string;
/** @example 2026-06-06T10:00:00Z */
created_at?: string;
id?: number;
/** @example 空调清洗上门服务记录 */
title?: string;
/** @example public */
visibility?: string;
/** @example false */
is_blocked?: boolean;
/** @example null */
handled_at?: string;
reporter?: {
/** @example 01HXXXX */
blocked_at?: string;
/** @example null */
blocked_by_uid?: string;
author?: {
/** @example 01HYYYY */
uid?: string;
/** @example Alice */
/** @example Bob */
display_name?: string;
};
/** @example null */
handled_by?: string;
/** @example 2 */
open_reports_count?: number;
/** @example 2026-07-11T10:10:00Z */
latest_report_at?: string;
/**
* @example [
* {
* "id": 1,
* "reason": "spam",
* "message": "疑似虚假事迹",
* "status": "open",
* "reporter": {
* "uid": "01HXXXX",
* "display_name": "Alice"
* },
* "created_at": "2026-07-11T10:10:00Z",
* "handled_at": null
* }
* ]
*/
reports?: {
/** @example 1 */
id?: number;
/** @example spam */
reason?: string;
/** @example 疑似虚假事迹 */
message?: string;
/** @example open */
status?: string;
reporter?: {
/** @example 01HXXXX */
uid?: string;
/** @example Alice */
display_name?: string;
};
/** @example 2026-07-11T10:10:00Z */
created_at?: string;
/** @example null */
handled_at?: string;
}[];
/** @example 2026-07-10T09:00:00Z */
created_at?: string;
}[];
pagination?: {
/** @example 1 */
@@ -1474,18 +1541,16 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/admin/v1/file-x/event-reports/{report_id}": {
"/api/admin/v1/file-x/reported-events/{event}": {
parameters: {
query?: never;
header?: never;
path: {
/**
* @description The ID of the report.
* @example 1
* @description 事件 ID。
* @example 25
*/
report_id: number;
/** @description Optional parameter. 必需。举报ID。 示例: 1 */
report: number;
event: number;
};
cookie?: never;
};
@@ -1495,30 +1560,33 @@ export interface paths {
delete?: never;
options?: never;
head?: never;
/** [事件举报] 处理举报 */
/**
* [事件审核] 处理被举报事件
* @description approve: 举报成立,屏蔽事件并将其全部待处理举报标记已处理;
* reject: 举报不成立,驳回全部待处理举报;
* revert: 撤销屏蔽(仅对已屏蔽事件有效),举报记录保留。
*/
patch: {
parameters: {
query?: never;
header?: never;
path: {
/**
* @description The ID of the report.
* @example 1
* @description 事件 ID。
* @example 25
*/
report_id: number;
/** @description Optional parameter. 必需。举报ID。 示例: 1 */
report: number;
event: number;
};
cookie?: never;
};
requestBody?: {
requestBody: {
content: {
"application/json": {
/**
* @description 必需。处理动作: hide, delete, resolve, dismiss。 示例: hide
* @example architecto
* @description 处理动作: approve, reject, revert。
* @example approve
*/
action?: string;
action: string;
};
};
};
@@ -1532,14 +1600,18 @@ export interface paths {
/** @example true */
success?: boolean;
data?: {
/** @example 1 */
/** @example reported_event */
kind?: string;
/** @example 25 */
id?: number;
/** @example resolved */
status?: string;
/** @example 2026-06-06T10:20:00Z */
handled_at?: string;
/** @example true */
is_blocked?: boolean;
/** @example 2026-07-11T10:20:00Z */
blocked_at?: string;
/** @example 01HXXXX */
handled_by_uid?: string;
blocked_by_uid?: string;
/** @example 0 */
open_reports_count?: number;
};
/** @example 举报已处理 */
message?: string;
@@ -1607,7 +1679,7 @@ export interface paths {
errors?: {
/**
* @example [
* "The selected action is invalid."
* "Event is not blocked."
* ]
*/
action?: string[];