88053353ab
- admin 用户列表新增剩余/已用/累计好客权益金额三列(benefitCoupon groupBy 聚合,排除 VOID) - admin/partner 门店入驻合同支持多张照片与 PDF(CommonResource 多记录,复用 ENV 多图逻辑) - 新增 contract-urls.util 归一化工具,向后兼容旧 contractUrl 字段并标记 deprecated 需求1/2/3
219 lines
5.3 KiB
TypeScript
219 lines
5.3 KiB
TypeScript
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(`接口返回非 JSON(HTTP ${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;
|
||
/** 好客权益·累计获得(含已使用,不含退款作废) */
|
||
benefitTotalAmount?: number;
|
||
/** 好客权益·已使用(已核销) */
|
||
benefitUsedAmount?: number;
|
||
/** 好客权益·剩余未使用 */
|
||
benefitBalance?: number;
|
||
};
|
||
|
||
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;
|
||
};
|
||
};
|