Files
affiliate_dash/frontend/src/api/index.ts
T
zhaoxing a9473990be refactor: 移除 Rock 发货处理中状态,新增异常派生筛选标记
- 新增迁移 028:历史 redeeming 回退为 bound,重建 pending 部分索引
- pending 语义改为 bound + redeem_requested_at 标记,不再写状态与状态日志
- 新增 anomaly 虚拟筛选项:基于状态日志派生异常标记,不改状态、不落库
- 状态列追加「⚠️ 异常」标签,统计新增 anomaly_stock
- 清理前后端 redeeming 相关分支与文案
2026-11-14 15:40:19 +08:00

1048 lines
31 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import request from "./request";
import type {
DashboardStats,
AlertChannelInput,
AlertNotifyChannel,
ApiClient,
ApiCredential,
CallbackCredential,
CallbackSubscription,
CreateManualOrderResult,
CreateTestOrderResult,
DeliveryBindResult,
DeliveryOrderInfo,
DeliveryLinkResult,
DeliverySubmitResult,
FulfillmentOrder,
LoginResult,
LowBalanceAlertConfig,
Merchant,
MerchantMember,
MerchantMemberGroup,
MerchantOption,
MerchantOwnerAccount,
MerchantRole,
MerchantProduct,
PageResult,
ProductCatalogItem,
RechargeApplication,
User,
WalletAccount,
WalletLedgerEntry,
LewanProductListResult,
UpdateProductRoutingInput,
SyncLewanProductInput,
SendLoginSMSCodeResult,
PreparedDeviceLogin,
DCAuthChallengeStatus,
} from "../types";
export const authApi = {
login: async (username: string, password: string) => {
const res = await request.post("/auth/login", { username, password });
return res.data.data as LoginResult;
},
sendLoginSmsCode: async (username: string, password: string) => {
const res = await request.post("/auth/login/sms-code", {
username,
password,
});
return res.data.data as SendLoginSMSCodeResult;
},
prepareLogin: async (data: {
username: string;
password: string;
smsCode: string;
apiBase?: string;
}) => {
const res = await request.post("/auth/login/prepare", data);
return res.data.data as PreparedDeviceLogin;
},
completeLogin: async (data: {
challengeId: string;
pollToken: string;
deviceTicket: string;
}) => {
const res = await request.post("/auth/login/complete", data);
return res.data.data as LoginResult;
},
deviceChallengeStatus: async (challengeId: string, pollToken: string) => {
const res = await request.get(
`/dcauth/challenge/${encodeURIComponent(challengeId)}/status`,
{
params: { pollToken },
},
);
return res.data.data as DCAuthChallengeStatus;
},
profile: async () => {
const res = await request.get("/auth/profile");
return res.data.data as User;
},
changePassword: (data: { current_password: string; new_password: string }) =>
request.put("/auth/password", data).then((r) => r.data.data),
updateCurrentAccount: (data: {
current_password: string;
username: string;
nickname?: string;
new_password?: string;
}) => request.put("/auth/account", data).then((r) => r.data.data as User),
};
export const dashboardApi = {
stats: () =>
request.get("/dashboard").then((r) => r.data.data as DashboardStats),
};
export const userApi = {
list: (params?: Record<string, unknown>) =>
request
.get("/platform/admins", { params })
.then((r) => r.data.data as PageResult<User>),
create: (data: {
username: string
password: string
nickname?: string
}) => request.post("/platform/admins", data).then((r) => r.data.data as User),
update: (
id: number,
data: {
username: string
nickname?: string
password?: string
status: number
},
) =>
request
.patch(`/platform/admins/${id}`, data)
.then((r) => r.data.data as User),
remove: (id: number) =>
request.delete(`/platform/admins/${id}`).then((r) => r.data.data),
bindPhone: (id: number, phone: string) =>
request
.post(`/admin/users/${id}/phone`, { phone })
.then((r) => r.data.data as User),
resetDevice: (id: number) =>
request
.post(`/admin/users/${id}/device/reset`)
.then((r) => r.data.data as { reset: boolean }),
};
export const merchantApi = {
current: () =>
request.get("/merchant").then(
(r) =>
r.data.data as {
merchant: Merchant;
role: string;
permissions: string[];
},
),
products: (params?: Record<string, unknown>) =>
request
.get("/merchant/products", { params })
.then((r) => r.data.data as PageResult<MerchantProduct>),
updateProduct: (
id: number,
data: {
display_name?: string;
price_amount?: number;
cost_amount?: number;
stock?: number;
status?: "active" | "inactive";
},
) => request.patch(`/merchant/products/${id}`, data).then((r) => r.data.data),
updateProductStatus: (id: number, status: MerchantProduct["status"]) =>
request
.patch(`/merchant/products/${id}/status`, { status })
.then((r) => r.data.data),
deleteProduct: (id: number) =>
request.delete(`/merchant/products/${id}`).then((r) => r.data.data),
orders: (params?: Record<string, unknown>) =>
request
.get("/merchant/orders", { params })
.then((r) => r.data.data as PageResult<FulfillmentOrder>),
manualOrderProducts: () =>
request
.get("/merchant/orders/products")
.then((r) => r.data.data as MerchantProduct[]),
createTestOrder: (data: {
sku: string;
buyer_reference?: string;
note?: string;
order_status?: "paid" | "ship_failed" | "cancelled";
}) =>
request
.post("/merchant/orders/test", data)
.then((r) => r.data.data as CreateTestOrderResult),
createManualOrder: (data: {
client_order_no: string;
sku: string;
quantity: number;
buyer_reference?: string;
game_account?: string;
note?: string;
}) =>
request
.post("/merchant/orders/manual", data)
.then((r) => r.data.data as CreateManualOrderResult),
cancelOrder: (orderNo: string, reason: string) =>
request
.post(`/merchant/orders/${encodeURIComponent(orderNo)}/cancel`, {
reason,
})
.then(
(r) =>
r.data.data as { order: FulfillmentOrder; refund_amount: number },
),
getDeliveryLink: (orderNo: string) =>
request
.get(`/merchant/orders/${encodeURIComponent(orderNo)}/delivery-link`)
.then((r) => r.data.data as DeliveryLinkResult),
revokeDeliveryLink: (orderNo: string) =>
request
.post(
`/merchant/orders/${encodeURIComponent(orderNo)}/delivery-link/revoke`,
)
.then((r) => r.data.data),
restoreDeliveryLink: (orderNo: string) =>
request
.post(
`/merchant/orders/${encodeURIComponent(orderNo)}/delivery-link/restore`,
)
.then((r) => r.data.data as DeliveryLinkResult),
wallet: () =>
request.get("/merchant/wallet").then((r) => r.data.data as WalletAccount),
ledger: (params?: Record<string, unknown>) =>
request
.get("/merchant/wallet/ledger", { params })
.then((r) => r.data.data as PageResult<WalletLedgerEntry>),
apiClients: () =>
request
.get("/merchant/api-clients")
.then((r) => r.data.data as ApiClient[]),
createApiClient: (data: {
name: string;
scopes: string;
signature_version?: string;
expires_at?: string;
}) =>
request
.post("/merchant/api-clients", data)
.then((r) => r.data.data as ApiCredential),
updateApiClientStatus: (id: number, status: ApiClient["status"]) =>
request
.patch(`/merchant/api-clients/${id}/status`, { status })
.then((r) => r.data.data),
deleteApiClient: (id: number) =>
request.delete(`/merchant/api-clients/${id}`).then((r) => r.data.data),
callbacks: () =>
request
.get("/merchant/callbacks")
.then((r) => r.data.data as CallbackSubscription | null),
saveCallback: (data: {
url: string;
events: string;
status: CallbackSubscription["status"];
rotate_secret?: boolean;
}) =>
request
.post("/merchant/callbacks", data)
.then((r) => r.data.data as CallbackCredential),
members: () =>
request
.get("/merchant/members")
.then((r) => r.data.data as MerchantMember[]),
addMember: (data: {
user_id?: number;
username?: string;
password?: string;
nickname?: string;
role: string;
is_default?: boolean;
}) =>
request
.post("/merchant/members", data)
.then((r) => r.data.data as MerchantMember),
updateMember: (
id: number,
data: {
username?: string;
password?: string;
nickname?: string;
role: string;
status: number;
is_default: boolean;
},
) =>
request
.patch(`/merchant/members/${id}`, data)
.then((r) => r.data.data as MerchantMember),
removeMember: (id: number) =>
request.delete(`/merchant/members/${id}`).then((r) => r.data.data),
bindMemberPhone: (id: number, phone: string) =>
request
.post(`/merchant/members/${id}/phone`, { phone })
.then((r) => r.data.data as User),
resetMemberDevice: (id: number) =>
request
.post(`/merchant/members/${id}/device/reset`)
.then((r) => r.data.data as { reset: boolean }),
roles: () =>
request.get("/merchant/roles").then((r) => r.data.data as MerchantRole[]),
createRole: (data: { code: string; name: string; permissions: string[] }) =>
request
.post("/merchant/roles", data)
.then((r) => r.data.data as MerchantRole),
updateRole: (id: number, data: { name: string; permissions: string[] }) =>
request
.patch(`/merchant/roles/${id}`, data)
.then((r) => r.data.data as MerchantRole),
rechargeApplications: (params?: Record<string, unknown>) =>
request
.get("/merchant/recharge/applications", { params })
.then((r) => r.data.data as PageResult<RechargeApplication>),
createRechargeApplication: (data: {
amount_cny: number;
vouchers: string[];
note?: string;
}) =>
// amount_cny 单位:分(1元 = 100分),积分按 1元 = 100积分 折算
request
.post("/merchant/recharge/applications", data)
.then((r) => r.data.data as RechargeApplication),
alertConfig: () =>
request
.get("/merchant/recharge/alert-config")
.then((r) => r.data.data as LowBalanceAlertConfig),
saveAlertConfig: (data: {
enabled: boolean;
threshold_points: number;
notify_interval_minutes: number;
max_notifications: number;
}) =>
request
.put("/merchant/recharge/alert-config", data)
.then((r) => r.data.data as LowBalanceAlertConfig),
alertChannels: () =>
request
.get("/merchant/alert-channels")
.then((r) => r.data.data as AlertNotifyChannel[]),
createAlertChannel: (data: AlertChannelInput) =>
request
.post("/merchant/alert-channels", data)
.then((r) => r.data.data as AlertNotifyChannel),
updateAlertChannel: (id: number, data: AlertChannelInput) =>
request
.put(`/merchant/alert-channels/${id}`, data)
.then((r) => r.data.data as AlertNotifyChannel),
deleteAlertChannel: (id: number) =>
request.delete(`/merchant/alert-channels/${id}`).then((r) => r.data.data),
testAlertChannel: (id: number) =>
request
.post(`/merchant/alert-channels/${id}/test`)
.then((r) => r.data.data),
};
export const uploadApi = {
file: (file: File) => {
const form = new FormData();
form.append("file", file);
return request
.post("/upload", form, {
headers: { "Content-Type": "multipart/form-data" },
timeout: 60000,
})
.then((r) => r.data.data as { url: string });
},
};
export const deliveryApi = {
getOrder: (orderNo: string, auth?: { exp?: string; sign?: string }) =>
request
.get(`/delivery/v1/orders/${encodeURIComponent(orderNo)}`, {
params: auth,
})
.then((r) => r.data.data as DeliveryOrderInfo),
bind: (
orderNo: string,
gameAccount: string,
auth?: { exp?: string; sign?: string },
) =>
request
.post(
`/delivery/v1/orders/${encodeURIComponent(orderNo)}/bind`,
{
game_account: gameAccount,
},
{ params: auth },
)
.then((r) => r.data.data as DeliveryBindResult),
getBindResult: (
orderNo: string,
bindUUID: string,
auth?: { exp?: string; sign?: string },
) =>
request
.get(`/delivery/v1/orders/${encodeURIComponent(orderNo)}/bind-result`, {
params: { ...auth, bind_uuid: bindUUID },
})
.then((r) => r.data.data as DeliveryBindResult),
submit: (
orderNo: string,
gameAccount: string,
bindUUID: string,
auth?: { exp?: string; sign?: string },
) =>
request
.post(
`/delivery/v1/orders/${encodeURIComponent(orderNo)}/submit`,
{
game_account: gameAccount,
bind_uuid: bindUUID,
},
{ params: auth },
)
.then((r) => r.data.data as DeliverySubmitResult),
};
export const platformApi = {
merchantAccounts: (params?: Record<string, unknown>) =>
request
.get("/platform/merchant-accounts", { params })
.then((r) => r.data.data as PageResult<MerchantMemberGroup>),
deleteMerchantAccount: (userId: number) =>
request
.delete(`/platform/merchant-accounts/${userId}`)
.then((r) => r.data.data),
merchants: (params?: Record<string, unknown>) =>
request
.get("/platform/merchants", { params })
.then((r) => r.data.data as PageResult<Merchant>),
// 不分页的精简商户列表,供筛选下拉使用(/platform/merchants 的 size 上限是 100)
merchantOptions: () =>
request
.get("/platform/merchant-options")
.then((r) => r.data.data as MerchantOption[]),
// 平台侧跨商户订单视图:不传 merchant_id 即全部商户
orders: (params?: Record<string, unknown>) =>
request
.get("/platform/orders", { params })
.then((r) => r.data.data as PageResult<FulfillmentOrder>),
createMerchant: (data: {
code: string;
name: string;
contact_name?: string;
contact_info?: string;
owner_user_id?: number;
owner_username?: string;
owner_password?: string;
owner_nickname?: string;
features?: string;
fee_type?: "rate" | "fixed";
fee_rate_bp?: number;
fee_fixed_amount?: number;
}) =>
request
.post("/platform/merchants", data)
.then((r) => r.data.data as Merchant),
updateMerchant: (id: number, data: Partial<Merchant>) =>
request.patch(`/platform/merchants/${id}`, data).then((r) => r.data.data),
members: (merchantId: number) =>
request
.get(`/platform/merchants/${merchantId}/members`)
.then((r) => r.data.data as MerchantMember[]),
addMember: (
merchantId: number,
data: {
user_id?: number;
username?: string;
password?: string;
nickname?: string;
role: string;
is_default?: boolean;
},
) =>
request
.post(`/platform/merchants/${merchantId}/members`, data)
.then((r) => r.data.data as MerchantMember),
updateMember: (
merchantId: number,
memberId: number,
data: { role: string; status: number; is_default: boolean },
) =>
request
.patch(`/platform/merchants/${merchantId}/members/${memberId}`, data)
.then((r) => r.data.data as MerchantMember),
removeMember: (merchantId: number, memberId: number) =>
request
.delete(`/platform/merchants/${merchantId}/members/${memberId}`)
.then((r) => r.data.data),
roles: (merchantId: number) =>
request
.get(`/platform/merchants/${merchantId}/roles`)
.then((r) => r.data.data as MerchantRole[]),
productCatalog: () =>
request
.get("/platform/product-catalog")
.then((r) => r.data.data as ProductCatalogItem[]),
merchantProducts: (merchantId: number) =>
request
.get(`/platform/merchants/${merchantId}/products`)
.then((r) => r.data.data as ProductCatalogItem[]),
updateMerchantProduct: (
merchantId: number,
productId: number,
data: Partial<MerchantProduct>,
) =>
request
.patch(`/platform/merchants/${merchantId}/products/${productId}`, data)
.then((r) => r.data.data),
assignProducts: (merchantId: number, catalogIds: number[]) =>
request
.post(`/platform/merchants/${merchantId}/products/assign`, {
catalog_ids: catalogIds,
})
.then((r) => r.data.data as { assigned: number }),
wallet: (merchantId: number) =>
request
.get(`/platform/merchants/${merchantId}/wallet`)
.then((r) => r.data.data as WalletAccount),
merchantAccount: (merchantId: number) =>
request
.get(`/platform/merchants/${merchantId}/account`)
.then((r) => r.data.data as MerchantOwnerAccount[]),
updateMerchantAccount: (
merchantId: number,
data: {
user_id: number;
username: string;
nickname?: string;
password?: string;
status?: number;
},
) =>
request
.patch(`/platform/merchants/${merchantId}/account`, data)
.then((r) => r.data.data as MerchantOwnerAccount),
walletLedger: (merchantId: number, params?: Record<string, unknown>) =>
request
.get(`/platform/merchants/${merchantId}/wallet/ledger`, { params })
.then((r) => r.data.data as PageResult<WalletLedgerEntry>),
adjustWallet: (
merchantId: number,
data: { amount: number; idempotency_key: string; note?: string },
) =>
request
.post(`/platform/merchants/${merchantId}/wallet/adjust`, data)
.then((r) => r.data.data as WalletAccount),
rechargeApplications: (params?: Record<string, unknown>) =>
request
.get("/platform/recharge/applications", { params })
.then((r) => r.data.data as PageResult<RechargeApplication>),
reviewRechargeApplication: (
id: number,
data: { approved: boolean; review_note?: string },
) =>
request
.post(`/platform/recharge/applications/${id}/review`, data)
.then((r) => r.data.data as RechargeApplication),
};
export const lewanApi = {
listProducts: (params?: { page?: number; size?: number; keyword?: string }) =>
request
.get("/platform/lewan/products", { params })
.then((r) => r.data.data as LewanProductListResult),
syncCatalog: (data: SyncLewanProductInput) =>
request
.post("/platform/lewan/sync-catalog", data)
.then((r) => r.data.data as ProductCatalogItem),
batchSyncCatalog: (products: SyncLewanProductInput[]) =>
request
.post("/platform/lewan/batch-sync-catalog", { products })
.then((r) => r.data.data as { synced_count: number }),
updateRouting: (id: number, data: UpdateProductRoutingInput) =>
request
.put(`/platform/products/${id}/routing`, data)
.then((r) => r.data.data as { updated: boolean }),
};
export interface RockConfig {
id: number;
auto_delivery_enabled: boolean;
base_url: string;
bearer_token: string;
username: string;
points: number;
black_token_cost: number;
min_points_warning: number;
token_warning_stock: number;
using_warn_days: number;
using_danger_days: number;
bound_warn_days: number;
auto_refresh_mismatch_enabled: boolean;
auto_purchase_enabled: boolean;
auto_purchase_count: number;
purchase_cooldown_minutes: number;
login_username?: string;
login_password_set?: boolean;
last_token_refresh_at?: string;
last_token_error?: string;
last_purchased_at?: string;
last_heartbeat_at?: string;
}
export interface RockStats {
available_stock: number;
using_stock: number;
bound_stock: number;
redeemed_stock: number;
mismatch_stock: number;
abnormal_stock: number;
deleted_stock?: number;
using_overdue_stock?: number;
using_danger_stock?: number;
bound_overdue_stock?: number;
anomaly_stock?: number;
auto_refresh_mismatch_enabled?: boolean;
upstream_points: number;
auto_delivery_enabled: boolean;
token_warning_stock: number;
auto_purchase_enabled: boolean;
auto_purchase_cooldown_seconds?: number;
next_auto_purchase_at?: string;
username: string;
last_heartbeat_at?: string;
last_purchase_error?: string;
last_purchase_error_at?: string;
}
export interface RockDashboard {
available_black: number;
available_blue: number;
black_token_cost: number;
blue_token_cost: number;
cost_updated: boolean;
}
export interface TokenBindingRefreshResult {
status: string;
bound: boolean;
role_name?: string;
role_id?: string;
channel?: string;
changed: boolean;
warning: boolean;
message: string;
redeemed_at?: string;
}
export interface TokenPackageLink {
package_id: number;
share_code: string;
url: string;
}
export interface RockTokenItem {
id: number;
upstream_token_id: string;
package_id?: number;
package_share_code?: string;
token?: string;
redeem_code: string;
color: string;
region: string;
status: string;
source?: string;
assigned_order_no?: string;
client_order_no?: string;
expected_uid?: string;
actual_role_name?: string;
actual_role_id?: string;
actual_channel?: string;
upstream_fulfill_id?: number;
target_skin?: string;
target_currency?: string;
target_currency_quantity?: number;
mismatch_at?: string;
mismatch_reason?: string;
remark?: string;
raw_data?: string;
claimed_at?: string;
using_at?: string;
bound_at?: string;
redeemed_at?: string;
// 上游异步兑奖(发货确认中)标记字段,不是状态
redeem_requested_at?: string;
redeem_checked_at?: string;
redeem_attempts?: number;
redeem_next_retry_at?: string;
redeem_last_message?: string;
redeem_last_error?: string;
redeem_timeout_warned_at?: string;
// 异常标记(派生字段,来自历史流转,不改变主状态)
has_anomaly?: boolean;
anomaly_type?: string;
anomaly_reason?: string;
anomaly_at?: string;
anomaly_count?: number;
created_at: string;
updated_at?: string;
deleted_at?: string | null;
// 后端按与筛选/统计一致的阈值计算,前端标签直接使用,避免本地时间造成边界不一致。
bound_overdue?: boolean;
using_overdue?: boolean;
using_danger?: boolean;
bound_days?: number;
using_days?: number;
}
export interface RockPurchaseResult {
purchased_count: number;
requested_count: number;
planned_count: number;
limit_reason: string;
log_id: number;
message: string;
}
export interface RockPurchaseLog {
id: number;
trigger_type: "auto" | "manual";
status: "running" | "success" | "partial" | "failed" | "skipped";
requested_count: number;
planned_count: number;
claimed_count: number;
imported_count: number;
upstream_available: number;
points_before: number;
unit_cost: number;
max_by_points: number;
max_by_stock: number;
limit_reason: string;
points_source: string;
stage: string;
error_message: string;
package_id?: number;
share_code: string;
duration_ms: number;
started_at: string;
finished_at?: string;
created_at: string;
}
export interface RockPurchaseStage {
id: number;
log_id: number;
seq: number;
stage: string;
method: string;
url: string;
request_body: string;
http_status: number;
response_body: string;
truncated: boolean;
duration_ms: number;
error_message: string;
created_at: string;
}
export interface PackageImportItem {
package_id: number;
share_code: string;
inserted: number;
skipped_bound: number;
error?: string;
}
export interface ImportAllResult {
scanned: number;
skipped: number;
empty: number;
imported: number;
failed: number;
tokens_imported: number;
tokens_skipped_bound: number;
remaining: number;
results: PackageImportItem[];
}
export interface RockTokenDeleteStatusCount {
status: string;
count: number;
}
export interface RockTokenDeleteItem {
id: number;
status: string;
assigned_order_no?: string;
}
export interface RockTokenDeletePreview {
total: number;
dangerous: number;
available: number;
requires_force: boolean;
status_counts: RockTokenDeleteStatusCount[];
dangerous_items: RockTokenDeleteItem[];
}
export interface RockTokenDeleteResult {
requested: number;
deleted: number;
forced: boolean;
status_counts: RockTokenDeleteStatusCount[];
}
export interface RockTokenRestoreSkipItem {
id: number;
status?: string;
reason: string;
}
export interface RockTokenRestoreResult {
requested: number;
restored: number;
skipped: number;
status_counts: RockTokenDeleteStatusCount[];
skipped_items: RockTokenRestoreSkipItem[];
}
export interface RockReleaseCheckResult {
can_release: boolean
upstream_status: string
role_name?: string
role_id?: string
message: string
}
export interface RockTokenStatusLog {
id: number
token_id: number
upstream_token_id: string
event_type: string
from_status: string
to_status: string
source: string
reason: string
forced: boolean
actor_user_id?: number | null
created_at: string
}
// 发货全链路报文日志:一次发货动作的每一步(入站 / 上游请求 / 上游响应 / 内部状态)。
export interface RockDeliveryLog {
id: number
trace_id: string
token_id: number
upstream_token_id: string
order_no: string
step: string
direction: 'inbound' | 'outbound' | 'internal' | string
status: string
http_method: string
http_url: string
http_status: number
request_headers: string
request_body: string
response_headers: string
response_body: string
duration_ms: number
error_message: string
actor_user_id?: number | null
actor_ip: string
user_agent: string
created_at: string
finished_at?: string
}
export interface RockStaleRefreshResult {
scanned: number;
fixed: number;
failed: number;
remaining: number;
message: string;
}
export const rockApi = {
getConfig: () =>
request.get("/platform/rock/config").then((r) => r.data.data as RockConfig),
updateConfig: (data: Partial<RockConfig>) =>
request
.put("/platform/rock/config", data)
.then((r) => r.data.data as RockConfig),
testConnection: (bearer_token?: string) =>
request
.post("/platform/rock/test-conn", { bearer_token })
.then((r) => r.data.data),
testLogin: (data: { username?: string; password?: string }) =>
request
.post("/platform/rock/login-test", data)
.then((r) => r.data.data as { username: string; role: string; points: number }),
refreshRockToken: () =>
request
.post("/platform/rock/token/refresh")
.then(
(r) =>
r.data.data as {
username: string;
role: string;
points: number;
refreshed_at: string;
},
),
getStats: () =>
request.get("/platform/rock/stats").then((r) => r.data.data as RockStats),
refreshDashboard: () =>
request
.post("/platform/rock/dashboard/refresh")
.then((r) => r.data.data as RockDashboard),
purchaseTokens: (count = 50) =>
request
.post("/platform/rock/purchase", { count })
.then((r) => r.data.data as RockPurchaseResult),
listPurchaseLogs: (params?: {
page?: number;
page_size?: number;
trigger_type?: string;
status?: string;
}) =>
request
.get("/platform/rock/purchase-logs", { params })
.then((r) => r.data.data as { list: RockPurchaseLog[]; total: number }),
getPurchaseLog: (id: number) =>
request
.get(`/platform/rock/purchase-logs/${id}`)
.then(
(r) =>
r.data.data as { log: RockPurchaseLog; stages: RockPurchaseStage[] },
),
importAllUpstreamPackages: (maxPackages = 50) =>
request
.post("/platform/rock/upstream-packages/import-all", {
max_packages: maxPackages,
})
.then((r) => r.data.data as ImportAllResult),
listTokens: (params?: {
page?: number;
page_size?: number;
status?: string;
search?: string;
}) =>
request.get("/platform/rock/tokens", { params }).then(
(r) =>
r.data.data as {
list: RockTokenItem[];
total: number;
page: number;
page_size: number;
},
),
refreshStaleTokens: () =>
request
.post("/platform/rock/token-batches/refresh-stale")
.then((r) => r.data.data as RockStaleRefreshResult),
listSupportBoundTokens: (params: { page?: number; page_size?: number; search: string }) =>
request
.get("/platform/rock/support/bound-tokens", { params })
.then(
(r) =>
r.data.data as {
list: RockTokenItem[];
total: number;
page: number;
page_size: number;
},
),
listSupportTokenStatusLogs: (id: number) =>
request
.get(`/platform/rock/support/tokens/${id}/status-logs`)
.then((r) => r.data.data as { list: RockTokenStatusLog[] }),
previewTokenDelete: (params?: { status?: string; search?: string }) =>
request
.get("/platform/rock/token-batches/preview", { params })
.then((r) => r.data.data as RockTokenDeletePreview),
batchDeleteTokens: (data: {
ids: number[];
force?: boolean;
force_confirm_text?: string;
}) =>
request
.post("/platform/rock/token-batches/batch-delete", data)
.then((r) => r.data.data as RockTokenDeleteResult),
deleteAllTokens: (data: {
status?: string;
search?: string;
expected_count: number;
force?: boolean;
confirm_text: string;
force_confirm_text?: string;
}) =>
request
.post("/platform/rock/token-batches/delete-all", data)
.then((r) => r.data.data as RockTokenDeleteResult),
listDeletedTokens: (params?: {
page?: number;
page_size?: number;
status?: string;
search?: string;
}) =>
request.get("/platform/rock/token-batches/deleted", { params }).then(
(r) =>
r.data.data as {
list: RockTokenItem[];
total: number;
page: number;
page_size: number;
},
),
restoreTokens: (data: { ids: number[] }) =>
request
.post("/platform/rock/token-batches/restore", data)
.then((r) => r.data.data as RockTokenRestoreResult),
correctExpectedUid: (id: number, expectedUid: string) =>
request
.post(`/platform/rock/tokens/${id}/expected-uid`, {
expected_uid: expectedUid,
})
.then((r) => r.data.data as { message?: string; status?: string }),
resetToken: (id: number) =>
request.post(`/platform/rock/tokens/${id}/reset`).then((r) => r.data.data),
checkReleaseToken: (id: number) =>
request
.post(`/platform/rock/tokens/${id}/release-check`)
.then((r) => r.data.data as RockReleaseCheckResult),
releaseToken: (
id: number,
data?: { force?: boolean; force_confirm_text?: string },
) =>
request
.post(`/platform/rock/tokens/${id}/release`, data ?? {})
.then((r) => r.data.data as { message: string }),
listTokenStatusLogs: (id: number) =>
request
.get(`/platform/rock/tokens/${id}/status-logs`)
.then((r) => r.data.data as { list: RockTokenStatusLog[] }),
listDeliveryLogs: (id: number) =>
request
.get(`/platform/rock/tokens/${id}/delivery-logs`)
.then((r) => r.data.data as { list: RockDeliveryLog[] }),
refreshTokenBinding: (id: number) =>
request
.post(`/platform/rock/tokens/${id}/refresh-binding`)
.then((r) => r.data.data as TokenBindingRefreshResult),
getTokenPackageLink: (id: number) =>
request
.get(`/platform/rock/tokens/${id}/package-link`)
.then((r) => r.data.data as TokenPackageLink),
updateRemark: (id: number, data: { remark: string; status?: string }) =>
request
.post(`/platform/rock/tokens/${id}/remark`, data)
.then((r) => r.data.data as { message: string; token: RockTokenItem }),
markAbnormal: (id: number, remark?: string) =>
request
.post(`/platform/rock/tokens/${id}/abnormal`, { remark })
.then((r) => r.data.data as { message: string; token: RockTokenItem }),
};