411 lines
13 KiB
TypeScript
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')
|
|
},
|
|
}
|