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 次删除

查看文件

@@ -999,6 +999,254 @@ export class MysqlRepository {
return res.affectedRows > 0;
}
// 1. 充值阶梯 (Recharge Tiers)
async getRechargeTiers(): Promise<any[]> {
const [rows]: any = await pool.query(`
SELECT
id, amount, bonus_amount as bonusAmount, tag,
sort_order as sortOrder, status,
created_at as createdAt, updated_at as updatedAt
FROM recharge_tiers
WHERE status = 1
ORDER BY sort_order ASC, amount ASC
`);
return rows;
}
async getAdminRechargeTiers(): Promise<any[]> {
const [rows]: any = await pool.query(`
SELECT
id, amount, bonus_amount as bonusAmount, tag,
sort_order as sortOrder, status,
created_at as createdAt, updated_at as updatedAt
FROM recharge_tiers
ORDER BY sort_order ASC, amount ASC
`);
return rows;
}
async createRechargeTier(data: {
amount: number;
bonusAmount?: number;
tag?: string;
sortOrder?: number;
status?: number;
}): Promise<any> {
const amount = Number(data.amount);
const bonusAmount = Number(data.bonusAmount || 0);
const tag = data.tag || '';
const sortOrder = Number(data.sortOrder || 0);
const status = data.status !== undefined ? Number(data.status) : 1;
const [res]: any = await pool.query(`
INSERT INTO recharge_tiers (amount, bonus_amount, tag, sort_order, status)
VALUES (?, ?, ?, ?, ?)
`, [amount, bonusAmount, tag, sortOrder, status]);
const newId = res.insertId;
const [rows]: any = await pool.query(`
SELECT
id, amount, bonus_amount as bonusAmount, tag,
sort_order as sortOrder, status,
created_at as createdAt, updated_at as updatedAt
FROM recharge_tiers
WHERE id = ?
`, [newId]);
return rows[0];
}
async updateRechargeTier(id: number | string, data: Partial<{
amount: number;
bonusAmount: number;
tag: string;
sortOrder: number;
status: number;
}>): Promise<any> {
const fields: string[] = [];
const values: any[] = [];
if (data.amount !== undefined) {
fields.push('amount = ?');
values.push(Number(data.amount));
}
if (data.bonusAmount !== undefined) {
fields.push('bonus_amount = ?');
values.push(Number(data.bonusAmount));
}
if (data.tag !== undefined) {
fields.push('tag = ?');
values.push(data.tag);
}
if (data.sortOrder !== undefined) {
fields.push('sort_order = ?');
values.push(Number(data.sortOrder));
}
if (data.status !== undefined) {
fields.push('status = ?');
values.push(Number(data.status));
}
if (fields.length > 0) {
values.push(id);
await pool.query(`UPDATE recharge_tiers SET ${fields.join(', ')} WHERE id = ?`, values);
}
const [rows]: any = await pool.query(`
SELECT
id, amount, bonus_amount as bonusAmount, tag,
sort_order as sortOrder, status,
created_at as createdAt, updated_at as updatedAt
FROM recharge_tiers
WHERE id = ?
`, [id]);
return rows[0] || null;
}
async deleteRechargeTier(id: number | string): Promise<boolean> {
const [res]: any = await pool.query('DELETE FROM recharge_tiers WHERE id = ?', [id]);
return res.affectedRows > 0;
}
// 2. 优惠券 (Coupons)
async getCoupons(categoryLimit?: string): Promise<any[]> {
let sql = `
SELECT
id, name, discount_amount as discountAmount, min_spend as minSpend,
valid_days as validDays, total_count as totalCount, received_count as receivedCount,
category_limit as categoryLimit, description, status,
created_at as createdAt, updated_at as updatedAt
FROM coupons
WHERE status = 1
`;
const params: any[] = [];
if (categoryLimit && categoryLimit !== 'ALL') {
sql += ' AND (category_limit = "ALL" OR category_limit = ?)';
params.push(categoryLimit);
}
sql += ' ORDER BY discount_amount DESC, id ASC';
const [rows]: any = await pool.query(sql, params);
return rows;
}
async getAdminCoupons(): Promise<any[]> {
const [rows]: any = await pool.query(`
SELECT
id, name, discount_amount as discountAmount, min_spend as minSpend,
valid_days as validDays, total_count as totalCount, received_count as receivedCount,
category_limit as categoryLimit, description, status,
created_at as createdAt, updated_at as updatedAt
FROM coupons
ORDER BY id DESC
`);
return rows;
}
async createCoupon(data: {
name: string;
discountAmount: number;
minSpend?: number;
validDays?: number;
totalCount?: number;
categoryLimit?: string;
description?: string;
status?: number;
}): Promise<any> {
const name = data.name;
const discountAmount = Number(data.discountAmount);
const minSpend = Number(data.minSpend || 0);
const validDays = Number(data.validDays || 7);
const totalCount = Number(data.totalCount || 1000);
const categoryLimit = data.categoryLimit || 'ALL';
const description = data.description || '';
const status = data.status !== undefined ? Number(data.status) : 1;
const [res]: any = await pool.query(`
INSERT INTO coupons (name, discount_amount, min_spend, valid_days, total_count, received_count, category_limit, description, status)
VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?)
`, [name, discountAmount, minSpend, validDays, totalCount, categoryLimit, description, status]);
const newId = res.insertId;
const [rows]: any = await pool.query(`
SELECT
id, name, discount_amount as discountAmount, min_spend as minSpend,
valid_days as validDays, total_count as totalCount, received_count as receivedCount,
category_limit as categoryLimit, description, status,
created_at as createdAt, updated_at as updatedAt
FROM coupons
WHERE id = ?
`, [newId]);
return rows[0];
}
async updateCoupon(id: number | string, data: Partial<{
name: string;
discountAmount: number;
minSpend: number;
validDays: number;
totalCount: number;
categoryLimit: string;
description: string;
status: number;
}>): Promise<any> {
const fields: string[] = [];
const values: any[] = [];
if (data.name !== undefined) {
fields.push('name = ?');
values.push(data.name);
}
if (data.discountAmount !== undefined) {
fields.push('discount_amount = ?');
values.push(Number(data.discountAmount));
}
if (data.minSpend !== undefined) {
fields.push('min_spend = ?');
values.push(Number(data.minSpend));
}
if (data.validDays !== undefined) {
fields.push('valid_days = ?');
values.push(Number(data.validDays));
}
if (data.totalCount !== undefined) {
fields.push('total_count = ?');
values.push(Number(data.totalCount));
}
if (data.categoryLimit !== undefined) {
fields.push('category_limit = ?');
values.push(data.categoryLimit);
}
if (data.description !== undefined) {
fields.push('description = ?');
values.push(data.description);
}
if (data.status !== undefined) {
fields.push('status = ?');
values.push(Number(data.status));
}
if (fields.length > 0) {
values.push(id);
await pool.query(`UPDATE coupons SET ${fields.join(', ')} WHERE id = ?`, values);
}
const [rows]: any = await pool.query(`
SELECT
id, name, discount_amount as discountAmount, min_spend as minSpend,
valid_days as validDays, total_count as totalCount, received_count as receivedCount,
category_limit as categoryLimit, description, status,
created_at as createdAt, updated_at as updatedAt
FROM coupons
WHERE id = ?
`, [id]);
return rows[0] || null;
}
async deleteCoupon(id: number | string): Promise<boolean> {
const [res]: any = await pool.query('DELETE FROM coupons WHERE id = ?', [id]);
return res.affectedRows > 0;
}
async getArbitrations(): Promise<any[]> {