915 lines
27 KiB
TypeScript
915 lines
27 KiB
TypeScript
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;
|
||
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;
|
||
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;
|
||
created_at: string;
|
||
updated_at?: string;
|
||
deleted_at?: string | null;
|
||
}
|
||
|
||
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 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 }),
|
||
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;
|
||
},
|
||
),
|
||
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),
|
||
releaseToken: (id: number) =>
|
||
request
|
||
.post(`/platform/rock/tokens/${id}/release`)
|
||
.then((r) => r.data.data),
|
||
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 }),
|
||
};
|