Files
dukang/apps/admin-web/src/lib/api.ts
T
jacy b626db5d84 feat(ops): add global test whitelist and exclude test accounts from settlement
Unify product/store visibility on HQ whitelist, mark isTest snapshots, and fix SUPER_ADMIN access for the new module.
2026-08-07 15:46:23 +08:00

213 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const apiBase = '/api/v1';
export const CLIENT_APP = 'HQ_WEB';
export type HqProfile = {
id: string;
phone: string;
name: string;
adminRole: string;
status: string;
permissionKeys?: string[];
};
export function getToken() {
return localStorage.getItem('accessToken');
}
export function saveAuth(data: { accessToken: string; refreshToken?: string }) {
localStorage.setItem('accessToken', data.accessToken);
if (data.refreshToken) localStorage.setItem('refreshToken', data.refreshToken);
}
export function clearAuth() {
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
}
export async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'X-Client-App': CLIENT_APP,
...(options.headers as Record<string, string>),
};
const token = getToken();
if (token) headers.Authorization = `Bearer ${token}`;
const res = await fetch(`${apiBase}${path}`, { ...options, headers });
const text = await res.text();
if (!text.trim()) {
throw new Error(`接口空响应(HTTP ${res.status} ${res.statusText || ''}`);
}
let json: { code: number; message?: string; data?: T };
try {
json = JSON.parse(text) as { code: number; message?: string; data?: T };
} catch {
throw new Error(`接口返回非 JSONHTTP ${res.status}: ${text.slice(0, 200)}`);
}
if (json.code === 401) {
clearAuth();
window.location.href = '/login';
throw new Error('未登录');
}
if (json.code !== 0) throw new Error(json.message || '请求失败');
return json.data as T;
}
export type Paginated<T> = {
items: T[];
total: number;
page: number;
pageSize: number;
summary?: {
count: number;
redeemAmount?: number;
payoutAmount?: number;
orderAmount?: number;
orderCommission?: number;
redeemCommission?: number;
wineryAmount?: number;
totalAmount: number;
};
};
export type DashboardStats = {
usersTotal: number;
guestUsers: number;
verifiedUsers: number;
mergedUsers: number;
ordersToday: number;
storesTotal: number;
partnersTotal: number;
redeemToday: number;
deliveriesTotal: number;
pendingPayouts?: number;
/** 合伙人已确认、待总部审核打款 */
pendingBills?: number;
pendingPartnerDraftBills?: number;
openTickets?: number;
pendingStoreWithdrawals?: number;
overdueStoreWithdrawals?: number;
ordersByStatus: Array<{ status: string; count: number }>;
};
export type DashboardAnalytics = {
summary: {
users: number;
orders: number;
payingUsers: number;
partners: number;
stores: number;
redeems: number;
redeemAmount: number;
};
byDate: Array<{
date: string;
users: number;
orders: number;
partners: number;
stores: number;
redeems: number;
redeemAmount: number;
}>;
byCity: Array<{
cityId: string;
cityName: string;
users: number;
orders: number;
partners: number;
stores: number;
redeems: number;
redeemAmount: number;
}>;
byPromo: Array<{
promoCodeId: string | null;
code: string;
name: string;
users: number;
orders: number;
}>;
byPartner: Array<{
partnerAccountId: string;
companyName: string;
stores: number;
redeems: number;
redeemAmount: number;
}>;
};
export type SystemVersion = {
id: string;
gitTag: string | null;
commitId: string;
commitMessage: string;
branch: string | null;
deployedBy: string | null;
deployedAt: string;
};
export type DeployTriggerResult = {
accepted: boolean;
started?: boolean;
message: string;
};
export type AdminUserRow = {
id: string;
userNo: string;
deviceKey: string | null;
phone: string | null;
phoneVerifiedAt: string | null;
mergedIntoUserId: string | null;
wxOpenId: string | null;
wechatVerified: boolean;
nickname: string | null;
status: number;
sourceType: string;
sourceRefId: string | null;
sourceLabel: string | null;
createdAt: string;
orderCount: number;
isTest?: boolean;
};
export type AdminOrderItem = {
productName: string;
productSpec: string;
productImage: string;
unitPrice: number;
quantity: number;
};
export type AdminOrderRow = {
id: string;
orderNo: string;
status: string;
deliveryType: string;
payAmount: number;
productName?: string;
productSpec?: string;
quantity?: number;
receiverName: string;
receiverPhone: string;
createdAt: string;
cityId?: string;
city?: { id: string; name: string; code: string };
fulfillmentWarehouseId?: string | null;
fulfillmentWarehouse?: { id: string; name: string } | null;
fulfillmentHold?: boolean;
fulfillmentHoldReason?: string | null;
orderType?: string;
isProxyOrder?: boolean;
proxyPartnerName?: string | null;
proxyPartnerPhone?: string | null;
isTest?: boolean;
user?: { id: string; userNo: string; phone: string | null; nickname: string | null };
delivery?: {
provider: string;
trackingNo: string | null;
providerOrderNo: string | null;
logisticsCompany?: string | null;
manualQueryUrl?: string | null;
};
};