This commit is contained in:
beabigegg
2025-11-12 22:53:17 +08:00
commit da700721fa
130 changed files with 23393 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
import axios, { AxiosError } from 'axios'
import type { AxiosInstance } from 'axios'
import type {
LoginRequest,
LoginResponse,
UploadResponse,
ProcessRequest,
ProcessResponse,
TaskStatus,
BatchStatus,
OCRResult,
ExportRequest,
ExportRule,
CSSTemplate,
TranslateRequest,
TranslateResponse,
TranslationConfig,
ApiError,
} from '@/types/api'
/**
* API Client Configuration
*/
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:12010'
const API_VERSION = 'v1'
class ApiClient {
private client: AxiosInstance
private token: string | null = null
constructor() {
this.client = axios.create({
baseURL: `${API_BASE_URL}/api/${API_VERSION}`,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
})
// Request interceptor to add auth token
this.client.interceptors.request.use(
(config) => {
if (this.token) {
config.headers.Authorization = `Bearer ${this.token}`
}
return config
},
(error) => Promise.reject(error)
)
// Response interceptor for error handling
this.client.interceptors.response.use(
(response) => response,
(error: AxiosError<ApiError>) => {
if (error.response?.status === 401) {
// Token expired or invalid
this.clearToken()
window.location.href = '/login'
}
return Promise.reject(error)
}
)
// Load token from localStorage
this.loadToken()
}
/**
* Set authentication token
*/
setToken(token: string) {
this.token = token
localStorage.setItem('auth_token', token)
}
/**
* Clear authentication token
*/
clearToken() {
this.token = null
localStorage.removeItem('auth_token')
}
/**
* Load token from localStorage
*/
private loadToken() {
const token = localStorage.getItem('auth_token')
if (token) {
this.token = token
}
}
/**
* Check if user is authenticated
*/
isAuthenticated(): boolean {
return this.token !== null
}
// ==================== Authentication ====================
/**
* Login
*/
async login(data: LoginRequest): Promise<LoginResponse> {
const response = await this.client.post<LoginResponse>('/auth/login', {
username: data.username,
password: data.password,
})
this.setToken(response.data.access_token)
return response.data
}
/**
* Logout
*/
logout() {
this.clearToken()
}
// ==================== File Upload ====================
/**
* Upload files
*/
async uploadFiles(files: File[]): Promise<UploadResponse> {
const formData = new FormData()
files.forEach((file) => {
formData.append('files', file)
})
const response = await this.client.post<UploadResponse>('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
return response.data
}
// ==================== OCR Processing ====================
/**
* Process OCR
*/
async processOCR(data: ProcessRequest): Promise<ProcessResponse> {
const response = await this.client.post<ProcessResponse>('/ocr/process', data)
return response.data
}
/**
* Get task status
*/
async getTaskStatus(taskId: string): Promise<TaskStatus> {
const response = await this.client.get<TaskStatus>(`/ocr/status/${taskId}`)
return response.data
}
/**
* Get OCR result
*/
async getOCRResult(taskId: string): Promise<OCRResult> {
const response = await this.client.get<OCRResult>(`/ocr/result/${taskId}`)
return response.data
}
/**
* Get batch status
*/
async getBatchStatus(batchId: number): Promise<BatchStatus> {
const response = await this.client.get<BatchStatus>(`/batch/${batchId}/status`)
return response.data
}
// ==================== Export ====================
/**
* Export results
*/
async exportResults(data: ExportRequest): Promise<Blob> {
const response = await this.client.post('/export', data, {
responseType: 'blob',
})
return response.data
}
/**
* Generate and download PDF
*/
async exportPDF(fileId: number, cssTemplate?: string): Promise<Blob> {
const params = cssTemplate ? { css_template: cssTemplate } : {}
const response = await this.client.get(`/export/pdf/${fileId}`, {
params,
responseType: 'blob',
})
return response.data
}
/**
* Get export rules
*/
async getExportRules(): Promise<ExportRule[]> {
const response = await this.client.get<ExportRule[]>('/export/rules')
return response.data
}
/**
* Create export rule
*/
async createExportRule(rule: Omit<ExportRule, 'id' | 'created_at'>): Promise<ExportRule> {
const response = await this.client.post<ExportRule>('/export/rules', rule)
return response.data
}
/**
* Update export rule
*/
async updateExportRule(ruleId: number, rule: Partial<ExportRule>): Promise<ExportRule> {
const response = await this.client.put<ExportRule>(`/export/rules/${ruleId}`, rule)
return response.data
}
/**
* Delete export rule
*/
async deleteExportRule(ruleId: number): Promise<void> {
await this.client.delete(`/export/rules/${ruleId}`)
}
/**
* Get CSS templates
*/
async getCSSTemplates(): Promise<CSSTemplate[]> {
const response = await this.client.get<CSSTemplate[]>('/export/css-templates')
return response.data
}
// ==================== Translation (FUTURE FEATURE - STUB) ====================
/**
* Translate document (STUB - Not yet implemented)
* This is a placeholder for future translation functionality
* @throws Will throw error with status 501 (Not Implemented)
*/
async translateDocument(data: TranslateRequest): Promise<TranslateResponse> {
// This endpoint is expected to return 501 Not Implemented until Phase 5
const response = await this.client.post<TranslateResponse>('/translate/document', data)
return response.data
}
/**
* Get translation configs (STUB - Not yet implemented)
* This is a placeholder for future translation functionality
* @throws Will throw error with status 501 (Not Implemented)
*/
async getTranslationConfigs(): Promise<TranslationConfig[]> {
// This endpoint is expected to return 501 Not Implemented until Phase 5
const response = await this.client.get<TranslationConfig[]>('/translate/configs')
return response.data
}
/**
* Create translation config (STUB - Not yet implemented)
* This is a placeholder for future translation functionality
* @throws Will throw error with status 501 (Not Implemented)
*/
async createTranslationConfig(
config: Omit<TranslationConfig, 'id' | 'created_at'>
): Promise<TranslationConfig> {
// This endpoint is expected to return 501 Not Implemented until Phase 5
const response = await this.client.post<TranslationConfig>('/translate/configs', config)
return response.data
}
}
// Export singleton instance
export const apiClient = new ApiClient()