Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | import { prisma } from '../../models'; import { MemberLevel, MEMBER_QUOTA } from '../../types'; import { generateOrderNo, handlePaymentCallback } from '../payment/payment.service'; import { safeParseInt } from '../../utils/safe-parse'; // 获取会员权益信息(新5级体系) export function getMemberBenefits() { return { levels: [ { level: 0, name: '免费版', price: 0, quota: MEMBER_QUOTA[0], features: ['每天3次生成', '每次最多5000字', '基础音色'], }, { level: 1, name: '入门版', price: MEMBER_PRICES.monthly.price, quota: MEMBER_QUOTA[1], features: ['每天10次生成', '每次最多10000字', '高清音质', '超出¥8/分钟'], }, { level: 2, name: '专业版', price: MEMBER_PRICES.monthly.price, quota: MEMBER_QUOTA[2], features: ['无限次生成', '每次最多10000字', '全部音色', '超出¥7/分钟'], }, { level: 3, name: '旗舰版', price: MEMBER_PRICES.monthly.price, quota: MEMBER_QUOTA[3], features: ['无限次生成', '无字数限制', '全部音色', 'VIP优先队列', '超出¥6/分钟'], }, { level: 4, name: '企业版', price: MEMBER_PRICES.monthly.price, quota: MEMBER_QUOTA[4], features: ['无限次生成', '无字数限制', '全部功能', '批量处理', '团队管理', '超出¥5/分钟'], }, ], }; } // 获取用户会员状态 export async function getMemberStatus(userId: string) { const user = await prisma.user.findUnique({ where: { id: safeParseInt(userId) } }); if (!user) { throw new Error('用户不存在'); } const today = new Date().toISOString().slice(0, 10); let dailyUsage = user.dailyUsage; const memberLevel = user.memberLevel; // 如果 memberLevel 超出范围,使用最高级别 const safeLevel = (memberLevel in MEMBER_QUOTA) ? (memberLevel as MemberLevel) : 4; const quota = MEMBER_QUOTA[safeLevel]; // 重置每日使用次数 if (user.lastUsageDate !== today) { dailyUsage = 0; } const isValid = memberLevel > 0 && user.memberExpireAt && new Date() < user.memberExpireAt; const levelNames = ['免费版', '入门版', '专业版', '旗舰版', '企业版']; return { level: memberLevel, levelName: levelNames[memberLevel] || levelNames[4], expireAt: user.memberExpireAt, isValid, quota: { dailyLimit: quota.dailyLimit, dailyUsed: dailyUsage, dailyRemaining: quota.dailyLimit === -1 ? -1 : Math.max(0, quota.dailyLimit - dailyUsage), wordLimit: quota.wordLimit, }, }; } // 会员价格(与 subscription 套餐体系对齐) export const MEMBER_PRICES = { monthly: { price: 19, days: 30 }, yearly: { price: 190, days: 365 }, }; // 创建订单(使用统一订单号生成) export async function createOrder( userId: string, productType: 'monthly' | 'yearly' ): Promise<{ orderNo: string; amount: number; }> { const priceInfo = MEMBER_PRICES[productType]; const orderNo = generateOrderNo(); const order = await prisma.order.create({ data: { userId: safeParseInt(userId), orderNo, productType, amount: priceInfo.price, status: 'pending', }, }); return { orderNo: order.orderNo, amount: Number(order.amount), }; } // 模拟支付成功(委托给新支付系统) export async function mockPaymentSuccess(orderNo: string, userId: string) { return handlePaymentCallback(orderNo, 'MOCK_' + Date.now(), 'success'); } // 获取订单列表 export async function getOrders(userId: string, page: number = 1, pageSize: number = 10) { const uid = safeParseInt(userId); const total = await prisma.order.count({ where: { userId: uid } }); const list = await prisma.order.findMany({ where: { userId: uid }, orderBy: { createdAt: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }); return { list, total, page, pageSize, totalPages: Math.ceil(total / pageSize), }; } |