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 <noreply@anthropic.com>
354 lines
8.1 KiB
TypeScript
354 lines
8.1 KiB
TypeScript
/**
|
|
* Hand-written types for the gig-platform admin API.
|
|
*
|
|
* The scribe-generated `types.gen.ts` covers paths/params, but its response
|
|
* schemas are example-based and incomplete — the envelope and entities below
|
|
* are the source of truth for data shapes (mirrors CLAUDE.md API design).
|
|
*/
|
|
|
|
// ---------- envelope ----------
|
|
|
|
export interface ApiResponse<T = unknown> {
|
|
success: boolean
|
|
data: T
|
|
message?: string
|
|
meta?: Record<string, unknown>
|
|
}
|
|
|
|
export interface Pagination {
|
|
current_page: number
|
|
next_page: number | null
|
|
page_size: number
|
|
prev_page: number | null
|
|
total_count: number
|
|
total_pages: number
|
|
}
|
|
|
|
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
pagination: Pagination
|
|
}
|
|
|
|
export interface ApiErrorPayload {
|
|
success: false
|
|
code: string
|
|
message: string
|
|
data?: { errors?: Record<string, string[]> } & Record<string, unknown>
|
|
}
|
|
|
|
export interface ListParams {
|
|
page?: number
|
|
page_size?: number
|
|
[key: string]: string | number | boolean | undefined
|
|
}
|
|
|
|
// ---------- auth ----------
|
|
|
|
export interface TokenGrant {
|
|
token_type: string
|
|
expires_in: number
|
|
access_token: string
|
|
refresh_token?: string
|
|
}
|
|
|
|
export interface AdminUser {
|
|
kind: 'user'
|
|
uid: string
|
|
sid?: string | null
|
|
username: string | null
|
|
email: string | null
|
|
phone: string | null
|
|
display_name: string | null
|
|
avatar: string | null
|
|
status: boolean | string
|
|
is_robot?: boolean
|
|
}
|
|
|
|
export interface MeResponse extends ApiResponse<AdminUser> {
|
|
meta: {
|
|
roles: string[]
|
|
permissions: string[]
|
|
}
|
|
}
|
|
|
|
// ---------- category ----------
|
|
|
|
export interface CategoryTranslation {
|
|
locale: string
|
|
name: string
|
|
description: string | null
|
|
}
|
|
|
|
export interface Category {
|
|
kind: 'category'
|
|
id: string
|
|
parent_id: string | null
|
|
level: number
|
|
slug: string
|
|
name: string | null
|
|
description: string | null
|
|
sort_order: number
|
|
is_active: boolean
|
|
visibility?: string
|
|
approval_status?: 'pending' | 'approved' | 'rejected' | string
|
|
source?: string
|
|
created_by_uid?: string | null
|
|
approved_by_uid?: string | null
|
|
approved_at?: string | null
|
|
merged_into_category_id?: string | null
|
|
translations?: CategoryTranslation[]
|
|
children?: Category[]
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
// ---------- studio ----------
|
|
|
|
export type ArticleStatus =
|
|
| 'planned'
|
|
| 'drafting'
|
|
| 'drafted'
|
|
| 'published'
|
|
| 'scheduled'
|
|
|
|
export interface StudioArticle {
|
|
kind: 'studio_article'
|
|
id: string
|
|
series_id: string
|
|
robot_author_id: string
|
|
category_id: string | null
|
|
subtopic_id: string | null
|
|
article_number: number
|
|
plan: Record<string, unknown> | null
|
|
outline: Record<string, unknown> | null
|
|
title: string | null
|
|
summary: string | null
|
|
key_takeaways: string[] | null
|
|
cta: string | null
|
|
tags: string[] | null
|
|
seo_keywords: string[] | null
|
|
cover_image_prompt: string | null
|
|
cover_asset_id: string | null
|
|
cover_image: { url: string; alt?: string | null } | null
|
|
inline_images: Array<{ url: string; alt?: string | null }> | null
|
|
inline_image_prompts: unknown[] | null
|
|
status: ArticleStatus
|
|
/** LLM used to draft the body, e.g. { provider, model, params }. */
|
|
drafting_model: { provider?: string; model?: string; [k: string]: unknown } | null
|
|
publish_schedule: Record<string, unknown> | null
|
|
dimzou_document_id: number | null
|
|
dimzou_publication_id: number | null
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export type RobotAuthorStatus = 'pending' | 'profiling' | 'ready' | 'paused'
|
|
|
|
export interface StudioRobotAuthor {
|
|
kind: 'studio_robot_author'
|
|
id: string
|
|
user_uid: string
|
|
/** Bound robot account's public name (index listing only). */
|
|
display_name?: string | null
|
|
avatar?: string | null
|
|
category_id: string
|
|
subtopic_id: string | null
|
|
/** Account-level voice — stored on the shared profile, flattened into the author. */
|
|
persona: string | null
|
|
article_style: Record<string, unknown> | null
|
|
image_style: Record<string, unknown> | null
|
|
publishing_rules: Record<string, unknown> | null
|
|
status: RobotAuthorStatus
|
|
source: 'user' | 'category'
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export type SeriesStatus = 'planned' | 'in_progress' | 'complete'
|
|
|
|
export interface StudioSeries {
|
|
kind: 'studio_series'
|
|
id: string
|
|
category_id: string
|
|
subtopic_id: string | null
|
|
robot_author_id: string
|
|
goal: string | null
|
|
/** Series-level angle/audience (moved off the author). */
|
|
positioning: string | null
|
|
target_readers: string | null
|
|
reader_journey: string | null
|
|
target_article_count: number | null
|
|
planned_articles: unknown[] | null
|
|
status: SeriesStatus
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface StudioSubtopic {
|
|
kind: 'studio_subtopic'
|
|
id: string
|
|
category_id: string
|
|
title: string
|
|
target_audience: string | null
|
|
pain_points: string | null
|
|
content_value: string | null
|
|
expandability_score: number | null
|
|
status: 'active' | 'archived'
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface StudioCategoryBrief {
|
|
kind: 'studio_category_brief'
|
|
id: string
|
|
category_id: string
|
|
description: string | null
|
|
target_audience: string | null
|
|
content_angles: string[] | null
|
|
risk_notes: string | null
|
|
subtopic_count: number
|
|
author_count: number
|
|
article_count: number
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface StudioStylePreset {
|
|
kind: 'studio_style_preset'
|
|
id: string
|
|
type: 'article' | 'image' | 'bundle'
|
|
name: string
|
|
payload: Record<string, unknown>
|
|
created_at: string
|
|
updated_at: string
|
|
}
|
|
|
|
export interface StudioAgentToken {
|
|
kind: 'studio_agent_token'
|
|
id: string
|
|
scopes: string[] | null
|
|
created_at: string | null
|
|
expires_at: string | null
|
|
}
|
|
|
|
export interface StudioAgentTokenGrant extends TokenGrant {
|
|
kind: 'studio_agent_token_grant'
|
|
connect: { endpoint: string; header: string }
|
|
}
|
|
|
|
// ---------- sid / locales / devices ----------
|
|
|
|
export interface SidRule {
|
|
id?: number
|
|
key: string
|
|
description: string | null
|
|
enabled: boolean
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
export interface LuckyNumber {
|
|
id: number
|
|
number: string
|
|
category: string | null
|
|
enabled: boolean
|
|
created_by?: string | null
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
export interface SidCheckResult {
|
|
sid: string
|
|
reserved: boolean
|
|
reasons?: string[]
|
|
}
|
|
|
|
export interface LocaleRow {
|
|
kind?: string
|
|
code: string
|
|
name: string
|
|
native_name: string
|
|
is_active: boolean
|
|
sort_order: number
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
export interface NotificationDevice {
|
|
id: number | string
|
|
device_id?: string
|
|
user_uid?: string | null
|
|
platform?: string
|
|
model?: string | null
|
|
is_online?: boolean
|
|
active_sessions_count?: number
|
|
last_seen_at?: string | null
|
|
created_at?: string
|
|
}
|
|
|
|
export type ReportStatus = 'open' | 'resolved' | 'dismissed'
|
|
|
|
export interface ReportUser {
|
|
uid: string
|
|
display_name?: string | null
|
|
}
|
|
|
|
export interface ResourceReport {
|
|
id: number
|
|
reason: string
|
|
message?: string | null
|
|
status: ReportStatus
|
|
reporter?: ReportUser | null
|
|
created_at: string
|
|
handled_at?: string | null
|
|
}
|
|
|
|
interface ReportedResourceBase {
|
|
kind?: string
|
|
id: number
|
|
is_blocked: boolean
|
|
blocked_at?: string | null
|
|
blocked_by_uid?: string | null
|
|
author?: ReportUser | null
|
|
open_reports_count: number
|
|
latest_report_at?: string | null
|
|
reports: ResourceReport[]
|
|
created_at?: string
|
|
}
|
|
|
|
export interface ReportedComment extends ReportedResourceBase {
|
|
body?: string | null
|
|
body_format?: string
|
|
status?: string
|
|
}
|
|
|
|
export interface ReportedEvent extends ReportedResourceBase {
|
|
title?: string | null
|
|
visibility?: string
|
|
}
|
|
|
|
export type DimzouTranslationStatus = 'draft' | 'awaiting_publish' | 'published'
|
|
|
|
export interface DimzouTranslation {
|
|
kind?: string
|
|
id: number
|
|
language_code: string
|
|
status: DimzouTranslationStatus
|
|
source_document?: { id: number; title?: string | null } | null
|
|
translated_document_id: number
|
|
created_by_uid: string
|
|
creator?: ReportUser | null
|
|
draft_version_id?: number | null
|
|
blocks: {
|
|
total: number
|
|
needs_translation: number
|
|
translation_failed: number
|
|
}
|
|
created_at?: string
|
|
updated_at?: string
|
|
}
|
|
|
|
export interface RetranslateResult {
|
|
translation_version_id: number
|
|
queued_blocks: number
|
|
}
|