feat: 实现注册优惠码功能

- 支持创建/编辑/删除优惠码,设置赠送金额和使用限制
  - 注册页面实时验证优惠码并显示赠送金额
  - 支持 URL 参数自动填充 (?promo=CODE)
  - 添加优惠码验证接口速率限制
  - 使用数据库行锁防止并发超限
  - 新增后台优惠码管理页面,支持复制注册链接
This commit is contained in:
long
2026-01-10 13:14:35 +08:00
parent 7d1fe818be
commit d2fc14fb97
79 changed files with 17045 additions and 54 deletions

View File

@@ -145,7 +145,8 @@ export default {
copiedToClipboard: 'Copied to clipboard',
copyFailed: 'Failed to copy',
contactSupport: 'Contact Support',
selectOption: 'Select an option',
optional: 'optional',
selectOption: 'Select an option',
searchPlaceholder: 'Search...',
noOptionsFound: 'No options found',
noGroupsAvailable: 'No groups available',
@@ -177,6 +178,7 @@ export default {
accounts: 'Accounts',
proxies: 'Proxies',
redeemCodes: 'Redeem Codes',
promoCodes: 'Promo Codes',
settings: 'Settings',
myAccount: 'My Account',
lightMode: 'Light Mode',
@@ -229,6 +231,17 @@ export default {
sendingCode: 'Sending...',
clickToResend: 'Click to resend code',
resendCode: 'Resend verification code',
promoCodeLabel: 'Promo Code',
promoCodePlaceholder: 'Enter promo code (optional)',
promoCodeValid: 'Valid! You will receive ${amount} bonus balance',
promoCodeInvalid: 'Invalid promo code',
promoCodeNotFound: 'Promo code not found',
promoCodeExpired: 'This promo code has expired',
promoCodeDisabled: 'This promo code is disabled',
promoCodeMaxUsed: 'This promo code has reached its usage limit',
promoCodeAlreadyUsed: 'You have already used this promo code',
promoCodeValidating: 'Promo code is being validated, please wait',
promoCodeInvalidCannotRegister: 'Invalid promo code. Please check and try again or clear the promo code field',
linuxdo: {
signIn: 'Continue with Linux.do',
orContinue: 'or continue with email',
@@ -1722,6 +1735,65 @@ export default {
}
},
// Promo Codes
promo: {
title: 'Promo Code Management',
description: 'Create and manage registration promo codes',
createCode: 'Create Promo Code',
editCode: 'Edit Promo Code',
deleteCode: 'Delete Promo Code',
searchCodes: 'Search codes...',
allStatus: 'All Status',
columns: {
code: 'Code',
bonusAmount: 'Bonus Amount',
maxUses: 'Max Uses',
usedCount: 'Used',
usage: 'Usage',
status: 'Status',
expiresAt: 'Expires At',
createdAt: 'Created At',
actions: 'Actions'
},
// Form labels (flat structure for template usage)
code: 'Promo Code',
autoGenerate: 'auto-generate if empty',
codePlaceholder: 'Enter promo code or leave empty',
bonusAmount: 'Bonus Amount ($)',
maxUses: 'Max Uses',
zeroUnlimited: '0 = unlimited',
expiresAt: 'Expires At',
notes: 'Notes',
notesPlaceholder: 'Optional notes for this code',
status: 'Status',
neverExpires: 'Never expires',
// Status labels
statusActive: 'Active',
statusDisabled: 'Disabled',
statusExpired: 'Expired',
statusMaxUsed: 'Used Up',
// Usage records
usageRecords: 'Usage Records',
viewUsages: 'View Usages',
noUsages: 'No usage records yet',
userPrefix: 'User #{id}',
copied: 'Copied!',
// Messages
noCodesYet: 'No promo codes yet',
createFirstCode: 'Create your first promo code to offer registration bonuses.',
codeCreated: 'Promo code created successfully',
codeUpdated: 'Promo code updated successfully',
codeDeleted: 'Promo code deleted successfully',
deleteCodeConfirm: 'Are you sure you want to delete this promo code? This action cannot be undone.',
copyRegisterLink: 'Copy register link',
registerLinkCopied: 'Register link copied to clipboard',
failedToLoad: 'Failed to load promo codes',
failedToCreate: 'Failed to create promo code',
failedToUpdate: 'Failed to update promo code',
failedToDelete: 'Failed to delete promo code',
failedToLoadUsages: 'Failed to load usage records'
},
// Usage Records
usage: {
title: 'Usage Records',

View File

@@ -142,6 +142,7 @@ export default {
copiedToClipboard: '已复制到剪贴板',
copyFailed: '复制失败',
contactSupport: '联系客服',
optional: '可选',
selectOption: '请选择',
searchPlaceholder: '搜索...',
noOptionsFound: '无匹配选项',
@@ -175,6 +176,7 @@ export default {
accounts: '账号管理',
proxies: 'IP管理',
redeemCodes: '兑换码',
promoCodes: '优惠码',
settings: '系统设置',
myAccount: '我的账户',
lightMode: '浅色模式',
@@ -227,6 +229,17 @@ export default {
sendingCode: '发送中...',
clickToResend: '点击重新发送验证码',
resendCode: '重新发送验证码',
promoCodeLabel: '优惠码',
promoCodePlaceholder: '输入优惠码(可选)',
promoCodeValid: '有效!注册后将获得 ${amount} 赠送余额',
promoCodeInvalid: '无效的优惠码',
promoCodeNotFound: '优惠码不存在',
promoCodeExpired: '此优惠码已过期',
promoCodeDisabled: '此优惠码已被禁用',
promoCodeMaxUsed: '此优惠码已达到使用上限',
promoCodeAlreadyUsed: '您已使用过此优惠码',
promoCodeValidating: '优惠码正在验证中,请稍候',
promoCodeInvalidCannotRegister: '优惠码无效,请检查后重试或清空优惠码',
linuxdo: {
signIn: '使用 Linux.do 登录',
orContinue: '或使用邮箱密码继续',
@@ -1867,6 +1880,65 @@ export default {
failedToDelete: '删除兑换码失败'
},
// Promo Codes
promo: {
title: '优惠码管理',
description: '创建和管理注册优惠码',
createCode: '创建优惠码',
editCode: '编辑优惠码',
deleteCode: '删除优惠码',
searchCodes: '搜索优惠码...',
allStatus: '全部状态',
columns: {
code: '优惠码',
bonusAmount: '赠送金额',
maxUses: '最大使用次数',
usedCount: '已使用',
usage: '使用量',
status: '状态',
expiresAt: '过期时间',
createdAt: '创建时间',
actions: '操作'
},
// 表单标签(扁平结构便于模板使用)
code: '优惠码',
autoGenerate: '留空自动生成',
codePlaceholder: '输入优惠码或留空',
bonusAmount: '赠送金额 ($)',
maxUses: '最大使用次数',
zeroUnlimited: '0 = 无限制',
expiresAt: '过期时间',
notes: '备注',
notesPlaceholder: '可选备注信息',
status: '状态',
neverExpires: '永不过期',
// 状态标签
statusActive: '启用',
statusDisabled: '禁用',
statusExpired: '已过期',
statusMaxUsed: '已用完',
// 使用记录
usageRecords: '使用记录',
viewUsages: '查看使用记录',
noUsages: '暂无使用记录',
userPrefix: '用户 #{id}',
copied: '已复制!',
// 消息
noCodesYet: '暂无优惠码',
createFirstCode: '创建您的第一个优惠码,为新用户提供注册奖励。',
codeCreated: '优惠码创建成功',
codeUpdated: '优惠码更新成功',
codeDeleted: '优惠码删除成功',
deleteCodeConfirm: '确定要删除此优惠码吗?此操作无法撤销。',
copyRegisterLink: '复制注册链接',
registerLinkCopied: '注册链接已复制到剪贴板',
failedToLoad: '加载优惠码失败',
failedToCreate: '创建优惠码失败',
failedToUpdate: '更新优惠码失败',
failedToDelete: '删除优惠码失败',
failedToLoadUsages: '加载使用记录失败'
},
// Usage Records
usage: {
title: '使用记录',