Files
geMoldInsight/frontend/src/shared/api-client.ts
T
2026-08-31 18:01:34 +08:00

411 lines
13 KiB
TypeScript

/**
* Typed domain API client — wraps `apiRequest` with OpenAPI-generated types.
*
* Usage:
* import { inventoryApi } from '@/shared/api-client'
* const products = await inventoryApi.listProducts({ item_type: 'finished' })
* // products is typed as Schema<'ProductResponse'>[]
*/
import { apiRequest } from './api'
import type { Schema } from '@/types/schemas'
// ── Auth ───────────────────────────────────────────────────────
export const authApi = {
login(username: string, password: string) {
const body = new URLSearchParams({ username, password })
return apiRequest<Schema<'Token'>>('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString(),
})
},
loginJson(username: string, password: string) {
return apiRequest<Schema<'Token'>>('/api/auth/login/json', {
method: 'POST',
body: JSON.stringify({ username, password } satisfies Schema<'LoginRequest'>),
})
},
me() {
return apiRequest<Schema<'UserResponse'>>('/api/auth/me')
},
logout() {
return apiRequest('/api/auth/logout', { method: 'POST' })
},
// Users
listUsers() {
return apiRequest<Schema<'UserResponse'>[]>('/api/auth/users')
},
createUser(data: Schema<'UserCreate'>) {
return apiRequest<Schema<'UserResponse'>>('/api/auth/users', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateUser(userId: number, data: Schema<'UserUpdate'>) {
return apiRequest<Schema<'UserResponse'>>(`/api/auth/users/${userId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteUser(userId: number) {
return apiRequest(`/api/auth/users/${userId}`, { method: 'DELETE' })
},
resetPassword(userId: number, newPassword: string) {
return apiRequest(`/api/auth/users/${userId}/reset-password`, {
method: 'PUT',
body: JSON.stringify({ new_password: newPassword }),
})
},
// Roles
listRoles() {
return apiRequest<Schema<'RoleResponse'>[]>('/api/auth/roles')
},
createRole(data: Schema<'RoleCreate'>) {
return apiRequest<Schema<'RoleResponse'>>('/api/auth/roles', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateRole(roleId: number, data: Schema<'RoleCreate'>) {
return apiRequest<Schema<'RoleResponse'>>(`/api/auth/roles/${roleId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteRole(roleId: number) {
return apiRequest(`/api/auth/roles/${roleId}`, { method: 'DELETE' })
},
setRolePermissions(roleId: number, permissionIds: number[]) {
return apiRequest(`/api/auth/roles/${roleId}/permissions`, {
method: 'PUT',
body: JSON.stringify({ permission_ids: permissionIds }),
})
},
// Permissions
listPermissions() {
return apiRequest<Schema<'PermissionResponse'>[]>('/api/auth/permissions')
},
}
// ── Inventory / ERP ────────────────────────────────────────────
export const inventoryApi = {
// Dashboard
dashboard() {
return apiRequest('/api/dashboard')
},
// Products
listProducts(params?: { item_type?: string; limit?: number }) {
const q = new URLSearchParams()
if (params?.item_type) q.set('item_type', params.item_type)
if (params?.limit) q.set('limit', String(params.limit))
const qs = q.toString()
return apiRequest<Schema<'ProductResponse'>[]>(`/api/products${qs ? `?${qs}` : ''}`)
},
createProduct(data: Schema<'ProductCreate'>) {
return apiRequest<Schema<'ProductResponse'>>('/api/products', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateProduct(id: number, data: Partial<Schema<'ProductCreate'>>) {
return apiRequest<Schema<'ProductResponse'>>(`/api/products/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteProduct(id: number) {
return apiRequest(`/api/products/${id}`, { method: 'DELETE' })
},
getProductMaterials(productId: number) {
return apiRequest<{ items: Schema<'ProductMaterialItemResponse'>[] }>(`/api/products/${productId}/materials`)
},
// from-task (mold analysis → product)
createProductFromTask(taskId: string) {
return apiRequest<Schema<'ProductResponse'>>(`/api/products/from-task/${taskId}`, {
method: 'POST',
})
},
// Warehouses
listWarehouses() {
return apiRequest<Schema<'WarehouseResponse'>[]>('/api/warehouses')
},
createWarehouse(data: Schema<'WarehouseCreate'>) {
return apiRequest<Schema<'WarehouseResponse'>>('/api/warehouses', {
method: 'POST',
body: JSON.stringify(data),
})
},
// Inventory
listInventory() {
return apiRequest<{ items: Schema<'InventoryResponse'>[] }>('/api/inventory')
},
// Stock Movements
listStockMovements(params?: { limit?: number }) {
const q = params?.limit ? `?limit=${params.limit}` : ''
return apiRequest<{ items: Schema<'StockMovementResponse'>[] }>(`/api/stock-movements${q}`)
},
// Suppliers
listSuppliers() {
return apiRequest<Schema<'SupplierResponse'>[]>('/api/suppliers')
},
createSupplier(data: Schema<'SupplierCreate'>) {
return apiRequest<Schema<'SupplierResponse'>>('/api/suppliers', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateSupplier(id: number, data: Partial<Schema<'SupplierCreate'>>) {
return apiRequest<Schema<'SupplierResponse'>>(`/api/suppliers/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteSupplier(id: number) {
return apiRequest(`/api/suppliers/${id}`, { method: 'DELETE' })
},
// Customers
listCustomers() {
return apiRequest<Schema<'CustomerResponse'>[]>('/api/customers')
},
createCustomer(data: Schema<'CustomerCreate'>) {
return apiRequest<Schema<'CustomerResponse'>>('/api/customers', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateCustomer(id: number, data: Partial<Schema<'CustomerCreate'>>) {
return apiRequest<Schema<'CustomerResponse'>>(`/api/customers/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteCustomer(id: number) {
return apiRequest(`/api/customers/${id}`, { method: 'DELETE' })
},
// Purchase Orders
listPurchaseOrders(params?: { limit?: number }) {
const q = params?.limit ? `?limit=${params.limit}` : ''
return apiRequest<{ items: Schema<'PurchaseOrderResponse'>[] }>(`/api/purchase-orders${q}`)
},
createPurchaseOrder(data: Schema<'PurchaseOrderCreate'>) {
return apiRequest<Schema<'PurchaseOrderResponse'>>('/api/purchase-orders', {
method: 'POST',
body: JSON.stringify(data),
})
},
updatePurchaseOrder(id: number, data: Partial<Schema<'PurchaseOrderCreate'>>) {
return apiRequest<Schema<'PurchaseOrderResponse'>>(`/api/purchase-orders/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
receivePurchaseOrder(id: number, data: Schema<'PurchaseOrderReceiveRequest'>) {
return apiRequest<Schema<'PurchaseOrderResponse'>>(`/api/purchase-orders/${id}/receive`, {
method: 'POST',
body: JSON.stringify(data),
})
},
updatePurchaseOrderStatus(id: number, status: string) {
return apiRequest<Schema<'PurchaseOrderResponse'>>(`/api/purchase-orders/${id}/status`, {
method: 'PATCH',
body: JSON.stringify({ status }),
})
},
// Sales Orders
listSalesOrders(params?: { limit?: number }) {
const q = params?.limit ? `?limit=${params.limit}` : ''
return apiRequest<{ items: Schema<'SalesOrderResponse'>[] }>(`/api/sales-orders${q}`)
},
getSalesOrder(id: number) {
return apiRequest<Schema<'SalesOrderDetailResponse'>>(`/api/sales-orders/${id}`)
},
createSalesOrder(data: Schema<'SalesOrderCreate'>) {
return apiRequest<Schema<'SalesOrderResponse'>>('/api/sales-orders', {
method: 'POST',
body: JSON.stringify(data),
})
},
updateSalesOrder(id: number, data: Partial<Schema<'SalesOrderCreate'>>) {
return apiRequest<Schema<'SalesOrderResponse'>>(`/api/sales-orders/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
})
},
deleteSalesOrder(id: number) {
return apiRequest(`/api/sales-orders/${id}`, { method: 'DELETE' })
},
// Purchase Demands (采购需求推导)
calculatePurchaseDemands(salesOrderIds: number[]) {
return apiRequest<Schema<'PurchaseDemandResponse'>>('/api/purchase-demands/calculate', {
method: 'POST',
body: JSON.stringify({ sales_order_ids: salesOrderIds } satisfies Schema<'PurchaseDemandCalculateRequest'>),
})
},
// Finance
financeSummary(params?: { year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<Schema<'FinanceSummaryResponse'>>(`/api/finance/summary?${q}`)
},
financeTransactions(params?: { status?: string; limit?: number; year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.status) q.set('status', params.status)
if (params?.limit) q.set('limit', String(params.limit))
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<{ items: Schema<'FinanceTransactionResponse'>[] }>(`/api/finance/transactions?${q}`)
},
financeReceivables(params?: { limit?: number; year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.limit) q.set('limit', String(params.limit))
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<Schema<'ReceivableItemResponse'>[]>(`/api/finance/receivables?${q}`)
},
financePayables(params?: { limit?: number; year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.limit) q.set('limit', String(params.limit))
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<Schema<'PayableItemResponse'>[]>(`/api/finance/payables?${q}`)
},
financePartnerStatement(partnerType: 'customer' | 'supplier', params?: { year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<Schema<'FinancePartnerStatementResponse'>>(`/api/finance/partner-statement/${partnerType}?${q}`)
},
financePartnerProductStatement(partnerType: 'customer' | 'supplier', params?: { year?: number; quarter?: number }) {
const q = new URLSearchParams()
if (params?.year) q.set('year', String(params.year))
if (params?.quarter) q.set('quarter', String(params.quarter))
return apiRequest<Schema<'FinancePartnerProductStatementResponse'>>(`/api/finance/partner-product-statement/${partnerType}?${q}`)
},
}
// ── MoldInsight ────────────────────────────────────────────────
export const moldinsightApi = {
uploadStp(formData: FormData) {
return apiRequest<{ task_id: string }>('/api/upload', {
method: 'POST',
body: formData,
})
},
getStatus(taskId: string) {
return apiRequest<{
task_id: string
status: string
progress: number
result?: Record<string, unknown>
error?: string
}>(`/api/status/${taskId}`)
},
batchUpload(formData: FormData) {
return apiRequest<{
batch_id: string
accepted: number
rejected: number
task_ids: string[]
}>('/api/batch-upload', {
method: 'POST',
body: formData,
})
},
getBatchStatus(batchId: string) {
return apiRequest<{
batch_id: string
total: number
completed: number
failed: number
processing: number
progress_percent: number
tasks: Array<{
task_id: string
filename: string
status: string
progress?: number
error?: string
html_file?: string
}>
}>(`/api/batch/${batchId}`)
},
estimateCost(data: {
task_id?: string
material?: string
mold_type?: string
cavity_count?: number
weight?: number
dimensions?: { length: number; width: number; height: number }
}) {
return apiRequest<{
mold_cost?: number
part_cost?: number
total_mold_cost?: number
confidence?: number
assumptions?: string[]
currency?: string
}>('/api/cost-estimate', {
method: 'POST',
body: JSON.stringify(data),
})
},
getAluminumPrice() {
return apiRequest<{ price: number; unit: string; updated_at: string }>('/api/aluminum-price/current')
},
}