feat(抽奖): 开放人工奖(crypto/physical/manual_other) + 领奖工单管理 + REST 对齐
- prize-form: 解禁 crypto/physical/manual_other 并加各自 config;权重改为中奖概率(%), 合计校验;vpn_duration 加"无订阅时新建订阅套餐" - prize-grid: 概率合计=100% 校验告警;卡片渲染真实 config(时长/金额) - claims-panel(新): 领奖工单列表 + 审核通过/驳回/标记发放 - activity-detail: 新增"领奖工单"Tab - service: 奖品改/删 id 走 /prizes/:id(对齐后端 REST);新增 claims 5 个接口 + 类型 - i18n: 补齐 zh-CN/en-US lottery 文案 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -202,14 +202,15 @@ export async function updateLotteryPrize(
|
||||
body: API.UpdateLotteryPrizeRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
const { id, ...rest } = body;
|
||||
return request<API.Response & { data?: API.LotteryPrize }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/prizes`,
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/prizes/${id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
data: rest,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
@@ -227,13 +228,9 @@ export async function deleteLotteryPrize(
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/prizes`,
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/prizes/${body.id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
@@ -285,3 +282,94 @@ export async function grantLotteryChances(
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领奖工单列表(Stage 2 人工奖)
|
||||
* GET /v1/admin/lottery/claims
|
||||
*/
|
||||
export async function getLotteryClaimList(
|
||||
params: API.GetLotteryClaimListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: API.ListLotteryClaimsResponse }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/claims`,
|
||||
{
|
||||
method: "GET",
|
||||
params: { ...params },
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领奖工单统计(各类型 reviewing/paying + 逾期)
|
||||
* GET /v1/admin/lottery/claims/summary
|
||||
*/
|
||||
export async function getLotteryClaimsSummary(options?: {
|
||||
[key: string]: any;
|
||||
}) {
|
||||
return request<API.Response & { data?: API.LotteryClaimsSummary }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/claims/summary`,
|
||||
{
|
||||
method: "GET",
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过领奖工单(reviewing → paying)
|
||||
* POST /v1/admin/lottery/claims/approve
|
||||
*/
|
||||
export async function approveLotteryClaim(
|
||||
body: API.ApproveLotteryClaimRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/claims/approve`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回领奖工单(reviewing/paying → rejected,reason 必填)
|
||||
* POST /v1/admin/lottery/claims/reject
|
||||
*/
|
||||
export async function rejectLotteryClaim(
|
||||
body: API.RejectLotteryClaimRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/claims/reject`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记已发放(paying → paid),填 tx_hash / delivery_ref
|
||||
* POST /v1/admin/lottery/claims/mark-paid
|
||||
*/
|
||||
export async function markPaidLotteryClaim(
|
||||
body: API.MarkPaidLotteryClaimRequest,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.Response & { data?: any }>(
|
||||
`${import.meta.env.VITE_API_PREFIX || ""}/v1/admin/lottery/claims/mark-paid`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+105
-17
@@ -3302,25 +3302,25 @@ declare namespace API {
|
||||
type AdminWithdrawalLog = WithdrawalLog;
|
||||
|
||||
type LotteryPrizeType =
|
||||
| 'vpn_duration'
|
||||
| 'commission'
|
||||
| 'none'
|
||||
| 'crypto'
|
||||
| 'physical'
|
||||
| 'manual_other'
|
||||
| 'coupon'
|
||||
| 'points';
|
||||
| "vpn_duration"
|
||||
| "commission"
|
||||
| "none"
|
||||
| "crypto"
|
||||
| "physical"
|
||||
| "manual_other"
|
||||
| "coupon"
|
||||
| "points";
|
||||
|
||||
type LotteryActivityStatus = 'draft' | 'running' | 'paused' | 'ended';
|
||||
type LotteryActivityStatus = "draft" | "running" | "paused" | "ended";
|
||||
|
||||
type LotteryChanceSourceType =
|
||||
| 'daily_signin'
|
||||
| 'new_subscription'
|
||||
| 'invite_success'
|
||||
| 'manual_grant';
|
||||
| "daily_signin"
|
||||
| "new_subscription"
|
||||
| "invite_success"
|
||||
| "manual_grant";
|
||||
|
||||
type LotteryEligibilityNode = {
|
||||
op?: 'AND' | 'OR';
|
||||
op?: "AND" | "OR";
|
||||
children?: LotteryEligibilityNode[];
|
||||
type?: string;
|
||||
params?: Record<string, any>;
|
||||
@@ -3371,11 +3371,20 @@ declare namespace API {
|
||||
unmet_action: string;
|
||||
};
|
||||
|
||||
type UpdateLotteryActivityRequest = CreateLotteryActivityRequest & { id: number };
|
||||
type UpdateLotteryActivityRequest = CreateLotteryActivityRequest & {
|
||||
id: number;
|
||||
};
|
||||
|
||||
type GetLotteryActivityListParams = { page: number; size: number; status?: string };
|
||||
type GetLotteryActivityListParams = {
|
||||
page: number;
|
||||
size: number;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
type GetLotteryActivityListResponse = { total: number; list: LotteryActivity[] };
|
||||
type GetLotteryActivityListResponse = {
|
||||
total: number;
|
||||
list: LotteryActivity[];
|
||||
};
|
||||
|
||||
type GetLotteryActivityDetailParams = { id: number };
|
||||
|
||||
@@ -3415,4 +3424,83 @@ declare namespace API {
|
||||
amount: number;
|
||||
source_ref: string;
|
||||
};
|
||||
|
||||
// ---- Stage 2 领奖工单(人工奖)--------------------------------------------
|
||||
|
||||
type LotteryClaimStatus =
|
||||
| "pending_claim"
|
||||
| "reviewing"
|
||||
| "paying"
|
||||
| "paid"
|
||||
| "rejected"
|
||||
| "expired";
|
||||
|
||||
type GetLotteryClaimListParams = {
|
||||
type?: LotteryPrizeType;
|
||||
status?: LotteryClaimStatus;
|
||||
activity_id?: number;
|
||||
user_id?: number;
|
||||
from?: number;
|
||||
to?: number;
|
||||
page: number;
|
||||
size: number;
|
||||
};
|
||||
|
||||
type AdminLotteryClaimUser = {
|
||||
id: number;
|
||||
email?: string;
|
||||
};
|
||||
|
||||
type AdminLotteryClaimPrize = {
|
||||
type: LotteryPrizeType;
|
||||
name: string;
|
||||
config: Record<string, any>;
|
||||
};
|
||||
|
||||
type AdminLotteryClaim = {
|
||||
id: number;
|
||||
draw_id: number;
|
||||
activity_id: number;
|
||||
user: AdminLotteryClaimUser;
|
||||
prize: AdminLotteryClaimPrize;
|
||||
status: LotteryClaimStatus;
|
||||
claim_data?: Record<string, any>;
|
||||
submitted_at?: number;
|
||||
expires_at: number;
|
||||
reviewed_by?: number;
|
||||
reviewed_at?: number;
|
||||
reject_reason?: string;
|
||||
tx_hash?: string;
|
||||
delivery_ref?: string;
|
||||
paid_at?: number;
|
||||
created_at: number;
|
||||
};
|
||||
|
||||
type ListLotteryClaimsResponse = {
|
||||
total: number;
|
||||
claims: AdminLotteryClaim[];
|
||||
};
|
||||
|
||||
type LotteryClaimsStatusCount = {
|
||||
reviewing: number;
|
||||
paying: number;
|
||||
};
|
||||
|
||||
type LotteryClaimsSummary = {
|
||||
crypto: LotteryClaimsStatusCount;
|
||||
physical: LotteryClaimsStatusCount;
|
||||
manual_other: LotteryClaimsStatusCount;
|
||||
overdue: number;
|
||||
};
|
||||
|
||||
type ApproveLotteryClaimRequest = { id: number };
|
||||
|
||||
type RejectLotteryClaimRequest = { id: number; reason: string };
|
||||
|
||||
type MarkPaidLotteryClaimRequest = {
|
||||
id: number;
|
||||
tx_hash?: string;
|
||||
delivery_ref?: string;
|
||||
paid_at?: number;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user