zhangjf 8490b7a2c6 fix: 全面修复网关路由与前端API路径一致性问题
问题分析:
1. 后端Controller路径不一致:
   - fund-cust: /api/v1/customer (不是/api/v1/cust/customer)
   - fund-proj: /api/v1/project (不是/api/v1/proj/project)
   - fund-sys: /api/v1/auth 和 /api/v1/sys/* 两种路径

2. 之前的错误修改导致路径不匹配

解决方案:
- 网关: StripPrefix=1 + PrefixPath=/api/v1
- 前端: baseURL=/fund,路径直接对应后端路径

网关路由配置:
- fund-sys: /fund/auth/**,/fund/sys/** -> /api/v1/auth/*,/api/v1/sys/*
- fund-cust: /fund/customer/** -> /api/v1/customer/*
- fund-proj: /fund/project/**,/fund/requirement/** -> /api/v1/project/*,/api/v1/requirement/*
- fund-exp: /fund/exp/** -> /api/v1/exp/*
- fund-receipt: /fund/receipt/** -> /api/v1/receipt/*
- fund-report: /fund/report/** -> /api/v1/report/*
- fund-file: /fund/file/** -> /api/v1/file/*

前端API路径规范:
- 认证: /auth/login -> /api/v1/auth/login
- 用户: /sys/user/page -> /api/v1/sys/user/page
- 客户: /customer/page -> /api/v1/customer/page
- 项目: /project/page -> /api/v1/project/page
- 支出: /exp/expense/page -> /api/v1/exp/expense/page
- 收款: /receipt/receivable/page -> /api/v1/receipt/receivable/page
- 报表: /report/stats -> /api/v1/report/stats
- 文件: /file/upload -> /api/v1/file/upload

修改文件:
- fund-gateway/application.yml: 路由配置调整
- TenantGatewayFilter.java: 白名单路径修正
- TokenAuthFilter.java: 白名单路径修正
- fund-admin/src/api/*.ts: 所有API路径修正
- fund-mobile/src/api/index.ts: 所有API路径修正
- FileUpload组件: 上传路径修正
2026-02-22 23:06:54 +08:00

103 lines
2.8 KiB
TypeScript

import request from './request'
// 报表统计API
export interface DashboardStats {
unpaidReceivable: number
pendingExpense: number
todayIncome: number
todayExpense: number
pendingApprovalCount: number
overdueReceivableCount: number
}
export interface TrendItem {
date: string
income: number
expense: number
}
export interface DistributionItem {
name: string
count: number
value: number | string
}
// 项目收支分析DTO
export interface ProjectFinance {
projectId: number
projectCode: string
projectName: string
customerName: string
status: string
receivableAmount: number
receivedAmount: number
unreceivedAmount: number
receiveRate: number
expenseAmount: number
profit: number
profitRate: number
}
// 获取仪表盘统计数据
export function getDashboardStats() {
return request.get<DashboardStats>('/report/dashboard/stats')
}
// 获取收支趋势
export function getTrend(period: 'week' | 'month' | 'quarter' = 'week') {
return request.get<TrendItem[]>('/report/trend', { params: { period } })
}
// 获取项目状态分布
export function getProjectStatusDistribution() {
return request.get<DistributionItem[]>('/report/project/status-distribution')
}
// 获取支出类型分布
export function getExpenseTypeDistribution() {
return request.get<DistributionItem[]>('/report/expense/type-distribution')
}
// 获取项目收支分析
export function getProjectFinance(params?: { status?: string; customerId?: number }) {
return request.get<ProjectFinance[]>('/report/project/finance', { params })
}
// 导出项目收支分析Excel
export function exportProjectFinance(params?: { status?: string; customerId?: number }) {
const baseUrl = import.meta.env.VITE_API_URL || ''
const token = localStorage.getItem('token')
const tenantId = localStorage.getItem('tenantId') || '1'
// 构建查询参数
const queryParams = new URLSearchParams()
if (params?.status) queryParams.append('status', params.status)
if (params?.customerId) queryParams.append('customerId', String(params.customerId))
const queryString = queryParams.toString()
const url = `${baseUrl}/report/project/finance/export${queryString ? '?' + queryString : ''}`
// 使用fetch下载
return fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
'X-Tenant-Id': tenantId
}
}).then(response => {
if (!response.ok) throw new Error('导出失败')
// 获取文件名
const contentDisposition = response.headers.get('Content-Disposition')
let filename = '项目收支分析报表.xlsx'
if (contentDisposition) {
const match = contentDisposition.match(/filename\*=utf-8''(.+)/i)
if (match && match[1]) {
filename = decodeURIComponent(match[1])
}
}
return response.blob().then(blob => ({ blob, filename }))
})
}