feat(auth): 接入 DCAuth v2 登录并完善成员管理
- 登录链路改为用户名 + 密码 + 短信验证码 + DCAuth v2 设备签名 - 迁移 014:新增 login_sms_codes / user_devices / device_challenges 与 users.phone - 新增 /api/dcauth/authorize 与 challenge 状态轮询;旧密码登录仅放行未绑定手机号的账号 - 成员管理支持手机号绑定、设备重置、账号改名、昵称与重置密码 - 移除最后一个商户关系时软删除账号,释放用户名、手机号并撤销设备绑定
This commit is contained in:
+537
-221
@@ -1,4 +1,4 @@
|
||||
import request from './request'
|
||||
import request from "./request";
|
||||
import type {
|
||||
DashboardStats,
|
||||
AlertChannelInput,
|
||||
@@ -17,11 +17,11 @@ import type {
|
||||
LoginResult,
|
||||
LowBalanceAlertConfig,
|
||||
Merchant,
|
||||
MerchantMember,
|
||||
MerchantMemberGroup,
|
||||
MerchantOption,
|
||||
MerchantOwnerAccount,
|
||||
MerchantRole,
|
||||
MerchantMember,
|
||||
MerchantMemberGroup,
|
||||
MerchantOption,
|
||||
MerchantOwnerAccount,
|
||||
MerchantRole,
|
||||
MerchantProduct,
|
||||
PageResult,
|
||||
ProductCatalogItem,
|
||||
@@ -32,328 +32,644 @@ import type {
|
||||
LewanProductListResult,
|
||||
UpdateProductRoutingInput,
|
||||
SyncLewanProductInput,
|
||||
} from '../types'
|
||||
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
|
||||
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
|
||||
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),
|
||||
}
|
||||
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),
|
||||
}
|
||||
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>),
|
||||
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),
|
||||
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[] }),
|
||||
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>),
|
||||
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'
|
||||
}
|
||||
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),
|
||||
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>),
|
||||
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[]),
|
||||
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),
|
||||
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),
|
||||
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 }),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
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>),
|
||||
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[]),
|
||||
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),
|
||||
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),
|
||||
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: { role: string; status: number; is_default: boolean }) =>
|
||||
request.patch(`/merchant/members/${id}`, data).then((r) => r.data.data as MerchantMember),
|
||||
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),
|
||||
roles: () => request.get('/merchant/roles').then((r) => r.data.data as MerchantRole[]),
|
||||
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),
|
||||
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),
|
||||
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 }) =>
|
||||
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),
|
||||
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),
|
||||
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[]),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
}
|
||||
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 })
|
||||
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),
|
||||
}
|
||||
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>),
|
||||
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),
|
||||
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>),
|
||||
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[]),
|
||||
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>),
|
||||
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),
|
||||
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[]),
|
||||
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),
|
||||
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),
|
||||
) =>
|
||||
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),
|
||||
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[]),
|
||||
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[]),
|
||||
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),
|
||||
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 }),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
}
|
||||
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),
|
||||
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),
|
||||
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 }),
|
||||
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 }),
|
||||
}
|
||||
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
|
||||
min_points_warning: number
|
||||
token_warning_stock: number
|
||||
auto_purchase_enabled: boolean
|
||||
auto_purchase_count: number
|
||||
purchase_cooldown_minutes: number
|
||||
last_purchased_at?: string
|
||||
last_heartbeat_at?: string
|
||||
id: number;
|
||||
auto_delivery_enabled: boolean;
|
||||
base_url: string;
|
||||
bearer_token: string;
|
||||
username: string;
|
||||
points: number;
|
||||
min_points_warning: number;
|
||||
token_warning_stock: number;
|
||||
auto_purchase_enabled: boolean;
|
||||
auto_purchase_count: number;
|
||||
purchase_cooldown_minutes: number;
|
||||
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
|
||||
upstream_points: number
|
||||
auto_delivery_enabled: boolean
|
||||
token_warning_stock: number
|
||||
auto_purchase_enabled: boolean
|
||||
username: string
|
||||
last_heartbeat_at?: string
|
||||
available_stock: number;
|
||||
using_stock: number;
|
||||
bound_stock: number;
|
||||
redeemed_stock: number;
|
||||
mismatch_stock: number;
|
||||
abnormal_stock: number;
|
||||
upstream_points: number;
|
||||
auto_delivery_enabled: boolean;
|
||||
token_warning_stock: number;
|
||||
auto_purchase_enabled: boolean;
|
||||
username: string;
|
||||
last_heartbeat_at?: string;
|
||||
}
|
||||
|
||||
export interface RockTokenItem {
|
||||
id: number
|
||||
upstream_token_id: string
|
||||
redeem_code: string
|
||||
color: string
|
||||
region: string
|
||||
status: 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
|
||||
claimed_at?: string
|
||||
bound_at?: string
|
||||
redeemed_at?: string
|
||||
created_at: string
|
||||
id: number;
|
||||
upstream_token_id: string;
|
||||
redeem_code: string;
|
||||
color: string;
|
||||
region: string;
|
||||
status: 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;
|
||||
claimed_at?: string;
|
||||
bound_at?: string;
|
||||
redeemed_at?: string;
|
||||
created_at: 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),
|
||||
getStats: () => request.get('/platform/rock/stats').then((r) => r.data.data as RockStats),
|
||||
purchaseTokens: (count = 50) => request.post('/platform/rock/purchase', { count }).then((r) => r.data.data),
|
||||
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 }),
|
||||
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),
|
||||
getStats: () =>
|
||||
request.get("/platform/rock/stats").then((r) => r.data.data as RockStats),
|
||||
purchaseTokens: (count = 50) =>
|
||||
request.post("/platform/rock/purchase", { count }).then((r) => r.data.data),
|
||||
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;
|
||||
},
|
||||
),
|
||||
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),
|
||||
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),
|
||||
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 }),
|
||||
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 }),
|
||||
}
|
||||
|
||||
|
||||
|
||||
request
|
||||
.post(`/platform/rock/tokens/${id}/abnormal`, { remark })
|
||||
.then((r) => r.data.data as { message: string; token: RockTokenItem }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user