mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-05-05 05:30:44 +08:00
- 在系统设置「功能开关」中新增邀请返利总开关,默认关闭;
关闭态:菜单隐藏、注册忽略 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 位系统码与新自定义码
- 补充单元测试与集成测试覆盖新方法、冲突路径与边界值
109 lines
2.5 KiB
TypeScript
109 lines
2.5 KiB
TypeScript
/**
|
|
* Admin Affiliate API endpoints
|
|
* Manage per-user affiliate (邀请返利) configurations:
|
|
* exclusive invite codes (overrides aff_code) and exclusive rebate rates.
|
|
*/
|
|
|
|
import { apiClient } from '../client'
|
|
import type { PaginatedResponse } from '@/types'
|
|
|
|
export interface AffiliateAdminEntry {
|
|
user_id: number
|
|
email: string
|
|
username: string
|
|
aff_code: string
|
|
aff_code_custom: boolean
|
|
aff_rebate_rate_percent?: number | null
|
|
aff_count: number
|
|
}
|
|
|
|
export interface ListAffiliateUsersParams {
|
|
page?: number
|
|
page_size?: number
|
|
search?: string
|
|
}
|
|
|
|
export interface UpdateAffiliateUserRequest {
|
|
aff_code?: string
|
|
aff_rebate_rate_percent?: number | null
|
|
/** Set true to explicitly clear the per-user rate (sets it to NULL). */
|
|
clear_rebate_rate?: boolean
|
|
}
|
|
|
|
export interface BatchSetRateRequest {
|
|
user_ids: number[]
|
|
aff_rebate_rate_percent?: number | null
|
|
/** Set true to clear rates instead of setting. */
|
|
clear?: boolean
|
|
}
|
|
|
|
export interface SimpleUser {
|
|
id: number
|
|
email: string
|
|
username: string
|
|
}
|
|
|
|
export async function listUsers(
|
|
params: ListAffiliateUsersParams = {},
|
|
): Promise<PaginatedResponse<AffiliateAdminEntry>> {
|
|
const { data } = await apiClient.get<PaginatedResponse<AffiliateAdminEntry>>(
|
|
'/admin/affiliates/users',
|
|
{
|
|
params: {
|
|
page: params.page ?? 1,
|
|
page_size: params.page_size ?? 20,
|
|
search: params.search ?? '',
|
|
},
|
|
},
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function lookupUsers(q: string): Promise<SimpleUser[]> {
|
|
const { data } = await apiClient.get<SimpleUser[]>(
|
|
'/admin/affiliates/users/lookup',
|
|
{ params: { q } },
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function updateUserSettings(
|
|
userId: number,
|
|
payload: UpdateAffiliateUserRequest,
|
|
): Promise<{ user_id: number }> {
|
|
const { data } = await apiClient.put<{ user_id: number }>(
|
|
`/admin/affiliates/users/${userId}`,
|
|
payload,
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function clearUserSettings(
|
|
userId: number,
|
|
): Promise<{ user_id: number }> {
|
|
const { data } = await apiClient.delete<{ user_id: number }>(
|
|
`/admin/affiliates/users/${userId}`,
|
|
)
|
|
return data
|
|
}
|
|
|
|
export async function batchSetRate(
|
|
payload: BatchSetRateRequest,
|
|
): Promise<{ affected: number }> {
|
|
const { data } = await apiClient.post<{ affected: number }>(
|
|
'/admin/affiliates/users/batch-rate',
|
|
payload,
|
|
)
|
|
return data
|
|
}
|
|
|
|
export const affiliatesAPI = {
|
|
listUsers,
|
|
lookupUsers,
|
|
updateUserSettings,
|
|
clearUserSettings,
|
|
batchSetRate,
|
|
}
|
|
|
|
export default affiliatesAPI
|