From 4086cc00de180e49532c3f08b0ffd7b867fa62da Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Mon, 5 Jan 2026 18:17:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=20Transaction=20?= =?UTF-8?q?=E5=92=8C=20Reconciliation=20API=20=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transaction API: - 新增 deposit() 充值方法 - 新增 withdraw() 提现方法 - 修正 transfer() 端点路径为 /transactions/transfer - 添加 DepositRequest 和 WithdrawRequest 类型 - 标记需要后端扩展的方法 Reconciliation API: - 新增 approveAdjustment() 审批补录方法 - 新增 rejectAdjustment() 拒绝补录方法 - 新增 getPendingAdjustments() 获取待审批列表 - 修正 runReconciliation() 端点路径为 /reconciliation/run - 完善类型定义 (ReconciliationBatch, ManualAdjustment 等) - 添加状态标签映射 现在前端 API 覆盖率: - Transaction: 100% (5/5 端点) - Reconciliation: 100% (8/8 端点) --- src/api/reconciliation.ts | 361 ++++++++++++++++++++++++++++---------- src/api/transaction.ts | 188 ++++++++++++++++---- 2 files changed, 427 insertions(+), 122 deletions(-) diff --git a/src/api/reconciliation.ts b/src/api/reconciliation.ts index 73c2e16..de65052 100644 --- a/src/api/reconciliation.ts +++ b/src/api/reconciliation.ts @@ -1,131 +1,312 @@ -// 对账相关API服务 +/** + * 对账 API 客户端 + * 提供对账批次管理、三账校验、手工补录等功能 + */ import { apiClient } from './client' +import type { PageResponse } from '@/types/api' +/** + * 对账批次 + */ export interface ReconciliationBatch { id: number - batchNo: string - reconDate: string - status: string - totalTransactions: number - matchedCount: number - mismatchedCount: number - bankTotal: number - ledgerTotal: number - inTransitNet: number - threeAccountBalanced: boolean - difference: number - createdAt: string - completedAt?: string + batch_no: string + physical_account_id: number + recon_date: string + total_count: number + matched_count: number + mismatch_count: number + status: ReconciliationStatus + bank_total?: string + transit_net?: string + ledger_total?: string + three_account_balanced?: boolean + created_at: string + completed_at?: string } +/** + * 对账批次状态 + */ +export type ReconciliationStatus = 'processing' | 'completed' | 'need_review' + +/** + * 对账明细项 + */ export interface ReconciliationItem { id: number - batchId: number - transactionId?: number - bankRefNo?: string - txnType: string - amount: number - bankAmount?: number - ledgerAmount?: number - matchStatus: 'matched' | 'mismatched' | 'bank_only' | 'ledger_only' - matchTime?: string - remarks?: string + batch_id: number + system_txn_no?: string + bank_ref_no?: string + system_amount?: string + bank_amount?: string + diff_amount: string + status: ReconciliationItemStatus + remark?: string + created_at: string } +/** + * 对账项状态 + */ +export type ReconciliationItemStatus = + | 'matched' // 已匹配 + | 'system_unreached' // 系统未达 + | 'bank_unreached' // 银行未达 + | 'amount_mismatch' // 金额不匹配 + | 'adjusted' // 已调整 + +/** + * 三账校验结果 + */ export interface ThreeAccountResult { - bankBalance: number - transitNet: number - ledgerTotal: number - isBalanced: boolean - difference: number + physical_account_id: number + bank_balance: string + transit_net: string + ledger_total: string + expected_total: string + difference: string + is_balanced: boolean + verified_at: string +} + +/** + * 手工补录 + */ +export interface ManualAdjustment { + id: number + adjustment_no: string + related_txn_no?: string + reconciliation_item_id?: number + adjustment_type: AdjustmentType + account_id: number + amount: string + reason: string + operator: string + approver?: string + status: AdjustmentStatus + created_at: string + approved_at?: string +} + +/** + * 补录类型 + */ +export type AdjustmentType = 'add' | 'reverse' | 'modify' + +/** + * 补录状态 + */ +export type AdjustmentStatus = 'pending' | 'approved' | 'rejected' + +/** + * 创建对账请求 + */ +export interface CreateReconciliationRequest { + physical_account_id: number + recon_date: string +} + +/** + * 创建补录请求 + */ +export interface CreateAdjustmentRequest { + related_txn_no?: string + reconciliation_item_id?: number + adjustment_type: AdjustmentType + account_id: number + amount: string + reason: string } export class ReconciliationAPI { - // 获取对账批次列表 - static async getBatches(params?: { - status?: string - startDate?: string - endDate?: string - page?: number - pageSize?: number - }): Promise<{ - items: ReconciliationBatch[] - total: number - }> { - return apiClient.get('/reconciliation/batches', params) + // ==================== 核心对账功能 (已对接后端) ==================== + + /** + * 执行对账 + * 对应后端: POST /api/v1/reconciliation/run + */ + static async runReconciliation(data: CreateReconciliationRequest): Promise { + return apiClient.post('/reconciliation/run', data) } - - // 获取对账批次详情 + + /** + * 获取对账批次详情 + * 对应后端: GET /api/v1/reconciliation/batches/:id + */ static async getBatch(id: number): Promise { return apiClient.get(`/reconciliation/batches/${id}`) } - // 创建对账批次 - static async createBatch(data: { - reconDate: string - accountIds?: number[] - }): Promise { - return apiClient.post('/reconciliation/batches', data) - } - - // 执行对账 - static async executeBatch(id: number): Promise { - return apiClient.post(`/reconciliation/batches/${id}/execute`) - } - - // 获取对账明细 + /** + * 获取对账明细 + * 对应后端: GET /api/v1/reconciliation/batches/:id/items + */ static async getBatchItems(batchId: number, params?: { - matchStatus?: string + status?: ReconciliationItemStatus page?: number - pageSize?: number - }): Promise<{ - items: ReconciliationItem[] - total: number - }> { - return apiClient.get(`/reconciliation/batches/${batchId}/items`, params) + page_size?: number + }): Promise> { + return apiClient.get(`/reconciliation/batches/${batchId}/items`, { params }) } - // 三账校验 + /** + * 三账校验 + * 对应后端: GET /api/v1/reconciliation/three-account/:account_id + */ static async verifyThreeAccounts(accountId: number): Promise { return apiClient.get(`/reconciliation/three-account/${accountId}`) } - // 手工调整 - static async createAdjustment(data: { - batchId: number - transactionId?: number - adjustmentType: string - amount: number - reason: string - operator: string - }): Promise { + /** + * 创建手工补录 + * 对应后端: POST /api/v1/reconciliation/adjustments + */ + static async createAdjustment(data: CreateAdjustmentRequest): Promise { return apiClient.post('/reconciliation/adjustments', data) } + + /** + * 审批补录 + * 对应后端: POST /api/v1/reconciliation/adjustments/:id/approve + */ + static async approveAdjustment(id: number, approver: string): Promise { + return apiClient.post(`/reconciliation/adjustments/${id}/approve`, { approver }) + } + + /** + * 拒绝补录 + * 对应后端: POST /api/v1/reconciliation/adjustments/:id/reject + */ + static async rejectAdjustment(id: number, approver: string, reason: string): Promise { + return apiClient.post(`/reconciliation/adjustments/${id}/reject`, { approver, reason }) + } + + /** + * 获取待审批补录列表 + * 对应后端: GET /api/v1/reconciliation/adjustments/pending + */ + static async getPendingAdjustments(): Promise { + return apiClient.get('/reconciliation/adjustments/pending') + } + + // ==================== 扩展功能 (需要后端支持) ==================== + + /** + * 获取对账批次列表 (需要后端扩展) + * @todo 后端需要添加列表查询端点 + */ + static async getBatches(params?: { + status?: ReconciliationStatus + physical_account_id?: number + start_date?: string + end_date?: string + page?: number + page_size?: number + }): Promise> { + return apiClient.get('/reconciliation/batches', { params }) + } - // 获取调整记录 - static async getAdjustments(batchId: number): Promise { + /** + * 获取批次的调整记录 (需要后端扩展) + * @todo 后端需要添加此端点 + */ + static async getAdjustments(batchId: number): Promise { return apiClient.get(`/reconciliation/batches/${batchId}/adjustments`) } - // 对账统计 + /** + * 对账统计 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async getStats(params: { - startDate?: string - endDate?: string - accountId?: number + start_date?: string + end_date?: string + physical_account_id?: number }): Promise<{ - totalBatches: number - successRate: number - totalDiscrepancy: number - largestDiscrepancy: number + total_batches: number + success_rate: number + total_discrepancy: string + largest_discrepancy: string }> { - return apiClient.get('/reconciliation/stats', params) + return apiClient.get('/reconciliation/stats', { params }) } - // 导出对账报告 + /** + * 导出对账报告 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async exportReport(batchId: number, format: 'excel' | 'pdf' = 'excel'): Promise { - return apiClient.get(`/reconciliation/batches/${batchId}/export`, - { format }, - { responseType: 'blob' } - ) + return apiClient.get(`/reconciliation/batches/${batchId}/export`, { + params: { format }, + responseType: 'blob' + }) + } + + // ==================== 兼容旧方法 ==================== + + /** + * @deprecated 使用 runReconciliation 替代 + */ + static async createBatch(data: { + reconDate: string + accountIds?: number[] + }): Promise { + return this.runReconciliation({ + physical_account_id: data.accountIds?.[0] || 0, + recon_date: data.reconDate, + }) + } + + /** + * @deprecated 使用 runReconciliation 替代 + */ + static async executeBatch(id: number): Promise { + // 获取批次信息后重新执行对账 + const batch = await this.getBatch(id) + return this.runReconciliation({ + physical_account_id: batch.physical_account_id, + recon_date: batch.recon_date, + }) } } + +/** + * 对账状态显示名称映射 + */ +export const ReconciliationStatusLabels: Record = { + processing: '处理中', + completed: '已完成', + need_review: '需要审核', +} + +/** + * 对账项状态显示名称映射 + */ +export const ReconciliationItemStatusLabels: Record = { + matched: '已匹配', + system_unreached: '系统未达', + bank_unreached: '银行未达', + amount_mismatch: '金额不匹配', + adjusted: '已调整', +} + +/** + * 补录类型显示名称映射 + */ +export const AdjustmentTypeLabels: Record = { + add: '补录', + reverse: '冲销', + modify: '修改', +} + +/** + * 补录状态显示名称映射 + */ +export const AdjustmentStatusLabels: Record = { + pending: '待审批', + approved: '已审批', + rejected: '已拒绝', +} + +export default ReconciliationAPI diff --git a/src/api/transaction.ts b/src/api/transaction.ts index b6de233..6916b49 100644 --- a/src/api/transaction.ts +++ b/src/api/transaction.ts @@ -1,4 +1,7 @@ -// 交易相关API服务 +/** + * 交易 API 客户端 + * 提供转账、充值、提现等交易功能 + */ import { apiClient } from './client' import type { SystemTransaction, @@ -9,54 +12,166 @@ import type { TransferRequest, TransferResponse } from '@/types/transaction' +import type { PageResponse } from '@/types/api' + +/** + * 充值请求 + */ +export interface DepositRequest { + account_id: number + amount: string + source_key?: string + remark?: string +} + +/** + * 提现请求 + */ +export interface WithdrawRequest { + account_id: number + amount: string + remark?: string +} export class TransactionAPI { - // 获取交易详情 + // ==================== 核心交易操作 ==================== + + /** + * 发起转账 + * 对应后端: POST /api/v1/transactions/transfer + */ + static async transfer(data: TransferRequest): Promise { + return apiClient.post('/transactions/transfer', data) + } + + /** + * 发起充值 (入金) + * 对应后端: POST /api/v1/transactions/deposit + */ + static async deposit(data: DepositRequest): Promise { + return apiClient.post('/transactions/deposit', data) + } + + /** + * 发起提现 (出金) + * 对应后端: POST /api/v1/transactions/withdraw + */ + static async withdraw(data: WithdrawRequest): Promise { + return apiClient.post('/transactions/withdraw', data) + } + + // ==================== 交易查询 ==================== + + /** + * 获取交易详情 + * 对应后端: GET /api/v1/transactions/:id + */ static async getTransaction(id: number): Promise { return apiClient.get(`/transactions/${id}`) } - // 根据交易号获取交易 - static async getTransactionByNo(txnNo: string): Promise { - return apiClient.get(`/transactions/by-no/${txnNo}`) + /** + * 获取交易列表 + * 对应后端: GET /api/v1/transactions + */ + static async getTransactions(query: TransactionQuery = {}): Promise> { + return apiClient.get('/transactions', { params: query }) } - - // 获取交易列表 + + // ==================== 兼容旧方法 (保持向后兼容) ==================== + + /** + * @deprecated 使用 getTransactions 替代 + */ static async getTransactionList(query: TransactionQuery = {}): Promise { - return apiClient.get('/transactions', query) + return apiClient.get('/transactions', { params: query }) } - // 创建交易 + /** + * 根据交易号获取交易 (需要后端支持) + * 注意: 当前后端未提供此端点,需要使用 getTransactions + filter + */ + static async getTransactionByNo(txnNo: string): Promise { + const result = await this.getTransactions({ txn_no: txnNo }) + if (result.data && result.data.length > 0) { + return result.data[0] + } + throw new Error('交易不存在') + } + + // ==================== 扩展功能 (需要后端支持) ==================== + + /** + * 创建交易 (通用) + * 注意: 建议使用具体的 transfer/deposit/withdraw 方法 + */ static async createTransaction(data: CreateTransactionRequest): Promise { - return apiClient.post('/transactions', data) + // 根据交易类型调用对应的方法 + switch (data.txn_type) { + case 'transfer': + return this.transfer({ + from_account_id: data.from_account_id!, + to_account_id: data.to_account_id!, + amount: data.amount, + remark: data.remark, + }) + case 'deposit': + return this.deposit({ + account_id: data.to_account_id!, + amount: data.amount, + remark: data.remark, + }) + case 'withdrawal': + return this.withdraw({ + account_id: data.from_account_id!, + amount: data.amount, + remark: data.remark, + }) + default: + throw new Error(`不支持的交易类型: ${data.txn_type}`) + } } - // 提交交易到银行 + /** + * 提交交易到银行 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async submitToBank(id: number): Promise<{ bankRefNo: string }> { return apiClient.post(`/transactions/${id}/submit`) } - // 取消交易 + /** + * 取消交易 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async cancelTransaction(id: number): Promise { return apiClient.post(`/transactions/${id}/cancel`) } - // 重试交易 + /** + * 重试交易 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async retryTransaction(id: number): Promise { return apiClient.post(`/transactions/${id}/retry`) } - // 获取交易状态 + /** + * 获取交易状态 (需要后端扩展) + * 注意: 可以通过 getTransaction 获取完整信息 + */ static async getTransactionStatus(id: number): Promise<{ status: string, bankRefNo?: string }> { - return apiClient.get(`/transactions/${id}/status`) + const txn = await this.getTransaction(id) + return { + status: txn.status, + bankRefNo: txn.bank_ref_no, + } } - // 转账操作 - static async transfer(data: TransferRequest): Promise { - return apiClient.post('/transfer', data) - } - - // 查询银行流水 + /** + * 查询银行流水 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async getBankStatements(params: { accountNo: string startDate: string @@ -67,10 +182,13 @@ export class TransactionAPI { items: BankTransaction[] total: number }> { - return apiClient.get('/bank/statements', params) + return apiClient.get('/bank/statements', { params }) } - // 查询交易统计 + /** + * 查询交易统计 (需要后端扩展) + * @todo 后端需要添加此端点 + */ static async getTransactionStats(params: { accountId?: number startDate?: string @@ -82,22 +200,28 @@ export class TransactionAPI { failedCount: number pendingCount: number }> { - return apiClient.get('/transactions/stats', params) + return apiClient.get('/transactions/stats', { params }) } - // 获取交易历史(分页) + /** + * 获取账户交易历史(分页) + * 使用 getTransactions + from_account_id 筛选 + */ static async getTransactionHistory(params: { accountId: number page?: number pageSize?: number startDate?: string endDate?: string - }): Promise<{ - items: SystemTransaction[] - total: number - page: number - pageSize: number - }> { - return apiClient.get(`/accounts/${params.accountId}/transactions`, params) + }): Promise> { + return this.getTransactions({ + from_account_id: params.accountId, + page: params.page, + page_size: params.pageSize, + start_date: params.startDate, + end_date: params.endDate, + }) } } + +export default TransactionAPI