179 lines
5.0 KiB
TypeScript
179 lines
5.0 KiB
TypeScript
import type {
|
|
CleaningSettlement,
|
|
CleaningTask,
|
|
PageResult,
|
|
SettlementStatus,
|
|
TaskStatus,
|
|
TransferMode,
|
|
WechatTransferPreflight
|
|
} from './types';
|
|
|
|
const API_BASE = (import.meta.env.VITE_ADMIN_API_BASE_URL || '/admin-api').replace(/\/$/, '');
|
|
|
|
export class ApiError extends Error {
|
|
constructor(
|
|
public readonly code: string,
|
|
message = code,
|
|
public readonly traceId = ''
|
|
) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
export interface ApiSession {
|
|
token: string;
|
|
}
|
|
|
|
async function request<T>(
|
|
session: ApiSession,
|
|
path: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
if (!session.token.trim()) {
|
|
throw new ApiError('AUTH_TOKEN_REQUIRED', '需要先填入后台访问令牌');
|
|
}
|
|
const headers = new Headers(options.headers);
|
|
headers.set('authorization', `Bearer ${session.token.trim()}`);
|
|
if (options.body && !headers.has('content-type')) {
|
|
headers.set('content-type', 'application/json');
|
|
}
|
|
const response = await fetch(`${API_BASE}${path}`, { ...options, headers });
|
|
const payload = await response.json().catch(() => ({}));
|
|
if (!response.ok || payload.code !== 0) {
|
|
throw new ApiError(
|
|
String(payload.code || `HTTP_${response.status}`),
|
|
String(payload.message || '请求失败'),
|
|
String(payload.traceId || '')
|
|
);
|
|
}
|
|
return payload.data as T;
|
|
}
|
|
|
|
export function listCleaningTasks(
|
|
session: ApiSession,
|
|
input: { page: number; pageSize: number; status?: TaskStatus }
|
|
) {
|
|
const params = new URLSearchParams({
|
|
page: String(input.page),
|
|
pageSize: String(input.pageSize)
|
|
});
|
|
if (input.status) params.set('status', input.status);
|
|
return request<PageResult<CleaningTask>>(session, `/cleaning/tasks?${params}`);
|
|
}
|
|
|
|
export function assignCleaningTask(
|
|
session: ApiSession,
|
|
taskId: string,
|
|
input: { cleanerUserId: string; note?: string }
|
|
) {
|
|
return request<CleaningTask>(session, `/cleaning/tasks/${encodeURIComponent(taskId)}/assign`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(input)
|
|
});
|
|
}
|
|
|
|
export function completeCleaningTask(session: ApiSession, taskId: string, note?: string) {
|
|
return request<CleaningTask>(session, `/cleaning/tasks/${encodeURIComponent(taskId)}/complete`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ note })
|
|
});
|
|
}
|
|
|
|
export function rejectCleaningTask(session: ApiSession, taskId: string, reason: string) {
|
|
return request<CleaningTask>(session, `/cleaning/tasks/${encodeURIComponent(taskId)}/reject`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ reason })
|
|
});
|
|
}
|
|
|
|
export function reclaimCleaningTimeouts(
|
|
session: ApiSession,
|
|
input: { olderThanMinutes: number; limit: number }
|
|
) {
|
|
return request<{ reclaimed: number; taskIds: string[] }>(session, '/cleaning/reclaim-timeouts', {
|
|
method: 'POST',
|
|
body: JSON.stringify(input)
|
|
});
|
|
}
|
|
|
|
export function listCleaningSettlements(
|
|
session: ApiSession,
|
|
input: { page: number; pageSize: number; status?: SettlementStatus }
|
|
) {
|
|
const params = new URLSearchParams({
|
|
page: String(input.page),
|
|
pageSize: String(input.pageSize)
|
|
});
|
|
if (input.status) params.set('status', input.status);
|
|
return request<PageResult<CleaningSettlement>>(session, `/cleaning/settlements?${params}`);
|
|
}
|
|
|
|
export function generateCleaningSettlement(
|
|
session: ApiSession,
|
|
input: { cleanerUserId: string; storeId?: string; note?: string }
|
|
) {
|
|
return request<CleaningSettlement>(session, '/cleaning/settlements', {
|
|
method: 'POST',
|
|
body: JSON.stringify(input)
|
|
});
|
|
}
|
|
|
|
export function confirmCleaningSettlement(session: ApiSession, settlementId: string, note?: string) {
|
|
return request<CleaningSettlement>(
|
|
session,
|
|
`/cleaning/settlements/${encodeURIComponent(settlementId)}/confirm`,
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify({ note })
|
|
}
|
|
);
|
|
}
|
|
|
|
export function executeWechatTransfer(
|
|
session: ApiSession,
|
|
settlementId: string,
|
|
input: { mode: TransferMode; note?: string }
|
|
) {
|
|
return request<{ settlement: CleaningSettlement; transferState: string; idempotent: boolean }>(
|
|
session,
|
|
`/cleaning/settlements/${encodeURIComponent(settlementId)}/wechat-transfer`,
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify(input)
|
|
}
|
|
);
|
|
}
|
|
|
|
export function preflightWechatTransfer(session: ApiSession, settlementId: string) {
|
|
return request<WechatTransferPreflight>(
|
|
session,
|
|
`/cleaning/settlements/${encodeURIComponent(settlementId)}/wechat-transfer/preflight`
|
|
);
|
|
}
|
|
|
|
export function syncWechatTransfer(session: ApiSession, settlementId: string, note?: string) {
|
|
return request<{ settlement: CleaningSettlement; transferState: string; idempotent: boolean }>(
|
|
session,
|
|
`/cleaning/settlements/${encodeURIComponent(settlementId)}/wechat-transfer/sync`,
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify({ note })
|
|
}
|
|
);
|
|
}
|
|
|
|
export function recordPayoutFailure(
|
|
session: ApiSession,
|
|
settlementId: string,
|
|
input: { error: string; payoutChannel?: string; payoutReference?: string; note?: string }
|
|
) {
|
|
return request<CleaningSettlement>(
|
|
session,
|
|
`/cleaning/settlements/${encodeURIComponent(settlementId)}/payout-failure`,
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify(input)
|
|
}
|
|
);
|
|
}
|