Files
gig-admin/src/api/types.ts
kongkx f5a7249969 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 <noreply@anthropic.com>
2026-07-11 14:20:37 +08:00

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
}