kae c08a9a4854 feat: implement create stock check and adjust modals
Both pages had toolbar buttons with no onClick handler. Added modal forms:
- Checks: date + checker + optional detail rows (product + actual qty)
- Adjusts: date + reason + required detail rows (product + adjust qty, negative to decrease)

Also updated createStockCheck and createStockAdjust API function signatures
from Partial<StockCheck/Adjust> to explicit typed request shapes.

Fixed a go-zero validation bug: non-optional fields (checker, adjustReason)
must be present in the JSON body; antd Form returns undefined for untouched
inputs which JSON.stringify omits, causing 400. Solved by setting default
empty strings in Form initialValues.
2026-06-18 18:33:57 +09:00

346 lines
16 KiB
TypeScript

import { request } from '@umijs/max';
import type {
ApiResponse,
BoltInfo,
ColorDetailItem,
CurrentUser,
InventoryLog,
LoginParams,
LoginResult,
Menu,
OperationLog,
PaginatedData,
PaginationParams,
PanInfo,
PanInput,
Product,
ProductSummaryItem,
ProductTree,
PurchaseOrder,
PurchasePayment,
PurchaseReceipt,
PurchaseStatsByProductItem,
PurchaseStatsBySupplierItem,
PurchaseStatsSummary,
Relation,
RelationHistory,
Role,
StockAdjust,
StockCheck,
StockGroup,
StockSummary,
Supplier,
SystemConfig,
User,
} from '@/types/api';
// ── Auth ──────────────────────────────────────────
export const login = (data: LoginParams) =>
request<ApiResponse<LoginResult>>('/api/v1/auth/login', { method: 'POST', data });
export const logout = () =>
request<ApiResponse>('/api/v1/auth/logout', { method: 'POST' });
export const getUserInfo = () =>
request<ApiResponse<CurrentUser>>('/api/v1/auth/info', { method: 'GET' });
export const changePassword = (data: { oldPassword: string; newPassword: string }) =>
request<ApiResponse>('/api/v1/auth/password', { method: 'PUT', data });
// ── Users ─────────────────────────────────────────
export const listUsers = (params: PaginationParams & { username?: string; realName?: string }) =>
request<ApiResponse<PaginatedData<User>>>('/api/v1/system/users', { method: 'GET', params });
export const getUser = (id: string) =>
request<ApiResponse<User>>(`/api/v1/system/users/${id}`, { method: 'GET' });
export const createUser = (data: Partial<User> & { password?: string }) =>
request<ApiResponse>('/api/v1/system/users', { method: 'POST', data });
export const updateUser = (id: string, data: Partial<User>) =>
request<ApiResponse>(`/api/v1/system/users/${id}`, { method: 'PUT', data });
export const deleteUser = (id: string) =>
request<ApiResponse>(`/api/v1/system/users/${id}`, { method: 'DELETE' });
export const updateUserStatus = (id: string, status: number) =>
request<ApiResponse>(`/api/v1/system/users/${id}/status`, { method: 'PUT', data: { status } });
// ── Roles ─────────────────────────────────────────
export const listRoles = (params?: PaginationParams & { roleName?: string }) =>
request<ApiResponse<PaginatedData<Role>>>('/api/v1/system/roles', { method: 'GET', params });
export const createRole = (data: Partial<Role>) =>
request<ApiResponse>('/api/v1/system/roles', { method: 'POST', data });
export const updateRole = (id: string, data: Partial<Role>) =>
request<ApiResponse>(`/api/v1/system/roles/${id}`, { method: 'PUT', data });
export const deleteRole = (id: string) =>
request<ApiResponse>(`/api/v1/system/roles/${id}`, { method: 'DELETE' });
export const setRolePermissions = (id: string, menuIds: string[]) =>
request<ApiResponse>(`/api/v1/system/roles/${id}/permissions`, { method: 'PUT', data: { menuIds } });
// ── Menus ─────────────────────────────────────────
export const listMenus = () =>
request<ApiResponse<PaginatedData<Menu>>>('/api/v1/system/menus', { method: 'GET' });
export const createMenu = (data: Partial<Menu>) =>
request<ApiResponse>('/api/v1/system/menus', { method: 'POST', data });
export const updateMenu = (id: string, data: Partial<Menu>) =>
request<ApiResponse>(`/api/v1/system/menus/${id}`, { method: 'PUT', data });
export const deleteMenu = (id: string) =>
request<ApiResponse>(`/api/v1/system/menus/${id}`, { method: 'DELETE' });
// ── Logs ──────────────────────────────────────────
export const listLogs = (params: PaginationParams & { username?: string; module?: string; operation?: string }) =>
request<ApiResponse<PaginatedData<OperationLog>>>('/api/v1/system/logs', { method: 'GET', params });
// ── Configs ───────────────────────────────────────
export const listConfigs = () =>
request<ApiResponse<PaginatedData<SystemConfig>>>('/api/v1/system/configs', { method: 'GET' });
export const updateConfig = (key: string, value: string) =>
request<ApiResponse>(`/api/v1/system/configs/${key}`, { method: 'PUT', data: { configValue: value } });
// ── Products ──────────────────────────────────────
export const listProducts = (params: PaginationParams & { productName?: string; spec?: string; color?: string }) =>
request<ApiResponse<PaginatedData<Product>>>('/api/v1/inventory/products', { method: 'GET', params });
export const getProduct = (id: string) =>
request<ApiResponse<Product>>(`/api/v1/inventory/products/${id}`, { method: 'GET' });
export const createProduct = (data: Partial<Product> & { pans?: PanInput[] }) =>
request<ApiResponse>('/api/v1/inventory/products', { method: 'POST', data });
export const updateProduct = (id: string, data: Partial<Product>) =>
request<ApiResponse>(`/api/v1/inventory/products/${id}`, { method: 'PUT', data });
export const deleteProduct = (id: string) =>
request<ApiResponse>(`/api/v1/inventory/products/${id}`, { method: 'DELETE' });
export const exportProducts = () =>
request('/api/v1/inventory/products/export', { method: 'GET', responseType: 'blob' });
// ── Product Panels ────────────────────────────────
export const getProductSummary = () =>
request<ApiResponse<{ list: ProductSummaryItem[] }>>('/api/v1/inventory/products/summary', { method: 'GET' });
export const getColorDetail = (productName: string) =>
request<ApiResponse<{ list: ColorDetailItem[] }>>('/api/v1/inventory/products/colors', { method: 'GET', params: { productName } });
export const getProductTree = (id: string) =>
request<ApiResponse<ProductTree>>(`/api/v1/inventory/products/${id}/tree`, { method: 'GET' });
// ── Pan / Bolt CRUD ───────────────────────────────
export const listPans = (productId: string) =>
request<ApiResponse<{ list: PanInfo[] }>>(`/api/v1/inventory/products/${productId}/pans`, { method: 'GET' });
export const savePans = (productId: string, pans: PanInput[]) =>
request<ApiResponse>(`/api/v1/inventory/products/${productId}/pans`, { method: 'PUT', data: { pans } });
export const listBolts = (panId: string) =>
request<ApiResponse<{ list: BoltInfo[] }>>(`/api/v1/inventory/pans/${panId}/bolts`, { method: 'GET' });
export const saveBolts = (panId: string, lengths: string[]) =>
request<ApiResponse>(`/api/v1/inventory/pans/${panId}/bolts`, { method: 'PUT', data: { lengths } });
// ── Pan / Bolt dimension panels ───────────────────
export const listPanView = (params: {
page?: number;
pageSize?: number;
productName?: string;
position?: string;
}) =>
request<ApiResponse<{ total: number; list: import('@/types/api').PanListItem[] }>>(
'/api/v1/inventory/pans',
{ method: 'GET', params },
);
export const listBoltView = (params: {
page?: number;
pageSize?: number;
productName?: string;
position?: string;
}) =>
request<ApiResponse<{ total: number; list: import('@/types/api').BoltListItem[] }>>(
'/api/v1/inventory/bolts',
{ method: 'GET', params },
);
// ── Stocks ────────────────────────────────────────
export const getStockSummary = () =>
request<ApiResponse<StockSummary>>('/api/v1/inventory/stocks/summary', { method: 'GET' });
export const getStockByColor = () =>
request<ApiResponse<PaginatedData<StockGroup>>>('/api/v1/inventory/stocks/by-color', { method: 'GET' });
export const getStockByLocation = () =>
request<ApiResponse<PaginatedData<StockGroup>>>('/api/v1/inventory/stocks/by-location', { method: 'GET' });
// ── Stock Checks ──────────────────────────────────
export const listStockChecks = (params: PaginationParams) =>
request<ApiResponse<PaginatedData<StockCheck>>>('/api/v1/inventory/checks', { method: 'GET', params });
export const getStockCheck = (id: string) =>
request<ApiResponse<StockCheck>>(`/api/v1/inventory/checks/${id}`, { method: 'GET' });
export const createStockCheck = (data: {
checkDate: string;
checker?: string;
remark?: string;
details?: Array<{ productId: string; actualQuantity: string; remark?: string }>;
}) => request<ApiResponse<{ id: string }>>('/api/v1/inventory/checks', { method: 'POST', data });
export const confirmStockCheck = (id: string) =>
request<ApiResponse>(`/api/v1/inventory/checks/${id}/confirm`, { method: 'POST' });
// ── Stock Adjusts ─────────────────────────────────
export const listStockAdjusts = (params: PaginationParams) =>
request<ApiResponse<PaginatedData<StockAdjust>>>('/api/v1/inventory/adjusts', { method: 'GET', params });
export const getStockAdjust = (id: string) =>
request<ApiResponse<StockAdjust>>(`/api/v1/inventory/adjusts/${id}`, { method: 'GET' });
export const createStockAdjust = (data: {
adjustDate: string;
adjustReason?: string;
remark?: string;
details?: Array<{ productId: string; adjustQuantity: string; remark?: string }>;
}) => request<ApiResponse<{ id: string }>>('/api/v1/inventory/adjusts', { method: 'POST', data });
export const approveStockAdjust = (id: string, action: number) =>
request<ApiResponse>(`/api/v1/inventory/adjusts/${id}/approve`, { method: 'POST', data: { action } });
// ── CRM Relations ─────────────────────────────────
export const listUpstream = (depth = 1) =>
request<ApiResponse<PaginatedData<Relation>>>('/api/v1/crm/graph/upstream', { method: 'GET', params: { depth } });
export const listDownstream = (depth = 1) =>
request<ApiResponse<PaginatedData<Relation>>>('/api/v1/crm/graph/downstream', { method: 'GET', params: { depth } });
export const createRelation = (data: {
fromTenantId: string;
toTenantId: string;
relationType: string;
validFrom?: string;
validTo?: string;
}) =>
request<ApiResponse>('/api/v1/crm/relationships', { method: 'POST', data });
export const updateRelation = (id: string, data: { status: number; validFrom?: string; validTo?: string }) =>
request<ApiResponse>(`/api/v1/crm/relationships/${id}`, { method: 'PUT', data });
export const listRelationHistory = (params?: PaginationParams) =>
request<ApiResponse<PaginatedData<RelationHistory>>>('/api/v1/crm/relationships/history', { method: 'GET', params });
// ── Suppliers ─────────────────────────────────────
export const listSuppliers = (params: PaginationParams & { supplierName?: string; status?: number }) =>
request<ApiResponse<PaginatedData<Supplier>>>('/api/v1/purchase/suppliers', { method: 'GET', params });
export const getSupplier = (id: string) =>
request<ApiResponse<Supplier>>(`/api/v1/purchase/suppliers/${id}`, { method: 'GET' });
export const createSupplier = (data: { supplierName: string; phone?: string; remark?: string }) =>
request<ApiResponse<{ id: string }>>('/api/v1/purchase/suppliers', { method: 'POST', data });
export const updateSupplier = (id: string, data: { supplierName?: string; phone?: string; status?: number; remark?: string }) =>
request<ApiResponse>(`/api/v1/purchase/suppliers/${id}`, { method: 'PUT', data });
export const deleteSupplier = (id: string) =>
request<ApiResponse>(`/api/v1/purchase/suppliers/${id}`, { method: 'DELETE' });
// ── Purchase Orders ───────────────────────────────
export const listPurchaseOrders = (params: PaginationParams & { supplierId?: string; status?: number; startDate?: string; endDate?: string }) =>
request<ApiResponse<PaginatedData<PurchaseOrder>>>('/api/v1/purchase/orders', { method: 'GET', params });
export const getPurchaseOrder = (id: string) =>
request<ApiResponse<PurchaseOrder>>(`/api/v1/purchase/orders/${id}`, { method: 'GET' });
export const createPurchaseOrder = (data: {
supplierId: string;
orderDate: string;
purchaseBy?: string;
remark?: string;
details: Array<{ productId: string; productName: string; spec?: string; color?: string; quantity: string; unitPrice: string; remark?: string }>;
}) =>
request<ApiResponse<{ id: string }>>('/api/v1/purchase/orders', { method: 'POST', data });
export const updatePurchaseOrder = (id: string, data: object) =>
request<ApiResponse>(`/api/v1/purchase/orders/${id}`, { method: 'PUT', data });
export const confirmPurchaseOrder = (id: string) =>
request<ApiResponse>(`/api/v1/purchase/orders/${id}/confirm`, { method: 'POST' });
export const cancelPurchaseOrder = (id: string) =>
request<ApiResponse>(`/api/v1/purchase/orders/${id}/cancel`, { method: 'POST' });
// ── Purchase Receipts ─────────────────────────────
export const listPurchaseReceipts = (params: PaginationParams & { orderId?: string; status?: number; startDate?: string; endDate?: string }) =>
request<ApiResponse<PaginatedData<PurchaseReceipt>>>('/api/v1/purchase/receipts', { method: 'GET', params });
export const getPurchaseReceipt = (id: string) =>
request<ApiResponse<PurchaseReceipt>>(`/api/v1/purchase/receipts/${id}`, { method: 'GET' });
export const createPurchaseReceipt = (data: {
orderId: string;
receiptDate: string;
receivedBy?: string;
remark?: string;
details: Array<{ orderDetailId: string; productId: string; actualQty: string; unitCost?: string; remark?: string }>;
}) =>
request<ApiResponse<{ id: string }>>('/api/v1/purchase/receipts', { method: 'POST', data });
export const confirmPurchaseReceipt = (id: string) =>
request<ApiResponse>(`/api/v1/purchase/receipts/${id}/confirm`, { method: 'POST' });
// ── Purchase Payments ─────────────────────────────
export const listPurchasePayments = (params: PaginationParams & { orderId?: string; startDate?: string; endDate?: string }) =>
request<ApiResponse<PaginatedData<PurchasePayment>>>('/api/v1/purchase/payments', { method: 'GET', params });
export const createPurchasePayment = (data: {
orderId: string;
paymentDate: string;
amount: string;
paymentMethod?: string;
remark?: string;
}) =>
request<ApiResponse<{ id: string }>>('/api/v1/purchase/payments', { method: 'POST', data });
// ── Purchase Stats ────────────────────────────────
export const getPurchaseStatsSummary = (params: { startDate?: string; endDate?: string }) =>
request<ApiResponse<PurchaseStatsSummary>>('/api/v1/purchase/stats/summary', { method: 'GET', params });
export const getPurchaseStatsBySupplier = (params: { startDate?: string; endDate?: string }) =>
request<ApiResponse<{ list: PurchaseStatsBySupplierItem[] }>>('/api/v1/purchase/stats/by-supplier', { method: 'GET', params });
export const getPurchaseStatsByProduct = (params: { startDate?: string; endDate?: string }) =>
request<ApiResponse<{ list: PurchaseStatsByProductItem[] }>>('/api/v1/purchase/stats/by-product', { method: 'GET', params });
// ── Inventory Logs ────────────────────────────────
export const listInventoryLogs = (params: PaginationParams & { productId?: string; changeType?: number; startDate?: string; endDate?: string }) =>
request<ApiResponse<PaginatedData<InventoryLog>>>('/api/v1/inventory/logs', { method: 'GET', params });