148 lines
5.6 KiB
TypeScript
148 lines
5.6 KiB
TypeScript
/**
|
||
* 管理后台 API 客户端 - 统一走后端接口(MongoDB)
|
||
* 前端仅通过此模块请求数据,不再直连 Dexie
|
||
*/
|
||
|
||
const BASE = "/api/admin"
|
||
|
||
async function fetchJson<T>(url: string, init?: RequestInit): Promise<{ success: boolean; data?: T; message?: string }> {
|
||
const res = await fetch(url, { ...init, headers: { "Content-Type": "application/json", ...init?.headers } })
|
||
const json = await res.json().catch(() => ({}))
|
||
if (!res.ok) return { success: false, message: json.message ?? res.statusText }
|
||
return json
|
||
}
|
||
|
||
export interface DashboardData {
|
||
stats: {
|
||
totalUsers: number
|
||
totalStreamers: number
|
||
totalOrders: number
|
||
totalRevenue: number
|
||
todayNewUsers: number
|
||
todayOrders: number
|
||
activeStreamers: number
|
||
pendingPawns: number
|
||
}
|
||
recentUsers: { id: string; name?: string; avatar?: string; phone?: string; createdAt?: string }[]
|
||
recentOrders: { orderNo: string; itemName: string; amount: number; createdAt: string }[]
|
||
}
|
||
|
||
export async function getDashboard(): Promise<DashboardData | null> {
|
||
const r = await fetchJson<{ data: DashboardData }>(`${BASE}/dashboard`)
|
||
return r.success && r.data ? r.data : null
|
||
}
|
||
|
||
export async function getUsers(): Promise<Record<string, unknown>[]> {
|
||
const r = await fetchJson<{ data: Record<string, unknown>[] }>(`${BASE}/users`)
|
||
return r.success && r.data ? r.data : []
|
||
}
|
||
|
||
export async function updateUser(id: string, body: Record<string, unknown>): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/users/${id}`, { method: "PATCH", body: JSON.stringify(body) })
|
||
return r.success === true
|
||
}
|
||
|
||
export async function deleteUser(id: string): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/users/${id}`, { method: "DELETE" })
|
||
return r.success === true
|
||
}
|
||
|
||
/** 用户详情(本库 + 用户资产 API 补充:消费记录、绑定主播),用于管理端点击查询 */
|
||
export interface UserDetailEnriched {
|
||
user: { user_id?: string; name?: string; gender?: string; phone?: string; created_at?: string; [k: string]: unknown } | null
|
||
consumption: { amount?: number; timestamp?: string; [k: string]: unknown }[]
|
||
boundStreamer: { streamer_id?: string; streamer_name?: string; [k: string]: unknown } | null
|
||
fromExternal: boolean
|
||
}
|
||
|
||
export async function getUserDetail(id: string): Promise<{
|
||
local: Record<string, unknown>
|
||
enriched: UserDetailEnriched
|
||
} | null> {
|
||
const r = await fetchJson<{ data: { local: Record<string, unknown>; enriched: UserDetailEnriched } }>(
|
||
`${BASE}/users/${id}/detail`
|
||
)
|
||
return r.success && r.data ? r.data : null
|
||
}
|
||
|
||
export async function getStreamers(): Promise<Record<string, unknown>[]> {
|
||
const r = await fetchJson<{ data: Record<string, unknown>[] }>(`${BASE}/streamers`)
|
||
return r.success && r.data ? r.data : []
|
||
}
|
||
|
||
/** 单条主播详情(含公会名、绑定统计,后端若已实现则返回) */
|
||
export async function getStreamer(id: string): Promise<Record<string, unknown> | null> {
|
||
const r = await fetchJson<{ data: Record<string, unknown> }>(`${BASE}/streamers/${id}`)
|
||
return r.success && r.data ? r.data : null
|
||
}
|
||
|
||
export async function createStreamer(body: Record<string, unknown>): Promise<{ id: string } | null> {
|
||
const r = await fetchJson<{ data: { id: string } }>(`${BASE}/streamers`, { method: "POST", body: JSON.stringify(body) })
|
||
return r.success && r.data ? r.data : null
|
||
}
|
||
|
||
export async function updateStreamer(id: string, body: Record<string, unknown>): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/streamers/${id}`, { method: "PATCH", body: JSON.stringify(body) })
|
||
return r.success === true
|
||
}
|
||
|
||
export async function deleteStreamer(id: string): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/streamers/${id}`, { method: "DELETE" })
|
||
return r.success === true
|
||
}
|
||
|
||
export async function getProducts(): Promise<Record<string, unknown>[]> {
|
||
const r = await fetchJson<{ data: Record<string, unknown>[] }>(`${BASE}/products`)
|
||
return r.success && r.data ? r.data : []
|
||
}
|
||
|
||
export async function createProduct(body: Record<string, unknown>): Promise<{ id: string } | null> {
|
||
const r = await fetchJson<{ data: { id: string } }>(`${BASE}/products`, { method: "POST", body: JSON.stringify(body) })
|
||
return r.success && r.data ? r.data : null
|
||
}
|
||
|
||
export async function updateProduct(id: string, body: Record<string, unknown>): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/products/${id}`, { method: "PATCH", body: JSON.stringify(body) })
|
||
return r.success === true
|
||
}
|
||
|
||
export async function deleteProduct(id: string): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/products/${id}`, { method: "DELETE" })
|
||
return r.success === true
|
||
}
|
||
|
||
export async function getPawns(): Promise<Record<string, unknown>[]> {
|
||
const r = await fetchJson<{ data: Record<string, unknown>[] }>(`${BASE}/pawns`)
|
||
return r.success && r.data ? r.data : []
|
||
}
|
||
|
||
export async function updatePawn(id: string, body: Record<string, unknown>): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/pawns/${id}`, { method: "PATCH", body: JSON.stringify(body) })
|
||
return r.success === true
|
||
}
|
||
|
||
export interface AdminOrder {
|
||
id: string
|
||
orderNo: string
|
||
type: string
|
||
itemName: string
|
||
amount: number
|
||
status: string
|
||
userId?: string
|
||
createdAt: string
|
||
sourceTable: string
|
||
}
|
||
|
||
export async function getOrders(): Promise<AdminOrder[]> {
|
||
const r = await fetchJson<{ data: AdminOrder[] }>(`${BASE}/orders`)
|
||
return r.success && r.data ? r.data : []
|
||
}
|
||
|
||
export async function updateOrderStatus(id: string, sourceTable: string, status: string): Promise<boolean> {
|
||
const r = await fetchJson(`${BASE}/orders/status`, {
|
||
method: "PATCH",
|
||
body: JSON.stringify({ id, sourceTable, status }),
|
||
})
|
||
return r.success === true
|
||
}
|