import { apiClient } from '@/shared/api/client' import type { ApiResponse, PaginatedResult } from '@/shared/types/types' // 结算差异判定阈值(分)。号主应得与钱包入账/线下结算差额绝对值达到此值即标红。 // 与后端 settlementDiffThresholdCent 保持一致,改口径时两端同步。 export const SETTLEMENT_DIFF_THRESHOLD_CENT = 5 export interface FinanceSummary { total_flow_amount_cent: number total_refund_amount_cent: number pending_refund_amount_cent: number channel_net_amount_cent: number platform_income_amount_cent: number normal_order_profit_amount_cent: number pickup_profit_amount_cent: number /** 普通(租赁)订单利润对应的已结算订单数量 */ settled_order_count: number /** 线下提号利润对应的已完成提号笔数 */ pickup_completed_count: number owner_should_income_amount_cent: number owner_wallet_income_amount_cent: number owner_effective_settlement_amount_cent: number offline_settlement_amount_cent: number offline_settlement_pending_amount_cent: number settlement_diff_amount_cent: number estimated_income_amount_cent: number successful_pay_count: number successful_refund_count: number full_refund_count: number partial_refund_count: number pending_refund_count: number pending_settle_order_count: number offline_settlement_pending_count: number financial_exception_count: number } export interface FinanceDailyItem { date: string total_flow_amount_cent: number total_refund_amount_cent: number pending_refund_amount_cent: number channel_net_amount_cent: number platform_income_amount_cent: number owner_should_income_amount_cent: number owner_wallet_income_amount_cent: number owner_effective_settlement_amount_cent: number offline_settlement_amount_cent: number offline_settlement_pending_amount_cent: number settlement_diff_amount_cent: number estimated_income_amount_cent: number successful_pay_count: number successful_refund_count: number full_refund_count: number partial_refund_count: number pending_refund_count: number settled_order_count: number pickup_completed_count: number /** 正常(租赁)订单已退全款笔数(不含撞车商城退款) */ normal_full_refund_count: number /** 线下提号取消笔数 */ pickup_cancelled_count: number sales_count: number paid_order_count: number offline_settlement_pending_count: number offline_settlement_paid_amount_cent: number offline_settlement_paid_count: number withdrawal_paid_amount_cent: number withdrawal_paid_count: number manual_paid_amount_cent: number manual_paid_count: number operating_expense_amount_cent: number operating_expense_count: number disbursement_paid_amount_cent: number disbursement_paid_count: number } export interface FinancePickupSummary { settled_amount_cent: number profit_amount_cent: number completed_count: number in_progress_count: number } export interface FinanceMohongSummary { flow_amount_cent: number refund_amount_cent: number net_amount_cent: number paid_order_count: number } export interface FinanceDisbursementSummary { paid_amount_cent: number paid_count: number pending_payment_amount_cent: number pending_payment_count: number offline_settlement_paid_amount_cent: number offline_settlement_paid_count: number offline_settlement_pending_amount_cent: number offline_settlement_pending_count: number withdrawal_amount_cent: number withdrawal_fee_amount_cent: number withdrawal_paid_amount_cent: number withdrawal_paid_count: number withdrawal_pending_amount_cent: number withdrawal_pending_count: number withdrawal_review_amount_cent: number withdrawal_review_count: number manual_paid_amount_cent: number manual_paid_count: number } export interface OperatingExpenseSummary { amount_cent: number count: number } export interface FinanceDisbursementListSummary { record_count: number paid_amount_cent: number paid_count: number payment_pending_amount_cent: number payment_pending_count: number review_pending_amount_cent: number review_pending_count: number withdrawal_fee_amount_cent: number } export interface FinanceDisbursementItem { source_type: 'platform_managed' | 'withdrawal' | 'manual_offline' source_id: number business_no: string order_id?: number withdrawal_id?: number user_id: number payee_name: string payee_phone: string uploader_name: string source_channel: string account_type: string account_name: string account_no: string bank_name: string amount_cent: number fee_cent: number actual_amount_cent: number status: 'review_pending' | 'payment_pending' | 'paid' | 'rejected' | 'cancelled' | 'voided' raw_status: string business_created_at?: string paid_at?: string operator_id?: number operator_name: string remark: string category: string custom_category_name: string voucher_url: string voided_at?: string voided_by?: number voided_by_name: string void_reason: string } export interface CreateManualDisbursementPayload { category: string custom_category_name?: string payee_name: string amount_cent: number paid_at: string remark: string voucher_url?: string } export interface ManualDisbursement { id: number disbursement_no: string category: string custom_category_name: string payee_name: string amount_cent: number paid_at: string remark: string voucher_url: string status: 'paid' | 'voided' created_by: number created_by_name: string voided_by?: number voided_by_name: string voided_at?: string void_reason: string created_at: string } export interface FinanceDisbursementQuery extends FinanceDateQuery { source_type?: string status?: string date_type?: string business_no?: string keyword?: string user_id?: string page?: number page_size?: number } export interface FinanceDisbursementList { items: FinanceDisbursementItem[] total: number page: number page_size: number summary: FinanceDisbursementListSummary } export interface FinanceDashboard { summary: FinanceSummary daily_items: FinanceDailyItem[] pickup_summary: FinancePickupSummary mohong_summary: FinanceMohongSummary disbursement_summary: FinanceDisbursementSummary operating_expense_summary: OperatingExpenseSummary generated_at: string } export interface OperatingExpense { id: number expense_no: string category: string payee_name: string amount_cent: number occurred_at: string remark: string voucher_url: string status: 'paid' | 'voided' created_by: number created_by_name: string voided_by?: number voided_by_name: string voided_at?: string void_reason: string created_at: string } export interface OperatingExpenseQuery extends FinanceDateQuery { status?: string category?: string keyword?: string date_type?: 'created' | 'occurred' page?: number page_size?: number } export interface OperatingExpenseListSummary { record_count: number paid_amount_cent: number paid_count: number } export interface OperatingExpenseList { items: OperatingExpense[] total: number page: number page_size: number summary: OperatingExpenseListSummary } export interface CreateOperatingExpensePayload { category: string payee_name: string amount_cent: number occurred_at: string remark: string voucher_url?: string } export interface FinanceDetail { order_id: number order_no: string order_status: string settlement_status: string refund_status: string handoff_mode: string settlement_mode: string offline_settlement_status: string offline_settlement_amount_cent: number renter_id: number renter_phone: string renter_nickname: string owner_id: number owner_phone: string owner_nickname: string order_rent_amount_cent: number order_deposit_amount_cent: number checkout_rent_amount_cent: number checkout_renter_refund_cent: number checkout_owner_income_cent: number checkout_platform_fee_cent: number owner_wallet_income_amount_cent: number owner_effective_settlement_amount_cent: number paid_amount_cent: number refunded_amount_cent: number refunding_amount_cent: number failed_refund_amount_cent: number channel_net_amount_cent: number platform_net_amount_cent: number settlement_diff_amount_cent: number finance_status: string created_at: string settled_at?: string offline_settled_at?: string } export interface FinanceDateQuery { start_date?: string end_date?: string } export interface FinanceDetailQuery extends FinanceDateQuery { order_no?: string user_id?: string order_status?: string settlement_status?: string settlement_mode?: string offline_settlement_status?: string date_type?: string page?: number page_size?: number } function cleanParams(query: object) { return Object.fromEntries( Object.entries(query).filter(([, value]) => value !== '' && value !== undefined) ) } export async function fetchFinanceDashboard(query: FinanceDateQuery = {}) { const { data } = await apiClient.get>('/admin/finance/dashboard', { params: cleanParams(query), }) return { ...data.data, daily_items: Array.isArray(data.data?.daily_items) ? data.data.daily_items : [], pickup_summary: data.data?.pickup_summary ?? { settled_amount_cent: 0, profit_amount_cent: 0, completed_count: 0, in_progress_count: 0, }, mohong_summary: data.data?.mohong_summary ?? { flow_amount_cent: 0, refund_amount_cent: 0, net_amount_cent: 0, paid_order_count: 0, }, disbursement_summary: data.data?.disbursement_summary ?? { paid_amount_cent: 0, paid_count: 0, pending_payment_amount_cent: 0, pending_payment_count: 0, offline_settlement_paid_amount_cent: 0, offline_settlement_paid_count: 0, offline_settlement_pending_amount_cent: 0, offline_settlement_pending_count: 0, withdrawal_amount_cent: 0, withdrawal_fee_amount_cent: 0, withdrawal_paid_amount_cent: 0, withdrawal_paid_count: 0, withdrawal_pending_amount_cent: 0, withdrawal_pending_count: 0, withdrawal_review_amount_cent: 0, withdrawal_review_count: 0, manual_paid_amount_cent: 0, manual_paid_count: 0, }, operating_expense_summary: data.data?.operating_expense_summary ?? { amount_cent: 0, count: 0, }, } } export async function fetchFinanceDetails(query: FinanceDetailQuery = {}) { const { data } = await apiClient.get>>( '/admin/finance/details', { 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 fetchFinanceDisbursements(query: FinanceDisbursementQuery = {}) { const { data } = await apiClient.get>( '/admin/finance/disbursements', { 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), summary: result?.summary ?? { record_count: 0, paid_amount_cent: 0, paid_count: 0, payment_pending_amount_cent: 0, payment_pending_count: 0, review_pending_amount_cent: 0, review_pending_count: 0, withdrawal_fee_amount_cent: 0, }, } } export async function fetchOperatingExpenses(query: OperatingExpenseQuery = {}) { const { data } = await apiClient.get>( '/admin/finance/operating-expenses', { 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), summary: result?.summary ?? { record_count: 0, paid_amount_cent: 0, paid_count: 0 }, } } export async function createOperatingExpense(payload: CreateOperatingExpensePayload) { const { data } = await apiClient.post>( '/admin/finance/operating-expenses', payload ) return data.data } export async function voidOperatingExpense(id: number, reason: string) { const { data } = await apiClient.post>( `/admin/finance/operating-expenses/${id}/void`, { reason } ) return data.data } export async function createManualDisbursement(payload: CreateManualDisbursementPayload) { const { data } = await apiClient.post>( '/admin/finance/manual-disbursements', payload ) return data.data } export async function voidManualDisbursement(id: number, reason: string) { const { data } = await apiClient.post>( `/admin/finance/manual-disbursements/${id}/void`, { reason } ) return data.data }