feat(web): task-2 布局骨架+登录页(ProLayout 菜单对齐归档版、Basic Auth 登录、401 全局登出、/api 代理)+ 领域 API 层(路径对齐 dataProvider)
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
// 领域 API 层:资源路径与语义逐一对照 web.archived/src/shared/api/dataProvider.js。
|
||||
// 全部经由 requestErrorConfig.request(Basic Auth + 401 全局登出)。
|
||||
import { jsonOptions, request } from '@/requestErrorConfig';
|
||||
|
||||
export const resourcePaths = {
|
||||
browsers: '/browsers',
|
||||
gateways: '/gateways',
|
||||
accounts: '/phase-a/accounts',
|
||||
drafts: '/phase-a/drafts',
|
||||
confirmations: '/phase-a/confirmations',
|
||||
tasks: '/phase-a/tasks',
|
||||
attempts: '/phase-a/attempts',
|
||||
'network-exits': '/network-exits',
|
||||
'creator-accounts': '/creator/accounts',
|
||||
'creator-competitors': '/creator/competitors',
|
||||
'creator-competitor-share-jobs': '/creator/competitor-share-jobs',
|
||||
'creator-works': '/creator/works',
|
||||
'creator-comments': '/creator/comments',
|
||||
'creator-leads': '/creator/leads',
|
||||
'creator-rules': '/creator/rules',
|
||||
'creator-operations': '/creator/operations',
|
||||
'creator-conversations': '/creator/conversations',
|
||||
'creator-events': '/creator/events',
|
||||
'creator-listeners': '/creator/listeners',
|
||||
} as const;
|
||||
|
||||
export type Resource = keyof typeof resourcePaths;
|
||||
|
||||
// 与归档版 filterKeys 一致:资源 → 允许透传的查询字段。
|
||||
const filterKeys: Partial<Record<Resource, string[]>> = {
|
||||
drafts: ['account_id'],
|
||||
confirmations: ['draft_id'],
|
||||
tasks: ['account_id', 'draft_id', 'state'],
|
||||
'creator-competitors': ['platform'],
|
||||
'creator-competitor-share-jobs': ['platform', 'status'],
|
||||
'creator-works': ['platform', 'source_id', 'source_type', 'published_after', 'published_before', 'min_likes', 'min_comments', 'min_shares'],
|
||||
'creator-comments': ['platform', 'work_id'],
|
||||
'creator-leads': ['platform'],
|
||||
'creator-operations': ['account_id'],
|
||||
'creator-conversations': ['account_id'],
|
||||
'creator-events': ['account_id'],
|
||||
};
|
||||
|
||||
export interface ListParams {
|
||||
resource: Resource;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
filters?: Record<string, string | number | undefined>;
|
||||
}
|
||||
|
||||
// creator-* 走 page/page_size 分页;其余资源由后端返回全量或自带 total。
|
||||
export async function getList<T = any>({ resource, page, pageSize, filters = {} }: ListParams): Promise<{ data: T[]; total: number; hasNext?: boolean }> {
|
||||
const path = resourcePaths[resource];
|
||||
const query = new URLSearchParams();
|
||||
const allowed = filterKeys[resource] ?? [];
|
||||
for (const key of allowed) {
|
||||
const value = filters[key];
|
||||
if (value !== undefined && value !== null && `${value}` !== '') query.set(key, `${value}`);
|
||||
}
|
||||
if (resource.startsWith('creator-')) {
|
||||
if (page) query.set('page', `${page}`);
|
||||
if (pageSize) query.set('page_size', `${pageSize}`);
|
||||
}
|
||||
const records = await request(`${path}${query.size ? `?${query}` : ''}`);
|
||||
const data: T[] = Array.isArray(records) ? records : records.data;
|
||||
return {
|
||||
data: data.map((record: any, index: number) => ({ ...record, id: record.id ?? record.alias ?? record.version ?? record.name ?? index })),
|
||||
total: records.total ?? data.length,
|
||||
...(records && !Array.isArray(records) && Object.hasOwn(records, 'has_next') ? { hasNext: Boolean(records.has_next) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
const GETONE_ALLOWED: Resource[] = ['accounts', 'network-exits', 'browsers', 'drafts', 'confirmations', 'tasks', 'attempts', 'creator-accounts', 'creator-competitors', 'creator-competitor-share-jobs', 'creator-works', 'creator-comments', 'creator-rules', 'creator-operations'];
|
||||
|
||||
export async function getOne<T = any>(resource: Resource, id: string | number): Promise<T> {
|
||||
if (!GETONE_ALLOWED.includes(resource)) throw new Error(`${resource} 不支持 getOne`);
|
||||
return request(`${resourcePaths[resource]}/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
export async function create(resource: Resource, variables: unknown): Promise<any> {
|
||||
return request(resourcePaths[resource], jsonOptions('POST', variables));
|
||||
}
|
||||
|
||||
export async function update(resource: Resource, id: string | number, variables: unknown): Promise<void> {
|
||||
if (resource === 'browsers') throw new Error('browsers 不支持 update');
|
||||
await request(`${resourcePaths[resource]}/${encodeURIComponent(id)}`, jsonOptions('PUT', variables));
|
||||
}
|
||||
|
||||
export async function remove(resource: Resource, id: string | number): Promise<void> {
|
||||
if (!['accounts', 'creator-competitors'].includes(resource)) throw new Error(`${resource} 不支持 deleteOne`);
|
||||
await request(`${resourcePaths[resource]}/${encodeURIComponent(id)}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
// ===== 显式动词的领域动作(不伪装成 CRUD)=====
|
||||
|
||||
export async function browserAction(alias: string, action: 'start' | 'stop' | 'recycle'): Promise<void> {
|
||||
const targets: Record<string, [string, string]> = {
|
||||
start: [`/browsers/${encodeURIComponent(alias)}/start`, 'POST'],
|
||||
stop: [`/browsers/${encodeURIComponent(alias)}/stop`, 'POST'],
|
||||
recycle: [`/browsers/${encodeURIComponent(alias)}`, 'DELETE'],
|
||||
};
|
||||
const target = targets[action];
|
||||
if (!target) throw new Error(`未知运行环境操作: ${action}`);
|
||||
await request(target[0], { method: target[1] });
|
||||
}
|
||||
|
||||
export async function accountAction(id: string, action: 'pause' | 'resume'): Promise<void> {
|
||||
if (action !== 'pause' && action !== 'resume') throw new Error(`未知账号操作: ${action}`);
|
||||
await request(`/phase-a/accounts/${encodeURIComponent(id)}/${action}`, { method: 'POST' });
|
||||
}
|
||||
|
||||
export function createDraft(accountID: string, content: string) {
|
||||
return request('/phase-a/drafts', jsonOptions('POST', { account_id: accountID, content }));
|
||||
}
|
||||
|
||||
export function confirmDraft(draftID: string, accountVersion: number, draftVersion: number) {
|
||||
return request('/phase-a/confirmations', jsonOptions('POST', { draft_id: draftID, account_version: accountVersion, draft_version: draftVersion }));
|
||||
}
|
||||
|
||||
export function enqueueConfirmation(confirmationID: string) {
|
||||
return request('/phase-a/tasks', jsonOptions('POST', { confirmation_id: confirmationID }));
|
||||
}
|
||||
|
||||
export async function taskAction(id: string, action: 'verify' | 'resume' | 'finish' | 'cancel', data?: unknown): Promise<void> {
|
||||
if (!['verify', 'resume', 'finish', 'cancel'].includes(action)) throw new Error(`未知任务操作: ${action}`);
|
||||
const options = data ? jsonOptions('POST', data) : { method: 'POST' };
|
||||
await request(`/phase-a/tasks/${encodeURIComponent(id)}/${action}`, options);
|
||||
}
|
||||
|
||||
export async function networkExitAction(id: string, action: 'check' | 'disable' | 'enable'): Promise<any> {
|
||||
if (!['check', 'disable', 'enable'].includes(action)) throw new Error(`未知网络出口操作: ${action}`);
|
||||
return request(`/network-exits/${encodeURIComponent(id)}/${action}`, { method: 'POST' });
|
||||
}
|
||||
|
||||
// creator-* 领域的透传请求(路径由调用方给出,含列表页/actions)。
|
||||
export function creatorRequest(path: string, options?: RequestInit) {
|
||||
return request(path, options);
|
||||
}
|
||||
|
||||
export function creatorAction(path: string, data?: unknown) {
|
||||
return request(path, data === undefined ? { method: 'POST' } : jsonOptions('POST', data));
|
||||
}
|
||||
|
||||
export function creatorCreate(path: string, data: unknown) {
|
||||
return request(path, jsonOptions('POST', data));
|
||||
}
|
||||
|
||||
export function creatorGet(path: string) {
|
||||
return request(path);
|
||||
}
|
||||
|
||||
export function creatorUpdate(path: string, data: unknown) {
|
||||
return request(path, jsonOptions('PUT', data));
|
||||
}
|
||||
|
||||
export function creatorSyncConversation(id: string, limit = 200) {
|
||||
return request(`/creator/conversations/${encodeURIComponent(id)}/sync?limit=${encodeURIComponent(limit)}`, { method: 'POST' });
|
||||
}
|
||||
Reference in New Issue
Block a user