feat: connect tenant coupon marketing ui

This commit is contained in:
Codex
2026-06-29 23:13:45 +08:00
parent 62c45a8fed
commit 620f3ac5ed
5 changed files with 410 additions and 13 deletions

View File

@@ -397,10 +397,81 @@ export interface CouponItem {
id: string;
code: string;
status?: string;
campaignName?: string | null;
planId?: string | null;
discountType?: string | null;
discountValue?: number | string | null;
validFrom?: string | null;
validTo?: string | null;
usedCount?: number;
maxUses?: number | null;
minOrderAmountCents?: number;
maxDiscountCents?: number | null;
perUserLimit?: number;
firstOrderOnly?: boolean;
allowedPlanIds?: string[];
allowedRegionIds?: string[];
metadata?: Record<string, unknown>;
source?: string | null;
remark?: string | null;
}
export interface CouponInput {
id?: string;
code: string;
planId?: string | null;
discountType?: 'fixed' | 'percent' | null;
discountValue?: number | string | null;
validFrom?: string | null;
validTo?: string | null;
maxUses?: number | null;
status?: 'active' | 'disabled' | 'archived';
campaignName?: string | null;
minOrderAmountCents?: number;
maxDiscountCents?: number | null;
perUserLimit?: number;
firstOrderOnly?: boolean;
allowedPlanIds?: string[];
allowedRegionIds?: string[];
metadata?: Record<string, unknown>;
source?: string | null;
remark?: string | null;
}
export interface CouponRedemptionItem {
id: string;
couponId?: string | null;
couponCode?: string | null;
campaignName?: string | null;
userId?: string | null;
userName?: string | null;
userPhone?: string | null;
planId?: string | null;
planName?: string | null;
orderId?: string | null;
orderNo?: string | null;
status?: string;
discountAppliedCents?: number;
regionId?: string | null;
regionName?: string | null;
source?: string | null;
remark?: string | null;
claimedAt?: string | null;
usedAt?: string | null;
createdAt?: string;
}
export interface CouponReport {
startDate?: string;
endDate?: string;
claimCount?: number;
usedCount?: number;
discountCents?: number;
paidAmountCents?: number;
conversionRate?: number;
byCoupon?: Array<Record<string, unknown>>;
byCampaign?: Array<Record<string, unknown>>;
daily?: Array<Record<string, unknown>>;
}
export interface CodeBatchItem {
@@ -982,8 +1053,34 @@ export async function executeContentImport(importType: ImportType, body: ImportR
});
}
export async function loadCoupons() {
return apiRequest<{ items?: CouponItem[] }>('/api/tenant-admin/coupons');
export async function loadCoupons(query: { status?: string; campaignName?: string; limit?: number } = {}) {
return apiRequest<{ items?: CouponItem[] }>('/api/tenant-admin/coupons', { query });
}
export async function upsertCoupon(input: CouponInput) {
return apiRequest<{ item?: CouponItem }>('/api/tenant-admin/coupons', {
method: 'PUT',
body: input,
});
}
export async function loadCouponRedemptions(query: {
couponId?: string;
status?: 'claimed' | 'pending' | 'used' | 'cancelled' | 'expired';
limit?: number;
} = {}) {
return apiRequest<{ items?: CouponRedemptionItem[] }>('/api/tenant-admin/coupons/redemptions', {
query: { ...query, limit: query.limit || 50 },
});
}
export async function loadCouponReport(query: {
startDate?: string;
endDate?: string;
couponId?: string;
campaignName?: string;
} = {}) {
return apiRequest<{ item?: CouponReport }>('/api/tenant-admin/coupons/report', { query });
}
export async function loadCodeBatches() {