mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-05-05 21:50:44 +08:00
feat(affiliate): add feature toggle and per-user custom invite settings
- 在系统设置「功能开关」中新增邀请返利总开关,默认关闭;
关闭态:菜单隐藏、注册忽略 aff、新充值不返利,但已有 quota 仍可转余额
- 支持管理员为指定用户设置专属邀请码(覆盖随机码,全局唯一)
- 支持管理员为指定用户设置专属返利比例(覆盖全局比例,可单条/批量调整)
- 在系统设置邀请返利卡片内嵌入专属用户管理表格(搜索/编辑/批量/删除),
删除采用项目通用 ConfirmDialog,会同时清除专属比例并把邀请码重置为系统随机码
- /affiliate 用户页新增「我的返利比例」卡片与动态使用说明,让用户直观看到
分享后能拿到多少(同源 resolveRebateRatePercent 计算,与实际充值一致)
- 新增数据库迁移 132 添加 aff_rebate_rate_percent 与 aff_code_custom 列
- 新增 admin 路由组 /api/v1/admin/affiliates/users/* 共 5 个端点
- AffiliateService 改为只依赖 *SettingService,去除冗余的 SettingRepository
- 邀请码格式校验放宽到 [A-Z0-9_-]{4,32},兼容旧 12 位系统码与新自定义码
- 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
This commit is contained in:
@@ -985,6 +985,8 @@ export default {
|
||||
loadFailed: 'Failed to load affiliate data',
|
||||
transferFailed: 'Failed to transfer affiliate quota',
|
||||
stats: {
|
||||
rebateRate: 'My Rebate Rate',
|
||||
rebateRateHint: 'What you earn each time an invitee recharges',
|
||||
invitedUsers: 'Invited Users',
|
||||
availableQuota: 'Available Rebate Quota',
|
||||
totalQuota: 'Historical Rebate Quota'
|
||||
@@ -1009,7 +1011,7 @@ export default {
|
||||
tips: {
|
||||
title: 'How It Works',
|
||||
line1: 'Share your affiliate code or invite link with new users.',
|
||||
line2: 'When invitees recharge, you receive rebate quota based on the configured rate.',
|
||||
line2: 'When invitees recharge, you receive {rate} of the recharge as rebate quota.',
|
||||
line3: 'Transfer rebate quota to balance at any time.'
|
||||
}
|
||||
},
|
||||
@@ -4779,6 +4781,55 @@ export default {
|
||||
enabled: 'Enable Available Channels',
|
||||
enabledHint: 'When off, the sidebar entry is hidden and the endpoint returns an empty list.',
|
||||
},
|
||||
affiliate: {
|
||||
title: 'Affiliate (Invite Rebate)',
|
||||
description: 'Existing users invite new ones; the inviter earns a percentage rebate on the invitee’s recharges. Disabled by default.',
|
||||
enabled: 'Enable Affiliate',
|
||||
enabledHint: 'When off, the affiliate menu is hidden, the aff parameter is ignored at signup, and new recharges generate no rebate. Existing rebate balances can still be transferred.',
|
||||
rebateRate: 'Global Rebate Rate',
|
||||
rebateRateHint: 'Default percentage given back to the inviter on recharges (0-100, e.g. 10 = 10%).',
|
||||
customUsers: {
|
||||
title: 'Per-User Overrides',
|
||||
description: 'Set a custom invite code or exclusive rebate rate for specific users. Lists only users that have an override applied.',
|
||||
addButton: 'Add Custom User',
|
||||
searchPlaceholder: 'Search by email or username',
|
||||
batchButton: 'Batch Set Rate ({count} selected)',
|
||||
empty: 'No users with custom affiliate settings yet',
|
||||
customBadge: 'custom',
|
||||
useGlobal: 'use global',
|
||||
resetTitle: 'Reset Custom Settings',
|
||||
resetMessage: 'Reset all custom settings for {email}?\n• The exclusive rebate rate will be cleared (fall back to the global rate)\n• The invite code will be regenerated as a new system code (previously shared links will stop working)',
|
||||
totalLabel: '{total} total',
|
||||
col: {
|
||||
email: 'Email',
|
||||
username: 'Username',
|
||||
code: 'Invite Code',
|
||||
rate: 'Custom Rate',
|
||||
actions: 'Actions',
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
addTitle: 'Add Custom User',
|
||||
editTitle: 'Edit Custom Settings',
|
||||
userLabel: 'User',
|
||||
userPlaceholder: 'Search by email or username',
|
||||
changeUser: 'Change user',
|
||||
codeLabel: 'Custom Invite Code (optional)',
|
||||
codePlaceholder: 'e.g. VIP2026',
|
||||
codeHint: '4-32 characters; A-Z, 0-9, underscore, dash. Leave empty to keep current. Input is upper-cased.',
|
||||
rateLabel: 'Exclusive Rebate Rate (optional)',
|
||||
ratePlaceholder: 'e.g. 30',
|
||||
rateHint: '0-100. Leave empty (in edit mode) to clear and fall back to the global rate.',
|
||||
errorBadRate: 'Please enter a number between 0 and 100',
|
||||
errorEmpty: 'Fill at least one: custom invite code or exclusive rebate rate',
|
||||
},
|
||||
batchModal: {
|
||||
title: 'Batch Set Rate ({count} users selected)',
|
||||
hint: 'Apply the same exclusive rebate rate to all selected users.',
|
||||
placeholder: 'e.g. 30',
|
||||
clearHint: 'Submitting empty will clear the exclusive rate for selected users.',
|
||||
},
|
||||
},
|
||||
},
|
||||
emailTabDisabledTitle: 'Email Verification Not Enabled',
|
||||
emailTabDisabledHint: 'Enable email verification in the Security tab to configure SMTP settings.',
|
||||
|
||||
@@ -989,6 +989,8 @@ export default {
|
||||
loadFailed: '加载邀请返利数据失败',
|
||||
transferFailed: '转入余额失败',
|
||||
stats: {
|
||||
rebateRate: '我的返利比例',
|
||||
rebateRateHint: '被邀请用户每次充值后你可获得的返利比例',
|
||||
invitedUsers: '邀请人数',
|
||||
availableQuota: '可转返利额度',
|
||||
totalQuota: '历史返利额度'
|
||||
@@ -1013,7 +1015,7 @@ export default {
|
||||
tips: {
|
||||
title: '使用说明',
|
||||
line1: '将邀请码或邀请链接分享给新用户。',
|
||||
line2: '被邀请用户充值后,你可获得对应比例的返利额度。',
|
||||
line2: '被邀请用户充值后,你可获得 {rate} 的返利额度。',
|
||||
line3: '返利额度可随时转入账户余额。'
|
||||
}
|
||||
},
|
||||
@@ -4942,6 +4944,55 @@ export default {
|
||||
enabled: '启用可用渠道',
|
||||
enabledHint: '关闭后用户端侧边栏入口隐藏,接口返回空数组。',
|
||||
},
|
||||
affiliate: {
|
||||
title: '邀请返利',
|
||||
description: '老用户邀请新用户注册,新用户充值后老用户按比例获得返利额度。默认关闭。',
|
||||
enabled: '启用邀请返利',
|
||||
enabledHint: '关闭后用户菜单中的邀请页面入口隐藏、注册时忽略邀请码、新充值不再产生返利。已有返利额度仍可转入余额。',
|
||||
rebateRate: '全局返利比例',
|
||||
rebateRateHint: '充值后返给邀请人的默认比例(0-100%,例如填写 10 表示返利 10%)。',
|
||||
customUsers: {
|
||||
title: '专属用户配置',
|
||||
description: '为指定用户设置专属邀请码或专属返利比例。仅展示已设置过专属配置的用户。',
|
||||
addButton: '添加专属用户',
|
||||
searchPlaceholder: '搜索邮箱或用户名',
|
||||
batchButton: '批量设置比例(已选 {count})',
|
||||
empty: '暂无专属配置用户',
|
||||
customBadge: '自定义',
|
||||
useGlobal: '沿用全局',
|
||||
resetTitle: '重置该用户的专属配置',
|
||||
resetMessage: '确认将 {email} 的专属配置全部重置为默认?\n• 专属返利比例将清除(沿用全局)\n• 邀请码将重新生成为系统随机码(已分发的旧邀请链接将失效)',
|
||||
totalLabel: '共 {total} 条',
|
||||
col: {
|
||||
email: '邮箱',
|
||||
username: '用户名',
|
||||
code: '邀请码',
|
||||
rate: '专属比例',
|
||||
actions: '操作',
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
addTitle: '添加专属用户',
|
||||
editTitle: '编辑专属配置',
|
||||
userLabel: '用户',
|
||||
userPlaceholder: '搜索邮箱或用户名',
|
||||
changeUser: '更换用户',
|
||||
codeLabel: '专属邀请码(可选)',
|
||||
codePlaceholder: '例如 VIP2026',
|
||||
codeHint: '4-32 位,仅支持大写字母、数字、下划线、连字符;留空表示不修改;输入将自动转大写。',
|
||||
rateLabel: '专属返利比例(可选)',
|
||||
ratePlaceholder: '例如 30',
|
||||
rateHint: '0-100%;留空(编辑模式下)表示清除专属比例并沿用全局。',
|
||||
errorBadRate: '请输入 0-100 之间的比例',
|
||||
errorEmpty: '至少填写一项:专属邀请码或专属返利比例',
|
||||
},
|
||||
batchModal: {
|
||||
title: '批量设置专属比例(已选 {count} 个用户)',
|
||||
hint: '为所选用户统一设置专属返利比例。',
|
||||
placeholder: '例如 30',
|
||||
clearHint: '留空提交将清除所选用户的专属比例。',
|
||||
},
|
||||
},
|
||||
},
|
||||
emailTabDisabledTitle: '邮箱验证未启用',
|
||||
emailTabDisabledHint: '请在「安全与认证」选项卡中启用邮箱验证后,再配置 SMTP 设置。',
|
||||
|
||||
Reference in New Issue
Block a user