Files
hfb_sys/frontend/src/features/admin/api/adminPickup.ts
T
yml2213 b4d2d1e2f5 feat(pickup): 增加第三方单号补录功能并优化列表提号备注展示
- 后端支持补录/修改第三方单号接口 PUT /api/v1/admin/pickups/:id/third-party-order-no,记录流转事件与审计日志
- 前端线下提号主列表在第三方单号列后展示提号备注列
- 前端列表操作列及提号详情页增加补录/修改第三方单号操作入口与弹窗
- 通过 scripts/check.sh 全量门禁校验
2026-10-09 18:45:12 +08:00

416 lines
11 KiB
TypeScript

import { apiClient } from '@/shared/api/client'
import type { ApiResponse, PaginatedResult } from '@/shared/types/types'
export type PickupAccountSource = 'internal' | 'external_platform_managed'
export type PickupSettlementMode = 'owner_wallet' | 'platform_managed'
export type PickupOfflineSettlementStatus = 'none' | 'pending' | 'settled'
export type PickupFinancialAdjustmentStatus = 'settled' | 'pending' | 'recovery_pending'
export type AvailableListingSourceType = '' | 'external' | 'internal'
export interface AdminPickup {
id: number
pickup_no: string
listing_id: number
listing_no: string
account_id: number
account_title: string
server_region: string
login_platform: string
owner_id: number
owner_phone: string
admin_id: number
operator: string
platform: string
third_party_order_no: string
shop_name: string
raw_shop_name?: string
account_source: PickupAccountSource
source_channel: string
settlement_mode: PickupSettlementMode
listing_price_cent: number
order_amount_cent: number
deposit_amount_cent: number
owner_price_cent: number
website_profit_cent: number
profit_amount_cent: number
profit_adjustment_cent: number
effective_profit_amount_cent: number
seller_ratio: number
buyer_ratio: number
account_snapshot?: Record<string, unknown>
settle_amount_cent: number
settle_adjustment_cent: number
effective_settle_amount_cent: number
status: string
offline_settlement_status: PickupOfflineSettlementStatus
offline_settlement_remark: string
offline_settled_by?: number
offline_settled_at?: string
remark: string
complete_remark: string
created_at: string
completed_at?: string
cancelled_at?: string
}
export interface AdminPickupFinancialAdjustment {
id: number
pickup_id: number
profit_delta_cent: number
settle_delta_cent: number
settlement_mode: PickupSettlementMode
status: PickupFinancialAdjustmentStatus
reason: string
created_by: number
settled_by?: number
settled_at?: string
settlement_remark: string
created_at: string
}
export interface AdminPickupProcessEvent {
id: number
stage: string
action: string
actor_type: string
actor_id: number
actor_name: string
target_type: string
target_id?: number
target_name: string
content: string
reason: string
payload: Record<string, unknown>
attachment_urls: string[]
state_before: Record<string, unknown>
state_after: Record<string, unknown>
created_at: string
}
export interface AvailableListing {
id: number
listing_no: string
account_id: number
account_title: string
server_region: string
login_platform: string
owner_id: number
owner_phone: string
listing_price_cent: number
owner_price_cent: number
owner_pure_price_cent: number
owner_extra_item_price_cent: number
owner_total_price_cent: number
website_profit_cent: number
seller_ratio: number
buyer_ratio: number
account_source: PickupAccountSource
is_external_upload: boolean
source_channel: string
handoff_mode: string
settlement_mode: string
}
export interface AdminPickupCreateRequest {
listing_id: number
operator?: string
platform?: string
third_party_order_no?: string
shop_name?: string
order_amount_cent?: number
deposit_amount_cent?: number
profit_amount_cent?: number
remark?: string
}
export interface AdminPickupCompleteRequest {
settle_amount_cent: number
profit_amount_cent?: number
complete_remark?: string
}
export interface AdminPickupProfitUpdateRequest {
profit_amount_cent: number
reason?: string
}
export interface AdminPickupThirdPartyOrderNoUpdateRequest {
third_party_order_no: string
}
export interface AdminPickupOfflineSettlementRequest {
remark?: string
}
export interface AdminPickupFinancialAdjustmentRequest {
profit_amount_cent?: number
settle_amount_cent?: number
reason: string
}
export interface AdminPickupFinancialAdjustmentSettlementRequest {
remark?: string
}
export interface AdminPickupListQuery {
page?: number
page_size?: number
keyword?: string
status?: string
shop_name?: string
account_source?: PickupAccountSource | ''
offline_settlement_status?: PickupOfflineSettlementStatus | ''
operator?: string
third_party_order_no?: string
start_time?: string
end_time?: string
}
export interface PickupShop {
id: number
name: string
platform: string
status: 'active' | 'disabled'
sort_order: number
remark: string
created_at: string
updated_at: string
}
export interface PickupShopCreateRequest {
name: string
platform?: string
status?: 'active' | 'disabled'
sort_order?: number
remark?: string
}
export interface PickupShopUpdateRequest {
name: string
platform?: string
status: 'active' | 'disabled'
sort_order?: number
remark?: string
}
export interface PickupShopQuery {
keyword?: string
platform?: string
status?: string
}
export type PickupShopMappingStatus = 'standard' | 'mapped' | 'unmapped'
export interface PickupShopHistoricalItem {
source_name: string
count: number
mapping_status: PickupShopMappingStatus
target_shop_id?: number
target_shop_name?: string
remark?: string
}
export interface PickupShopHistoricalStats {
items: PickupShopHistoricalItem[]
total_pickups: number
total_shops: number
standard_count: number
mapped_count: number
unmapped_count: number
}
export interface MapHistoricalShopsRequest {
from_shop_names: string[]
target_shop_name: string
create_target_missing?: boolean
target_platform?: string
remark?: string
}
export interface MapHistoricalShopsResult {
updated_pickups_count: number
target_shop_name: string
target_shop_id: number
created_standard_shop: boolean
}
function cleanParams(query: object) {
return Object.fromEntries(
Object.entries(query).filter(([, value]) => value !== '' && value !== undefined)
)
}
export async function fetchAdminPickups(query: AdminPickupListQuery = {}) {
const { data } = await apiClient.get<ApiResponse<PaginatedResult<AdminPickup>>>(
'/admin/pickups',
{ params: cleanParams(query) }
)
const result = data.data
return {
items: Array.isArray(result?.items) ? result.items : [],
total: Number(result?.total ?? 0),
page: Number(result?.page ?? query.page ?? 1),
page_size: Number(result?.page_size ?? query.page_size ?? 20),
}
}
export async function fetchAdminPickup(id: string | number) {
const { data } = await apiClient.get<ApiResponse<AdminPickup>>(`/admin/pickups/${id}`)
return data.data
}
export async function fetchAdminPickupShopOptions(platform = '') {
const { data } = await apiClient.get<ApiResponse<string[]>>('/admin/pickups/shop-options', {
params: cleanParams({ platform }),
})
return Array.isArray(data.data) ? data.data : []
}
export async function fetchAvailableListings(
keyword = '',
page = 1,
page_size = 20,
source_type: AvailableListingSourceType = ''
) {
const { data } = await apiClient.get<ApiResponse<PaginatedResult<AvailableListing>>>(
'/admin/pickups/available-listings',
{ params: cleanParams({ keyword, page, page_size, source_type }) }
)
const result = data.data
return {
items: Array.isArray(result?.items) ? result.items : [],
total: Number(result?.total ?? 0),
}
}
export async function createAdminPickup(req: AdminPickupCreateRequest) {
const { data } = await apiClient.post<ApiResponse<AdminPickup>>('/admin/pickups', req)
return data.data
}
export async function completeAdminPickup(id: number, req: AdminPickupCompleteRequest) {
const { data } = await apiClient.post<ApiResponse<AdminPickup>>(
`/admin/pickups/${id}/complete`,
req
)
return data.data
}
export async function confirmAdminPickupOfflineSettlement(
id: number,
req: AdminPickupOfflineSettlementRequest = {}
) {
const { data } = await apiClient.post<ApiResponse<AdminPickup>>(
`/admin/pickups/${id}/offline-settlement`,
req
)
return data.data
}
export async function updateAdminPickupProfit(id: number, req: AdminPickupProfitUpdateRequest) {
const { data } = await apiClient.put<ApiResponse<AdminPickup>>(`/admin/pickups/${id}/profit`, req)
return data.data
}
export async function updateAdminPickupThirdPartyOrderNo(
id: number,
req: AdminPickupThirdPartyOrderNoUpdateRequest
) {
const { data } = await apiClient.put<ApiResponse<AdminPickup>>(
`/admin/pickups/${id}/third-party-order-no`,
req
)
return data.data
}
export async function createAdminPickupFinancialAdjustment(
id: number,
req: AdminPickupFinancialAdjustmentRequest
) {
const { data } = await apiClient.post<ApiResponse<AdminPickup>>(
`/admin/pickups/${id}/financial-adjustments`,
req
)
return data.data
}
export async function fetchAdminPickupFinancialAdjustments(id: string | number) {
const { data } = await apiClient.get<ApiResponse<AdminPickupFinancialAdjustment[]>>(
`/admin/pickups/${id}/financial-adjustments`
)
return Array.isArray(data.data) ? data.data : []
}
export async function fetchAdminPickupProcessEvents(id: string | number) {
const { data } = await apiClient.get<ApiResponse<{ items: AdminPickupProcessEvent[] }>>(
`/admin/pickups/${id}/process-events`
)
return Array.isArray(data.data?.items) ? data.data.items : []
}
export async function settleAdminPickupFinancialAdjustment(
id: number,
req: AdminPickupFinancialAdjustmentSettlementRequest = {}
) {
const { data } = await apiClient.post<ApiResponse<{ settled: boolean }>>(
`/admin/pickup-financial-adjustments/${id}/settle`,
req
)
return data.data
}
export async function cancelAdminPickup(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ cancelled: boolean }>>(
`/admin/pickups/${id}/cancel`,
{ reason }
)
return data.data
}
export async function fetchPickupShops(query: PickupShopQuery = {}) {
const { data } = await apiClient.get<ApiResponse<PickupShop[]>>('/admin/pickups/shops', {
params: cleanParams(query),
})
return Array.isArray(data.data) ? data.data : []
}
export async function createPickupShop(req: PickupShopCreateRequest) {
const { data } = await apiClient.post<ApiResponse<PickupShop>>('/admin/pickups/shops', req)
return data.data
}
export async function updatePickupShop(id: number, req: PickupShopUpdateRequest) {
const { data } = await apiClient.put<ApiResponse<PickupShop>>(`/admin/pickups/shops/${id}`, req)
return data.data
}
export async function deletePickupShop(id: number) {
const { data } = await apiClient.delete<ApiResponse<{ deleted: boolean }>>(
`/admin/pickups/shops/${id}`
)
return data.data
}
export async function fetchHistoricalShopStats() {
const { data } = await apiClient.get<ApiResponse<PickupShopHistoricalStats>>(
'/admin/pickups/shops/historical-stats'
)
return data.data
}
export async function mapHistoricalShops(req: MapHistoricalShopsRequest) {
const { data } = await apiClient.post<ApiResponse<MapHistoricalShopsResult>>(
'/admin/pickups/shops/map-historical',
req
)
return data.data
}
export async function deleteShopMapping(sourceName: string) {
const { data } = await apiClient.delete<ApiResponse<{ deleted: boolean }>>(
'/admin/pickups/shops/mappings',
{ params: { source_name: sourceName } }
)
return data.data
}