Files
doodle-mini/miniprogram/services/admin-api.ts
T

171 lines
6.0 KiB
TypeScript

import { apiRequest } from './api-request';
import type { ApiWorksheet } from './content-api';
export type AdminAction =
| 'categories.list'
| 'categories.create'
| 'categories.update'
| 'worksheets.list'
| 'worksheets.status'
| 'worksheets.batch'
| 'site.config'
| 'site.rebuild'
| 'site.timer';
interface AdminWorksheet extends ApiWorksheet {
status: 'draft' | 'active' | 'hidden';
likesDisplay: string;
downloadsDisplay: string;
likesSeed: string;
downloadsSeed: string;
}
interface AdminPage {
items: AdminWorksheet[];
total: number;
hasNext: boolean;
page: number;
pageSize: number;
}
/** 管理页迁移适配:只调用具名 REST 接口,旧页面展示字段在客户端映射,不传旧用户身份。 */
export async function managementRequest<T>(
action: AdminAction,
payload: Record<string, unknown> = {},
): Promise<{
success: boolean;
data?: T;
stats?: { total: number; active: number; draft: number; hidden: number };
message?: string;
}> {
let data: unknown;
let stats;
switch (action) {
case 'categories.list': {
const rows =
await apiRequest<Array<{ id: string }>>('/admin/categories');
data = rows.map((row) => ({ ...row, _id: row.id }));
break;
}
case 'categories.create':
data = await apiRequest('/admin/categories', {
method: 'POST',
data: payload,
});
break;
case 'categories.update': {
const { id, ...fields } = payload;
data = await apiRequest(
`/admin/categories/${encodeURIComponent(String(id))}`,
{ method: 'PUT', data: fields },
);
break;
}
case 'worksheets.list': {
const rows: AdminWorksheet[] = [];
let expected: number | undefined;
for (let page = 1; ; page++) {
const response = await apiRequest<AdminPage>(
'/admin/catalog/worksheets',
{
data: {
page,
pageSize: 100,
...(payload.category
? { categoryId: payload.category }
: {}),
...(payload.status
? { status: payload.status }
: {}),
},
},
);
if (
response.page !== page ||
response.pageSize !== 100 ||
!Array.isArray(response.items) ||
!Number.isSafeInteger(response.total) ||
(expected !== undefined && response.total !== expected) ||
response.hasNext !== page * 100 < response.total
)
throw new Error('管理目录发生变化,请重试');
expected = response.total;
rows.push(...response.items);
if (!response.hasNext) break;
}
if (
rows.length !== expected ||
new Set(rows.map((row) => row.id)).size !== rows.length
)
throw new Error('管理目录发生变化,请重试');
data = rows.map((row) => ({
...row,
_id: row.id,
likes: payload.rawStats ? row.likes : row.likesDisplay,
downloads: payload.rawStats
? row.downloads
: row.downloadsDisplay,
}));
stats = {
total: rows.length,
active: rows.filter((row) => row.status === 'active').length,
draft: rows.filter((row) => row.status === 'draft').length,
hidden: rows.filter((row) => row.status === 'hidden').length,
};
break;
}
case 'worksheets.status':
data = await apiRequest(
`/admin/worksheets/${encodeURIComponent(String(payload.id))}/status`,
{ method: 'PUT', data: { status: payload.status } },
);
break;
case 'worksheets.batch': {
const patches = (
payload.patches as Array<Record<string, unknown>>
).map(({ likes_seed, downloads_seed, ...row }) => ({
...row,
...(likes_seed === undefined ? {} : { likesSeed: likes_seed }),
...(downloads_seed === undefined
? {}
: { downloadsSeed: downloads_seed }),
}));
data = await apiRequest('/admin/worksheets/batch', {
method: 'POST',
timeout: 60000,
data: { patches, dryRun: payload.dryRun === true },
});
break;
}
case 'site.config':
data = await apiRequest('/admin/site/config');
break;
case 'site.rebuild':
data = await apiRequest('/admin/site/rebuild', {
method: 'POST',
timeout: 60000,
data: payload,
});
break;
case 'site.timer':
data = await apiRequest('/admin/site/timer', {
method: 'PUT',
data: { enabled: payload.enabled },
});
break;
default:
throw new Error('不支持的管理操作');
}
if (
[
'categories.create',
'categories.update',
'worksheets.status',
'worksheets.batch',
'site.rebuild',
].includes(action)
) {
const app = getApp<IAppOption>();
if (typeof app.refreshPageConfig === 'function')
await app.refreshPageConfig();
}
return { success: true, data: data as T, ...(stats ? { stats } : {}) };
}