扩展用户管理字段与组织编码生成,顶部改为仓库下拉;Nana 分 AI 与专属顾问 Tab,仓库页移除客服字段,并完善扫描语音与订单相关页面。 Co-authored-by: Cursor <cursoragent@cursor.com>
1220 lines
37 KiB
TypeScript
1220 lines
37 KiB
TypeScript
/**
|
||
* OMS 订单接口(Swagger:OMS-Order,与 admin 同源)
|
||
*/
|
||
import { axiosInstance } from '@/api/rbac'
|
||
import { resolveAdminApiPath } from '@/utils/adminApi'
|
||
|
||
function orderUrl(path: string): string {
|
||
return resolveAdminApiPath(path)
|
||
}
|
||
|
||
export interface OrderListRequest {
|
||
page: number
|
||
pageSize: number
|
||
/** all 或各状态英文 key,与文档一致 */
|
||
status?: string
|
||
/** 子状态:all / pending / processed(问题件、已理赔 Tab) */
|
||
handleStatus?: string
|
||
keyword?: string
|
||
createTimeStart?: string
|
||
createTimeEnd?: string
|
||
}
|
||
|
||
export interface OrderHandleStatusCounts {
|
||
pending: number
|
||
processed: number
|
||
total?: number
|
||
}
|
||
|
||
export interface OrderListResult {
|
||
items: any[]
|
||
total: number
|
||
}
|
||
|
||
export interface OrderStatusCountsResult {
|
||
total: number
|
||
counts: Record<string, number>
|
||
handleCounts?: Record<string, OrderHandleStatusCounts>
|
||
}
|
||
|
||
function assertBusinessOk(body: any) {
|
||
if (body == null) throw new Error('空响应')
|
||
const code = body.code ?? body.Code
|
||
const ok =
|
||
code === undefined ||
|
||
code === null ||
|
||
code === 0 ||
|
||
code === 200 ||
|
||
code === '0' ||
|
||
code === '200' ||
|
||
body.success === true ||
|
||
body.Success === true
|
||
if (!ok) {
|
||
throw new Error(body.msg ?? body.Msg ?? body.message ?? body.Message ?? '请求失败')
|
||
}
|
||
}
|
||
|
||
/** 兼容 data 包裹或顶层直出(camel/Pascal) */
|
||
function unwrapApiData<T = Record<string, any>>(body: any): T {
|
||
if (body == null) return {} as T
|
||
const wrapped = body.data ?? body.Data
|
||
if (wrapped !== undefined && wrapped !== null) {
|
||
return wrapped as T
|
||
}
|
||
return body as T
|
||
}
|
||
|
||
/** 取出分页载荷(兼容 data 包裹或顶层直出、items/list/records、camel/Pascal) */
|
||
function parseOrderListPayload(resBody: any): OrderListResult {
|
||
assertBusinessOk(resBody)
|
||
const inner = resBody.data ?? resBody.Data ?? resBody
|
||
if (Array.isArray(inner)) {
|
||
return { items: inner, total: inner.length }
|
||
}
|
||
const payload =
|
||
inner && typeof inner === 'object' && !Array.isArray(inner) ? inner : resBody
|
||
|
||
const items =
|
||
payload.items ??
|
||
payload.Items ??
|
||
payload.list ??
|
||
payload.List ??
|
||
payload.records ??
|
||
payload.Records ??
|
||
payload.rows ??
|
||
payload.Rows ??
|
||
(Array.isArray(payload) ? payload : [])
|
||
|
||
const totalRaw =
|
||
payload.total ??
|
||
payload.Total ??
|
||
payload.totalCount ??
|
||
payload.TotalCount ??
|
||
payload.count ??
|
||
payload.Count
|
||
|
||
const list = Array.isArray(items) ? items : []
|
||
const total =
|
||
typeof totalRaw === 'number'
|
||
? totalRaw
|
||
: totalRaw != null && totalRaw !== ''
|
||
? Number(totalRaw)
|
||
: list.length
|
||
|
||
return {
|
||
items: list,
|
||
total: Number.isFinite(total) ? total : 0,
|
||
}
|
||
}
|
||
|
||
/** 分页查询订单列表 POST /order/list */
|
||
export async function postOrderList(params: OrderListRequest): Promise<OrderListResult> {
|
||
const body: OrderListRequest = {
|
||
page: params.page,
|
||
pageSize: params.pageSize,
|
||
status: params.status ?? 'all',
|
||
keyword: params.keyword ?? '',
|
||
}
|
||
if (params.handleStatus?.trim()) {
|
||
body.handleStatus = params.handleStatus.trim()
|
||
}
|
||
if (params.createTimeStart?.trim()) {
|
||
body.createTimeStart = params.createTimeStart.trim()
|
||
}
|
||
if (params.createTimeEnd?.trim()) {
|
||
body.createTimeEnd = params.createTimeEnd.trim()
|
||
}
|
||
const res = await axiosInstance.post(orderUrl('/order/list'), body)
|
||
return parseOrderListPayload(res.data)
|
||
}
|
||
|
||
/** 各状态订单数量聚合 GET /order/status-counts(单次查询,非逐状态分页) */
|
||
export async function getOrderStatusCounts(): Promise<OrderStatusCountsResult> {
|
||
const res = await axiosInstance.get(orderUrl('/order/status-counts'))
|
||
assertBusinessOk(res.data)
|
||
const inner = res.data?.data ?? res.data?.Data ?? res.data ?? {}
|
||
const totalRaw = inner.total ?? inner.Total ?? 0
|
||
const counts = inner.counts ?? inner.Counts ?? {}
|
||
const handleCountsRaw = inner.handleCounts ?? inner.HandleCounts ?? {}
|
||
const handleCounts: Record<string, OrderHandleStatusCounts> = {}
|
||
if (handleCountsRaw && typeof handleCountsRaw === 'object') {
|
||
for (const [key, value] of Object.entries(handleCountsRaw as Record<string, any>)) {
|
||
handleCounts[key] = {
|
||
pending: Number(value?.pending ?? value?.Pending ?? 0) || 0,
|
||
processed: Number(value?.processed ?? value?.Processed ?? 0) || 0,
|
||
total: Number(value?.total ?? value?.Total ?? 0) || undefined,
|
||
}
|
||
}
|
||
}
|
||
return {
|
||
total: Number(totalRaw) || 0,
|
||
counts: typeof counts === 'object' && counts !== null ? counts : {},
|
||
handleCounts,
|
||
}
|
||
}
|
||
|
||
/** 订单详情 GET /order/detail?id= */
|
||
export async function getOrderDetail(id: number | string): Promise<any> {
|
||
const res = await axiosInstance.get(orderUrl('/order/detail'), {
|
||
params: { id },
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|
||
|
||
export interface OrderIdRequest {
|
||
id: number | string
|
||
}
|
||
|
||
export interface OrderExportRequest {
|
||
status?: string
|
||
keyword?: string
|
||
createTimeStart?: string
|
||
createTimeEnd?: string
|
||
}
|
||
|
||
export interface OrderPrintResult {
|
||
printUrl?: string
|
||
}
|
||
|
||
export interface OrderExportResult {
|
||
downloadUrl?: string
|
||
expireAt?: string
|
||
}
|
||
|
||
async function postOrderById(path: string, body: OrderIdRequest): Promise<void> {
|
||
const res = await axiosInstance.post(orderUrl(path), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
}
|
||
|
||
/** POST /order/pay */
|
||
export function postOrderPay(body: OrderIdRequest) {
|
||
return postOrderById('/order/pay', body)
|
||
}
|
||
|
||
/** POST /order/pre-declare */
|
||
export function postOrderPreDeclare(body: OrderIdRequest) {
|
||
return postOrderById('/order/pre-declare', body)
|
||
}
|
||
|
||
/** POST /order/intercept */
|
||
export function postOrderIntercept(body: OrderIdRequest) {
|
||
return postOrderById('/order/intercept', body)
|
||
}
|
||
|
||
/** POST /order/cancel-intercept */
|
||
export function postOrderCancelIntercept(body: OrderIdRequest) {
|
||
return postOrderById('/order/cancel-intercept', body)
|
||
}
|
||
|
||
/** POST /order/delete */
|
||
export function postOrderDelete(body: OrderIdRequest) {
|
||
return postOrderById('/order/delete', body)
|
||
}
|
||
|
||
export interface OrderTrackUpsertResult {
|
||
skipped?: boolean
|
||
skipReason?: string
|
||
success?: boolean
|
||
url?: string
|
||
requestJson?: string
|
||
curlCommand?: string
|
||
statusCode?: number
|
||
responseBody?: string
|
||
}
|
||
|
||
/** POST /order/track-upsert-small-bag → 同步调用轨迹 UpsertSmallBag(联调/手动触发) */
|
||
export async function postOrderTrackUpsertSmallBag(body: OrderIdRequest): Promise<OrderTrackUpsertResult> {
|
||
const res = await axiosInstance.post(orderUrl('/order/track-upsert-small-bag'), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
const d = res.data?.data ?? res.data?.Data ?? res.data ?? {}
|
||
return {
|
||
skipped: d.skipped ?? d.Skipped,
|
||
skipReason: d.skipReason ?? d.SkipReason,
|
||
success: d.success ?? d.Success,
|
||
url: d.url ?? d.Url,
|
||
requestJson: d.requestJson ?? d.RequestJson,
|
||
curlCommand: d.curlCommand ?? d.CurlCommand,
|
||
statusCode: d.statusCode ?? d.StatusCode,
|
||
responseBody: d.responseBody ?? d.ResponseBody,
|
||
}
|
||
}
|
||
|
||
export interface OrderDownstreamForwardResult {
|
||
success?: boolean
|
||
supplierCode?: string
|
||
url?: string
|
||
requestJson?: string
|
||
statusCode?: number
|
||
responseBody?: string
|
||
}
|
||
|
||
/** POST /order/downstream-forward-create-one → 后端查订单表组装并转发 createOrderOne */
|
||
export async function postOrderDownstreamForwardCreateOne(
|
||
body: OrderIdRequest
|
||
): Promise<OrderDownstreamForwardResult> {
|
||
const res = await axiosInstance.post(orderUrl('/order/downstream-forward-create-one'), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
const d = res.data?.data ?? res.data?.Data ?? res.data ?? {}
|
||
return {
|
||
success: d.success ?? d.Success,
|
||
supplierCode: d.supplierCode ?? d.SupplierCode,
|
||
url: d.url ?? d.Url,
|
||
requestJson: d.requestJson ?? d.RequestJson,
|
||
statusCode: d.statusCode ?? d.StatusCode,
|
||
responseBody: d.responseBody ?? d.ResponseBody,
|
||
}
|
||
}
|
||
|
||
export interface OrderBatchActionFailure {
|
||
orderId?: number
|
||
OrderId?: number
|
||
serviceNo?: string
|
||
ServiceNo?: string
|
||
reason?: string
|
||
Reason?: string
|
||
}
|
||
|
||
export interface OrderBatchActionResult {
|
||
successCount?: number
|
||
SuccessCount?: number
|
||
failures?: OrderBatchActionFailure[]
|
||
Failures?: OrderBatchActionFailure[]
|
||
}
|
||
|
||
export interface OrderBatchJobOutput {
|
||
jobId?: number
|
||
JobId?: number
|
||
action?: string
|
||
Action?: string
|
||
status?: string
|
||
Status?: string
|
||
total?: number
|
||
Total?: number
|
||
successCount?: number
|
||
SuccessCount?: number
|
||
failCount?: number
|
||
FailCount?: number
|
||
startedAt?: string
|
||
StartedAt?: string
|
||
finishedAt?: string
|
||
FinishedAt?: string
|
||
createTime?: string
|
||
CreateTime?: string
|
||
}
|
||
|
||
export interface OrderBatchJobItemOutput {
|
||
id?: number
|
||
Id?: number
|
||
orderId?: number
|
||
OrderId?: number
|
||
serviceNo?: string
|
||
ServiceNo?: string
|
||
status?: string
|
||
Status?: string
|
||
failReason?: string
|
||
FailReason?: string
|
||
startedAt?: string
|
||
StartedAt?: string
|
||
finishedAt?: string
|
||
FinishedAt?: string
|
||
}
|
||
|
||
function parseOrderBatchJob(raw: any): {
|
||
jobId: number
|
||
action: string
|
||
status: string
|
||
total: number
|
||
successCount: number
|
||
failCount: number
|
||
startedAt?: string
|
||
finishedAt?: string
|
||
createTime?: string
|
||
} {
|
||
const d = unwrapApiData(raw)
|
||
return {
|
||
jobId: Number(d.jobId ?? d.JobId ?? 0),
|
||
action: String(d.action ?? d.Action ?? ''),
|
||
status: String(d.status ?? d.Status ?? ''),
|
||
total: Number(d.total ?? d.Total ?? 0),
|
||
successCount: Number(d.successCount ?? d.SuccessCount ?? 0),
|
||
failCount: Number(d.failCount ?? d.FailCount ?? 0),
|
||
startedAt: d.startedAt ?? d.StartedAt,
|
||
finishedAt: d.finishedAt ?? d.FinishedAt,
|
||
createTime: d.createTime ?? d.CreateTime,
|
||
}
|
||
}
|
||
|
||
function parseOrderBatchJobItem(raw: any): {
|
||
id: number
|
||
orderId: number
|
||
serviceNo?: string
|
||
status: string
|
||
failReason?: string
|
||
resultJson?: string
|
||
} {
|
||
return {
|
||
id: Number(raw.id ?? raw.Id ?? 0),
|
||
orderId: Number(raw.orderId ?? raw.OrderId ?? 0),
|
||
serviceNo: raw.serviceNo ?? raw.ServiceNo,
|
||
status: String(raw.status ?? raw.Status ?? ''),
|
||
failReason: raw.failReason ?? raw.FailReason,
|
||
resultJson: raw.resultJson ?? raw.ResultJson,
|
||
}
|
||
}
|
||
|
||
export function parseBatchJobPrintUrl(item: { resultJson?: string }): string {
|
||
if (!item.resultJson) return ''
|
||
try {
|
||
const obj = JSON.parse(item.resultJson)
|
||
return String(obj.printUrl ?? obj.PrintUrl ?? '').trim()
|
||
} catch {
|
||
return ''
|
||
}
|
||
}
|
||
|
||
const ORDER_BATCH_ACTION_ROUTES: Record<string, string> = {
|
||
pay: '/order/batch/pay',
|
||
'pre-declare': '/order/batch/pre-declare',
|
||
intercept: '/order/batch/intercept',
|
||
'cancel-intercept': '/order/batch/cancel-intercept',
|
||
delete: '/order/batch/delete',
|
||
print: '/order/batch/print',
|
||
'mark-problematic': '/order/batch/mark-problematic',
|
||
'mark-claimed': '/order/batch/mark-claimed',
|
||
'handle-status-update': '/order/batch/handle-status-update',
|
||
'track-upsert-small-bag': '/order/batch/track-upsert',
|
||
'downstream-forward-create-one': '/order/batch/downstream-forward',
|
||
}
|
||
|
||
/** POST /order/batch/jobs 或按 action 路由的批量任务 */
|
||
export async function postOrderBatchJob(body: {
|
||
action: string
|
||
orderIds: Array<number | string>
|
||
payloadJson?: string
|
||
requestId?: string
|
||
}): Promise<ReturnType<typeof parseOrderBatchJob>> {
|
||
const route = ORDER_BATCH_ACTION_ROUTES[body.action] ?? '/order/batch/jobs'
|
||
const payload = {
|
||
action: body.action,
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
payloadJson: body.payloadJson,
|
||
requestId: body.requestId,
|
||
}
|
||
const res = await axiosInstance.post(orderUrl(route), payload)
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJob(res.data)
|
||
}
|
||
|
||
export function formatBatchJobFailureMessage(
|
||
job: { successCount: number; failCount: number },
|
||
items: Array<{ orderId: number; serviceNo?: string; status: string; failReason?: string }>,
|
||
rows?: any[],
|
||
getRowLabel?: (row: any, item: { orderId: number; serviceNo?: string }) => string
|
||
): string {
|
||
const failed = items.filter((item) => item.status === 'failed')
|
||
if (!failed.length) {
|
||
return `完成:成功 ${job.successCount} 条`
|
||
}
|
||
const lines = failed.slice(0, 8).map((item) => {
|
||
const row = rows?.find((r) => Number(r?.id ?? r?.Id) === item.orderId)
|
||
const label = getRowLabel?.(row, item) ?? item.serviceNo ?? String(item.orderId)
|
||
return `【${label}】${item.failReason || '失败'}`
|
||
})
|
||
return [`完成:成功 ${job.successCount} 条,失败 ${job.failCount} 条`, ...lines].join('\n')
|
||
}
|
||
|
||
const BATCH_JOB_TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled'])
|
||
|
||
export interface OrderBatchDlxStats {
|
||
enabled: boolean
|
||
deadLetterMessageCount: number
|
||
dlxAlertThreshold: number
|
||
alert: boolean
|
||
}
|
||
|
||
export interface OrderBatchJobManageResult {
|
||
jobId: number
|
||
retriedCount: number
|
||
cancelledCount: number
|
||
status: string
|
||
}
|
||
|
||
function parseOrderBatchDlxStats(raw: any): OrderBatchDlxStats {
|
||
const d = raw?.data ?? raw?.Data ?? raw ?? {}
|
||
return {
|
||
enabled: Boolean(d.enabled ?? d.Enabled),
|
||
deadLetterMessageCount: Number(d.deadLetterMessageCount ?? d.DeadLetterMessageCount ?? 0),
|
||
dlxAlertThreshold: Number(d.dlxAlertThreshold ?? d.DlxAlertThreshold ?? 0),
|
||
alert: Boolean(d.alert ?? d.Alert),
|
||
}
|
||
}
|
||
|
||
function parseOrderBatchJobManage(raw: any): OrderBatchJobManageResult {
|
||
const d = raw?.data ?? raw?.Data ?? raw ?? {}
|
||
return {
|
||
jobId: Number(d.jobId ?? d.JobId ?? 0),
|
||
retriedCount: Number(d.retriedCount ?? d.RetriedCount ?? 0),
|
||
cancelledCount: Number(d.cancelledCount ?? d.CancelledCount ?? 0),
|
||
status: String(d.status ?? d.Status ?? ''),
|
||
}
|
||
}
|
||
|
||
/** GET /order/batch/jobs */
|
||
export async function getOrderBatchJobList(params: {
|
||
page?: number
|
||
pageSize?: number
|
||
status?: string
|
||
action?: string
|
||
jobId?: number | string
|
||
}): Promise<{ items: Array<ReturnType<typeof parseOrderBatchJob>>; total: number }> {
|
||
const res = await axiosInstance.get(orderUrl('/order/batch/jobs'), {
|
||
params: {
|
||
Page: params.page ?? 1,
|
||
PageSize: params.pageSize ?? 30,
|
||
Status: params.status || undefined,
|
||
Action: params.action || undefined,
|
||
JobId: params.jobId ? Number(params.jobId) : undefined,
|
||
},
|
||
})
|
||
const parsed = parseOrderListPayload(res.data)
|
||
return {
|
||
items: (parsed.items || []).map(parseOrderBatchJob),
|
||
total: parsed.total,
|
||
}
|
||
}
|
||
|
||
/** GET /order/batch/dlx/stats */
|
||
export async function getOrderBatchDlxStats(): Promise<OrderBatchDlxStats> {
|
||
const res = await axiosInstance.get(orderUrl('/order/batch/dlx/stats'))
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchDlxStats(res.data)
|
||
}
|
||
|
||
/** POST /order/batch/jobs/{id}/retry-failed */
|
||
export async function postOrderBatchJobRetryFailed(
|
||
jobId: number | string,
|
||
body?: { itemIds?: number[] }
|
||
): Promise<OrderBatchJobManageResult> {
|
||
const res = await axiosInstance.post(orderUrl(`/order/batch/jobs/${jobId}/retry-failed`), body ?? {})
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJobManage(res.data)
|
||
}
|
||
|
||
/** POST /order/batch/jobs/{id}/cancel */
|
||
export async function postOrderBatchJobCancel(jobId: number | string): Promise<OrderBatchJobManageResult> {
|
||
const res = await axiosInstance.post(orderUrl(`/order/batch/jobs/${jobId}/cancel`))
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJobManage(res.data)
|
||
}
|
||
|
||
function sleep(ms: number) {
|
||
return new Promise<void>((resolve) => {
|
||
setTimeout(resolve, ms)
|
||
})
|
||
}
|
||
|
||
/** POST /order/batch/track-upsert */
|
||
export async function postOrderBatchTrackUpsert(body: {
|
||
orderIds: Array<number | string>
|
||
requestId?: string
|
||
}): Promise<ReturnType<typeof parseOrderBatchJob>> {
|
||
const res = await axiosInstance.post(orderUrl('/order/batch/track-upsert'), {
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
requestId: body.requestId,
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJob(res.data)
|
||
}
|
||
|
||
/** POST /order/batch/downstream-forward */
|
||
export async function postOrderBatchDownstreamForward(body: {
|
||
orderIds: Array<number | string>
|
||
requestId?: string
|
||
}): Promise<ReturnType<typeof parseOrderBatchJob>> {
|
||
const res = await axiosInstance.post(orderUrl('/order/batch/downstream-forward'), {
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
requestId: body.requestId,
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJob(res.data)
|
||
}
|
||
|
||
/** GET /order/batch/jobs/{id} */
|
||
export async function getOrderBatchJob(jobId: number | string): Promise<ReturnType<typeof parseOrderBatchJob>> {
|
||
const res = await axiosInstance.get(orderUrl(`/order/batch/jobs/${jobId}`))
|
||
assertBusinessOk(res.data)
|
||
return parseOrderBatchJob(res.data)
|
||
}
|
||
|
||
/** GET /order/batch/jobs/{id}/items */
|
||
export async function getOrderBatchJobItems(
|
||
jobId: number | string
|
||
): Promise<Array<ReturnType<typeof parseOrderBatchJobItem>>> {
|
||
const res = await axiosInstance.get(orderUrl(`/order/batch/jobs/${jobId}/items`))
|
||
assertBusinessOk(res.data)
|
||
const payload = unwrapApiData(res.data)
|
||
const list = Array.isArray(payload) ? payload : payload.items ?? payload.Items ?? []
|
||
return (Array.isArray(list) ? list : []).map(parseOrderBatchJobItem)
|
||
}
|
||
|
||
/** 轮询批量任务直至结束或超时 */
|
||
export async function waitOrderBatchJob(
|
||
jobId: number | string,
|
||
options?: { intervalMs?: number; timeoutMs?: number }
|
||
): Promise<{
|
||
job: ReturnType<typeof parseOrderBatchJob>
|
||
items: Array<ReturnType<typeof parseOrderBatchJobItem>>
|
||
}> {
|
||
const intervalMs = options?.intervalMs ?? 1500
|
||
const timeoutMs = options?.timeoutMs ?? 300_000
|
||
const started = Date.now()
|
||
while (Date.now() - started < timeoutMs) {
|
||
const job = await getOrderBatchJob(jobId)
|
||
if (BATCH_JOB_TERMINAL_STATUSES.has(job.status.toLowerCase())) {
|
||
const items = await getOrderBatchJobItems(jobId)
|
||
return { job, items }
|
||
}
|
||
await sleep(intervalMs)
|
||
}
|
||
throw new Error('批量任务执行超时,请稍后在任务列表中查看进度')
|
||
}
|
||
|
||
export function isOrderBatchQueueDisabledError(error: unknown): boolean {
|
||
const msg = String((error as any)?.message ?? (error as any)?.msg ?? '')
|
||
return msg.includes('未启用') || msg.toLowerCase().includes('rabbitmq')
|
||
}
|
||
|
||
export interface OrderMarkProblematicRequest {
|
||
orderIds: Array<number | string>
|
||
issueTemplateId?: number | string
|
||
issueType?: string
|
||
title?: string
|
||
content?: string
|
||
remark?: string
|
||
}
|
||
|
||
export interface OrderMarkClaimedRequest {
|
||
orderIds: Array<number | string>
|
||
claimType?: string
|
||
claimAmount?: number
|
||
claimCurrency?: string
|
||
claimReason?: string
|
||
remark?: string
|
||
}
|
||
|
||
export interface OrderHandleStatusUpdateRequest {
|
||
orderIds: Array<number | string>
|
||
handleStatus?: string
|
||
remark?: string
|
||
}
|
||
|
||
function parseBatchActionResult(raw: any): { successCount: number; failures: Array<{ orderId: number; serviceNo?: string; reason: string }> } {
|
||
const d = raw?.data ?? raw?.Data ?? raw ?? {}
|
||
const failuresRaw = d.failures ?? d.Failures ?? []
|
||
const failures = (Array.isArray(failuresRaw) ? failuresRaw : []).map((item: any) => ({
|
||
orderId: Number(item.orderId ?? item.OrderId ?? 0),
|
||
serviceNo: item.serviceNo ?? item.ServiceNo,
|
||
reason: String(item.reason ?? item.Reason ?? ''),
|
||
}))
|
||
return {
|
||
successCount: Number(d.successCount ?? d.SuccessCount ?? 0),
|
||
failures,
|
||
}
|
||
}
|
||
|
||
/** POST /order/mark-problematic */
|
||
export async function postOrderMarkProblematic(body: OrderMarkProblematicRequest): Promise<{ successCount: number; failures: Array<{ orderId: number; serviceNo?: string; reason: string }> }> {
|
||
const res = await axiosInstance.post(orderUrl('/order/mark-problematic'), {
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
issueTemplateId: body.issueTemplateId != null ? Number(body.issueTemplateId) : undefined,
|
||
issueType: body.issueType,
|
||
title: body.title,
|
||
content: body.content,
|
||
remark: body.remark,
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return parseBatchActionResult(res.data)
|
||
}
|
||
|
||
/** POST /order/mark-claimed */
|
||
export async function postOrderMarkClaimed(body: OrderMarkClaimedRequest) {
|
||
const res = await axiosInstance.post(orderUrl('/order/mark-claimed'), {
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
claimType: body.claimType,
|
||
claimAmount: body.claimAmount,
|
||
claimCurrency: body.claimCurrency,
|
||
claimReason: body.claimReason,
|
||
remark: body.remark,
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return parseBatchActionResult(res.data)
|
||
}
|
||
|
||
/** POST /order/handle-status/update */
|
||
export async function postOrderHandleStatusUpdate(body: OrderHandleStatusUpdateRequest) {
|
||
const res = await axiosInstance.post(orderUrl('/order/handle-status/update'), {
|
||
orderIds: body.orderIds.map((id) => Number(id)),
|
||
handleStatus: body.handleStatus ?? 'processed',
|
||
remark: body.remark,
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return parseBatchActionResult(res.data)
|
||
}
|
||
|
||
/** POST /order/print → data.printUrl */
|
||
export async function postOrderPrint(body: OrderIdRequest): Promise<OrderPrintResult> {
|
||
const res = await axiosInstance.post(orderUrl('/order/print'), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
const d = res.data?.data ?? res.data?.Data ?? {}
|
||
return {
|
||
printUrl: d.printUrl ?? d.PrintUrl ?? '',
|
||
}
|
||
}
|
||
|
||
/** POST /order/export → data.downloadUrl、expireAt */
|
||
export async function postOrderExport(params: OrderExportRequest): Promise<OrderExportResult> {
|
||
const res = await axiosInstance.post(orderUrl('/order/export'), {
|
||
status: params.status ?? 'all',
|
||
keyword: params.keyword ?? '',
|
||
createTimeStart: params.createTimeStart ?? '',
|
||
createTimeEnd: params.createTimeEnd ?? '',
|
||
})
|
||
assertBusinessOk(res.data)
|
||
const d = res.data?.data ?? res.data?.Data ?? {}
|
||
return {
|
||
downloadUrl: d.downloadUrl ?? d.DownloadUrl ?? '',
|
||
expireAt: d.expireAt ?? d.ExpireAt ?? '',
|
||
}
|
||
}
|
||
|
||
/** POST /order/price-check → data.items + data.failures */
|
||
export interface PriceCheckRequest {
|
||
destinationCountry: string
|
||
shippingMethod: string
|
||
cargoWeight: string
|
||
length: string
|
||
width: string
|
||
height: string
|
||
/** @deprecated 请使用 cargoTypes */
|
||
cargoType?: string
|
||
/** 货物类型(多选,字典 cargo_attribute 编码) */
|
||
cargoTypes?: string[]
|
||
/** 仓库主键(多选;为空则遍历全部仓库) */
|
||
warehouseIds?: number[]
|
||
destinationProvince: string
|
||
postalCode: string
|
||
}
|
||
|
||
export interface PriceCheckFailure {
|
||
productId?: number
|
||
productCode?: string
|
||
productName?: string
|
||
step?: string
|
||
reason?: string
|
||
cargoTypeName?: string
|
||
warehouseName?: string
|
||
}
|
||
|
||
function normalizePriceCheckFailure(raw: unknown): PriceCheckFailure | null {
|
||
if (raw == null) return null
|
||
if (typeof raw === 'string') {
|
||
const text = raw.trim()
|
||
return text ? { reason: text } : null
|
||
}
|
||
if (typeof raw !== 'object') return null
|
||
const row = raw as Record<string, unknown>
|
||
const reason = String(
|
||
row.reason ?? row.Reason ?? row.message ?? row.Message ?? row.msg ?? row.Msg ?? '',
|
||
).trim()
|
||
if (!reason && row.step == null && row.Step == null) return null
|
||
return {
|
||
productId: (row.productId ?? row.ProductId) as number | undefined,
|
||
productCode: (row.productCode ?? row.ProductCode) as string | undefined,
|
||
productName: (row.productName ?? row.ProductName) as string | undefined,
|
||
step: (row.step ?? row.Step) as string | undefined,
|
||
reason: reason || undefined,
|
||
cargoTypeName: (row.cargoTypeName ?? row.CargoTypeName) as string | undefined,
|
||
warehouseName: (row.warehouseName ?? row.WarehouseName) as string | undefined,
|
||
}
|
||
}
|
||
|
||
/** 解析查价响应(兼容 data 包裹 / 直出、camel/Pascal、failures 在根或 data 内) */
|
||
export function parsePriceCheckResponse(resBody: any): {
|
||
items: any[]
|
||
failures: PriceCheckFailure[]
|
||
} {
|
||
assertBusinessOk(resBody)
|
||
const root = resBody ?? {}
|
||
const inner = root.data ?? root.Data ?? root
|
||
|
||
if (Array.isArray(inner)) {
|
||
return { items: inner, failures: [] }
|
||
}
|
||
|
||
const payload =
|
||
inner && typeof inner === 'object' && !Array.isArray(inner) ? inner : root
|
||
|
||
const items =
|
||
(payload as any).items ??
|
||
(payload as any).Items ??
|
||
(payload as any).list ??
|
||
(payload as any).List ??
|
||
[]
|
||
|
||
const rawFailures =
|
||
(payload as any).failures ??
|
||
(payload as any).Failures ??
|
||
root.failures ??
|
||
root.Failures ??
|
||
[]
|
||
|
||
const failureRows = Array.isArray(rawFailures)
|
||
? rawFailures
|
||
: rawFailures && typeof rawFailures === 'object'
|
||
? [rawFailures]
|
||
: []
|
||
|
||
const failures = failureRows
|
||
.map(normalizePriceCheckFailure)
|
||
.filter((f): f is PriceCheckFailure => f != null && Boolean(f.reason?.trim()))
|
||
|
||
const itemList = Array.isArray(items) ? items : []
|
||
|
||
if (!itemList.length && !failures.length) {
|
||
const msg = String(
|
||
root.msg ??
|
||
root.Msg ??
|
||
root.message ??
|
||
root.Message ??
|
||
(payload as any).msg ??
|
||
(payload as any).Msg ??
|
||
(payload as any).message ??
|
||
(payload as any).Message ??
|
||
'',
|
||
).trim()
|
||
if (msg) {
|
||
failures.push({ reason: msg })
|
||
}
|
||
}
|
||
|
||
return { items: itemList, failures }
|
||
}
|
||
|
||
export async function postOrderPriceCheck(params: PriceCheckRequest): Promise<{
|
||
items: any[]
|
||
failures: PriceCheckFailure[]
|
||
}> {
|
||
const res = await axiosInstance.post(orderUrl('/order/price-check'), params)
|
||
return parsePriceCheckResponse(res.data)
|
||
}
|
||
|
||
/** GET /order/template/list */
|
||
export async function getOrderTemplateList(params: {
|
||
page?: number
|
||
pageSize?: number
|
||
type?: 'standard' | 'custom' | string
|
||
keyword?: string
|
||
}): Promise<OrderListResult> {
|
||
const res = await axiosInstance.get(orderUrl('/order/template/list'), {
|
||
params: {
|
||
page: params.page ?? 1,
|
||
pageSize: params.pageSize ?? 50,
|
||
type: params.type ?? '',
|
||
keyword: params.keyword ?? '',
|
||
},
|
||
})
|
||
return parseOrderListPayload(res.data)
|
||
}
|
||
|
||
/** 从 axios 响应中解析二进制下载内容 */
|
||
function resolveDownloadBlob(response: {
|
||
data?: unknown
|
||
headers?: Record<string, string | undefined>
|
||
}): { blob: Blob; contentType: string } {
|
||
const headers = response?.headers ?? {}
|
||
const contentType = String(headers['content-type'] ?? headers['Content-Type'] ?? '')
|
||
const raw = response?.data
|
||
|
||
if (raw instanceof Blob) {
|
||
return { blob: raw, contentType: contentType || raw.type }
|
||
}
|
||
if (raw instanceof ArrayBuffer) {
|
||
return {
|
||
blob: new Blob([raw], {
|
||
type: contentType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
}),
|
||
contentType,
|
||
}
|
||
}
|
||
if (raw instanceof Uint8Array) {
|
||
return {
|
||
blob: new Blob([raw], {
|
||
type: contentType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
}),
|
||
contentType,
|
||
}
|
||
}
|
||
if (raw && typeof raw === 'object') {
|
||
const body = raw as Record<string, unknown>
|
||
throw new Error(
|
||
String(body.msg ?? body.Msg ?? body.message ?? body.Message ?? '下载失败'),
|
||
)
|
||
}
|
||
throw new Error('下载响应无效')
|
||
}
|
||
|
||
async function parseDownloadErrorBlob(blob: Blob): Promise<never> {
|
||
const text = await blob.text()
|
||
try {
|
||
const json = JSON.parse(text)
|
||
throw new Error(String(json.msg ?? json.message ?? json.Message ?? '下载失败'))
|
||
} catch (error: unknown) {
|
||
if (error instanceof Error && error.message !== '下载失败') {
|
||
throw error
|
||
}
|
||
throw new Error(text || '下载失败')
|
||
}
|
||
}
|
||
|
||
function triggerBrowserFileDownload(blob: Blob, fileName: string) {
|
||
const url = URL.createObjectURL(blob)
|
||
const a = document.createElement('a')
|
||
a.href = url
|
||
a.download = fileName.endsWith('.xlsx') ? fileName : `${fileName}.xlsx`
|
||
a.style.display = 'none'
|
||
document.body.appendChild(a)
|
||
a.click()
|
||
document.body.removeChild(a)
|
||
URL.revokeObjectURL(url)
|
||
}
|
||
|
||
/** GET /order/template/download?templateId= → Excel 文件流 */
|
||
export async function downloadOrderTemplate(templateId: number, fileName: string) {
|
||
const response = await axiosInstance.get(orderUrl('/order/template/download'), {
|
||
params: { templateId },
|
||
responseType: 'arraybuffer',
|
||
})
|
||
const { blob, contentType } = resolveDownloadBlob(response)
|
||
const ct = contentType || blob.type || ''
|
||
if (ct.includes('application/json') || ct.includes('text/json')) {
|
||
await parseDownloadErrorBlob(blob)
|
||
}
|
||
if (!blob.size) {
|
||
throw new Error('下载文件为空')
|
||
}
|
||
triggerBrowserFileDownload(blob, fileName)
|
||
}
|
||
|
||
export interface OrderTemplateFieldSchemaItem {
|
||
fieldKey: string
|
||
label: string
|
||
required: boolean
|
||
dataType: string
|
||
dictType?: string
|
||
group: string
|
||
example: string
|
||
}
|
||
|
||
export interface OrderTemplateCustomDetail {
|
||
id: number
|
||
name: string
|
||
type: string
|
||
standardTemplateKey?: string
|
||
mappingStatus?: string
|
||
sourceFileName?: string
|
||
sourceHeaders: string[]
|
||
mapping?: {
|
||
standardTemplateKey?: string
|
||
headerRowIndex?: number
|
||
dataStartRowIndex?: number
|
||
mappings?: Array<{ standardFieldKey: string; sourceColumn: string; required?: boolean }>
|
||
unmappedSourceColumns?: string[]
|
||
}
|
||
standardFields: OrderTemplateFieldSchemaItem[]
|
||
}
|
||
|
||
/** GET /order/template/field-schema */
|
||
export async function getOrderTemplateFieldSchema(templateKey?: string) {
|
||
const res = await axiosInstance.get(orderUrl('/order/template/field-schema'), {
|
||
params: { templateKey: templateKey ?? '' },
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return (res.data?.data ?? res.data?.Data ?? res.data) as {
|
||
templateKey: string
|
||
templateName: string
|
||
fields: OrderTemplateFieldSchemaItem[]
|
||
}
|
||
}
|
||
|
||
/** POST /order/template/custom/upload */
|
||
export async function postOrderTemplateCustomUpload(name: string, file: File) {
|
||
const form = new FormData()
|
||
form.append('name', name)
|
||
form.append('file', file)
|
||
const res = await axiosInstance.post(orderUrl('/order/template/custom/upload'), form)
|
||
assertBusinessOk(res.data)
|
||
const d = unwrapApiData(res.data)
|
||
const templateId = Number(d.templateId ?? d.TemplateId ?? d.id ?? d.Id)
|
||
if (!Number.isFinite(templateId) || templateId <= 0) {
|
||
throw new Error('上传成功但未返回模板 ID')
|
||
}
|
||
return {
|
||
templateId,
|
||
name: String(d.name ?? d.Name ?? name),
|
||
mappingStatus: String(d.mappingStatus ?? d.MappingStatus ?? 'draft'),
|
||
sourceHeaders: (d.sourceHeaders ?? d.SourceHeaders ?? []) as string[],
|
||
}
|
||
}
|
||
|
||
/** GET /order/template/custom/detail */
|
||
export async function getOrderTemplateCustomDetail(templateId: number): Promise<OrderTemplateCustomDetail> {
|
||
const res = await axiosInstance.get(orderUrl('/order/template/custom/detail'), {
|
||
params: { templateId },
|
||
})
|
||
assertBusinessOk(res.data)
|
||
const d = unwrapApiData(res.data)
|
||
return {
|
||
id: Number(d.id ?? d.Id ?? templateId),
|
||
name: String(d.name ?? d.Name ?? ''),
|
||
type: String(d.type ?? d.Type ?? 'custom'),
|
||
standardTemplateKey: d.standardTemplateKey ?? d.StandardTemplateKey,
|
||
mappingStatus: d.mappingStatus ?? d.MappingStatus,
|
||
sourceFileName: d.sourceFileName ?? d.SourceFileName,
|
||
sourceHeaders: (d.sourceHeaders ?? d.SourceHeaders ?? []) as string[],
|
||
mapping: d.mapping ?? d.Mapping,
|
||
standardFields: (d.standardFields ?? d.StandardFields ?? []) as OrderTemplateFieldSchemaItem[],
|
||
}
|
||
}
|
||
|
||
/** POST /order/template/custom/save-mapping */
|
||
export async function postOrderTemplateSaveMapping(body: {
|
||
templateId: number
|
||
standardTemplateKey?: string
|
||
headerRowIndex?: number
|
||
dataStartRowIndex?: number
|
||
mappings: Array<{ standardFieldKey: string; sourceColumn: string }>
|
||
}) {
|
||
const templateId = Number(body.templateId)
|
||
if (!Number.isFinite(templateId) || templateId <= 0) {
|
||
throw new Error('模板 ID 无效')
|
||
}
|
||
const payload = {
|
||
TemplateId: templateId,
|
||
StandardTemplateKey: body.standardTemplateKey,
|
||
HeaderRowIndex: body.headerRowIndex ?? 1,
|
||
DataStartRowIndex: body.dataStartRowIndex ?? 2,
|
||
Mappings: body.mappings.map((item) => ({
|
||
StandardFieldKey: item.standardFieldKey,
|
||
SourceColumn: item.sourceColumn,
|
||
})),
|
||
}
|
||
const res = await axiosInstance.post(orderUrl('/order/template/custom/save-mapping'), payload)
|
||
assertBusinessOk(res.data)
|
||
const d = unwrapApiData(res.data)
|
||
return {
|
||
templateId: Number(d.templateId ?? d.TemplateId ?? templateId),
|
||
mappingStatus: String(d.mappingStatus ?? d.MappingStatus ?? 'draft'),
|
||
missingRequiredFields: (d.missingRequiredFields ?? d.MissingRequiredFields ?? []) as string[],
|
||
}
|
||
}
|
||
|
||
/** DELETE /order/template/custom/{id} */
|
||
export async function deleteOrderTemplateCustom(templateId: number) {
|
||
const res = await axiosInstance.delete(orderUrl(`/order/template/custom/${templateId}`))
|
||
const body = res?.data
|
||
if (body == null || body === '') {
|
||
return
|
||
}
|
||
assertBusinessOk(body)
|
||
}
|
||
|
||
/** POST /order/upload multipart: file + templateId */
|
||
export async function postOrderUpload(
|
||
file: File,
|
||
templateId: number
|
||
): Promise<{ taskId?: number; jobId?: number; async?: boolean }> {
|
||
const form = new FormData()
|
||
form.append('file', file)
|
||
form.append('templateId', String(templateId))
|
||
const res = await axiosInstance.post(orderUrl('/order/upload'), form)
|
||
assertBusinessOk(res.data)
|
||
const d = unwrapApiData(res.data)
|
||
const taskId = d.taskId ?? d.TaskId
|
||
const jobId = d.jobId ?? d.JobId
|
||
const asyncFlag = d.async ?? d.Async
|
||
return {
|
||
taskId: taskId != null ? Number(taskId) : undefined,
|
||
jobId: jobId != null ? Number(jobId) : undefined,
|
||
async: asyncFlag === true || asyncFlag === 'true',
|
||
}
|
||
}
|
||
|
||
/** GET /order/task/list */
|
||
export async function getOrderTaskList(params: {
|
||
page?: number
|
||
pageSize?: number
|
||
status?: string
|
||
keyword?: string
|
||
}): Promise<OrderListResult> {
|
||
const res = await axiosInstance.get(orderUrl('/order/task/list'), {
|
||
params: {
|
||
page: params.page ?? 1,
|
||
pageSize: params.pageSize ?? 20,
|
||
status: params.status ?? '',
|
||
keyword: params.keyword ?? '',
|
||
},
|
||
})
|
||
return parseOrderListPayload(res.data)
|
||
}
|
||
|
||
/** GET /order/task/detail?taskId= */
|
||
export async function getOrderTaskDetail(taskId: number | string): Promise<any> {
|
||
const res = await axiosInstance.get(orderUrl('/order/task/detail'), {
|
||
params: { taskId },
|
||
})
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? {}
|
||
}
|
||
|
||
/** POST /order/parcel/create */
|
||
export async function postOrderParcelCreate(body: Record<string, any>): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/parcel/create'), body)
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? {}
|
||
}
|
||
|
||
export interface OrderParcelBatchCreateResult {
|
||
batchNo?: string
|
||
BatchNo?: string
|
||
jobId?: number
|
||
JobId?: number
|
||
async?: boolean
|
||
Async?: boolean
|
||
total?: number
|
||
Total?: number
|
||
successCount?: number
|
||
SuccessCount?: number
|
||
failCount?: number
|
||
FailCount?: number
|
||
items?: Array<{
|
||
index?: number
|
||
Index?: number
|
||
requestId?: string
|
||
RequestId?: string
|
||
clientNo?: string
|
||
ClientNo?: string
|
||
serviceNo?: string
|
||
ServiceNo?: string
|
||
trackNo?: string
|
||
TrackNo?: string
|
||
labelUrl?: string
|
||
LabelUrl?: string
|
||
success?: boolean
|
||
Success?: boolean
|
||
message?: string
|
||
Message?: string
|
||
}>
|
||
Items?: OrderParcelBatchCreateResult['items']
|
||
}
|
||
|
||
function parseOrderParcelBatchCreateResult(raw: any): {
|
||
batchNo: string
|
||
jobId?: number
|
||
async: boolean
|
||
total: number
|
||
successCount: number
|
||
failCount: number
|
||
items: Array<{
|
||
index: number
|
||
clientNo?: string
|
||
serviceNo?: string
|
||
success: boolean
|
||
message?: string
|
||
}>
|
||
} {
|
||
const d = raw?.data ?? raw?.Data ?? raw ?? {}
|
||
const itemsRaw = d.items ?? d.Items ?? []
|
||
const items = (Array.isArray(itemsRaw) ? itemsRaw : []).map((item: any, idx: number) => ({
|
||
index: Number(item.index ?? item.Index ?? idx + 1),
|
||
clientNo: item.clientNo ?? item.ClientNo,
|
||
serviceNo: item.serviceNo ?? item.ServiceNo,
|
||
success: item.success ?? item.Success ?? false,
|
||
message: item.message ?? item.Message,
|
||
}))
|
||
return {
|
||
batchNo: String(d.batchNo ?? d.BatchNo ?? ''),
|
||
jobId: d.jobId != null || d.JobId != null ? Number(d.jobId ?? d.JobId) : undefined,
|
||
async: d.async === true || d.Async === true,
|
||
total: Number(d.total ?? d.Total ?? items.length),
|
||
successCount: Number(d.successCount ?? d.SuccessCount ?? 0),
|
||
failCount: Number(d.failCount ?? d.FailCount ?? 0),
|
||
items,
|
||
}
|
||
}
|
||
|
||
/** POST /order/parcel/batch-create */
|
||
export async function postOrderParcelBatchCreate(
|
||
bodies: Array<Record<string, any>>
|
||
): Promise<ReturnType<typeof parseOrderParcelBatchCreateResult>> {
|
||
const res = await axiosInstance.post(orderUrl('/order/parcel/batch-create'), bodies)
|
||
assertBusinessOk(res.data)
|
||
return parseOrderParcelBatchCreateResult(res.data)
|
||
}
|
||
|
||
/** POST /order/update */
|
||
export async function postOrderUpdate(body: Record<string, any>): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/update'), body)
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|
||
|
||
/** POST /order/weight/update */
|
||
export async function postOrderWeightUpdate(body: {
|
||
id: number | string
|
||
weights: Array<{
|
||
type: string
|
||
length?: number
|
||
width?: number
|
||
height?: number
|
||
actualWeight?: number
|
||
}>
|
||
}): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/weight/update'), body)
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|
||
|
||
/** POST /order/fee/recalculate-receivable */
|
||
export async function postOrderRecalculateReceivable(body: OrderIdRequest): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/fee/recalculate-receivable'), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|
||
|
||
/** POST /order/fee/recalculate-payable */
|
||
export async function postOrderRecalculatePayable(body: OrderIdRequest): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/fee/recalculate-payable'), { id: body.id })
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|
||
|
||
export interface OrderFeeAddRequest {
|
||
id: number | string
|
||
type: 'receivable' | 'payable'
|
||
costItem: string
|
||
amount: number
|
||
currency: string
|
||
chargingStage: string
|
||
downstreamProvider?: string
|
||
priceNo?: string
|
||
priceEffectiveTime?: string
|
||
}
|
||
|
||
/** POST /order/fee/add */
|
||
export async function postOrderFeeAdd(body: OrderFeeAddRequest): Promise<any> {
|
||
const res = await axiosInstance.post(orderUrl('/order/fee/add'), body)
|
||
assertBusinessOk(res.data)
|
||
return res.data?.data ?? res.data?.Data ?? res.data
|
||
}
|