feat(marketing): implement recharge tiers and coupon management across admin, server, and uniapp

这个提交包含在:
xcbyy
2026-10-10 09:22:46 +08:00
父节点 51682fffea
当前提交 d9c8388711
共有 12 个文件被更改,包括 1494 次插入 和 7 次删除

查看文件

@@ -0,0 +1,104 @@
// 已读取AGENTS.md
import { ContentSecurityService } from '../security/content-security.service';
export interface RechargeTierItem {
id: number;
amount: number;
bonusAmount: number;
tag?: string;
sortOrder: number;
status: number;
}
export interface CouponItem {
id: number;
name: string;
discountAmount: number;
minSpend: number;
validDays: number;
totalCount: number;
receivedCount: number;
categoryLimit: string;
description?: string;
status: number;
}
export class MarketingService {
private tiers: RechargeTierItem[] = [
{ id: 1, amount: 50, bonusAmount: 0, tag: '基础充值', sortOrder: 1, status: 1 },
{ id: 2, amount: 100, bonusAmount: 5, tag: '热门畅享', sortOrder: 2, status: 1 },
{ id: 3, amount: 200, bonusAmount: 15, tag: '超值加赠', sortOrder: 3, status: 1 },
{ id: 4, amount: 500, bonusAmount: 50, tag: '尊享特惠', sortOrder: 4, status: 1 },
{ id: 5, amount: 1000, bonusAmount: 120, tag: '土豪专享', sortOrder: 5, status: 1 }
];
private coupons: CouponItem[] = [
{ id: 1, name: '新用户注册专享立减券', discountAmount: 20, minSpend: 50, validDays: 15, totalCount: 2000, receivedCount: 128, categoryLimit: 'ALL', description: '全品类满50可用', status: 1 },
{ id: 2, name: '周末同城聚会AA抵扣券', discountAmount: 15, minSpend: 80, validDays: 7, totalCount: 1000, receivedCount: 85, categoryLimit: 'MEAL', description: '限美食探店使用', status: 1 },
{ id: 3, name: '工体K歌麦霸欢唱减免券', discountAmount: 30, minSpend: 120, validDays: 10, totalCount: 800, receivedCount: 62, categoryLimit: 'SING', description: '限KTV陪唱使用', status: 1 }
];
private nextTierId = 6;
private nextCouponId = 4;
private secService = new ContentSecurityService();
// 充值阶梯
getActiveTiers(): RechargeTierItem[] {
return this.tiers.filter((t) => t.status === 1).sort((a, b) => a.sortOrder - b.sortOrder);
}
createTier(data: { amount: number; bonusAmount?: number; tag?: string; sortOrder?: number; status?: number }): RechargeTierItem {
if (!data.amount || data.amount <= 0) {
throw new Error('充值金额必须大于0');
}
const item: RechargeTierItem = {
id: this.nextTierId++,
amount: Number(data.amount),
bonusAmount: Number(data.bonusAmount || 0),
tag: data.tag || '',
sortOrder: Number(data.sortOrder || 0),
status: data.status !== undefined ? Number(data.status) : 1
};
this.tiers.push(item);
return item;
}
// 优惠券业务
getActiveCoupons(category?: string): CouponItem[] {
return this.coupons
.filter((c) => c.status === 1)
.filter((c) => !category || category === 'ALL' || c.categoryLimit === 'ALL' || c.categoryLimit === category)
.sort((a, b) => b.discountAmount - a.discountAmount);
}
createCoupon(data: { name: string; discountAmount: number; minSpend?: number; validDays?: number; totalCount?: number; categoryLimit?: string; description?: string; status?: number }): CouponItem {
if (!data.name || !data.name.trim()) {
throw new Error('优惠券名称不能为空');
}
if (!data.discountAmount || data.discountAmount <= 0) {
throw new Error('减免面额必须大于0');
}
const sec = this.secService.checkText(data.name + ' ' + (data.description || ''));
if (!sec.pass) {
const err = new Error(sec.message);
(err as any).code = sec.code;
throw err;
}
const item: CouponItem = {
id: this.nextCouponId++,
name: data.name.trim(),
discountAmount: Number(data.discountAmount),
minSpend: Number(data.minSpend || 0),
validDays: Number(data.validDays || 7),
totalCount: Number(data.totalCount || 1000),
receivedCount: 0,
categoryLimit: data.categoryLimit || 'ALL',
description: data.description || '',
status: data.status !== undefined ? Number(data.status) : 1
};
this.coupons.push(item);
return item;
}
}