'use client' import { useState, useEffect } from 'react' import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Plus, Minus, Package, Trash2, Search, BarChart, Download, Upload, Edit2, Save, Warehouse, TrendingUp, Users, ShoppingCart } from 'lucide-react' import { motion } from "framer-motion" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { BarChart as RechartsBarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts' import { format } from 'date-fns' interface InventoryItem { id: number; name: string; quantity: number; warehouse: string; unitPrice: number; supplier: string; } interface Supplier { id: number; name: string; } interface Product { id: number; name: string; } interface OutboundRecord { id: number; productId: number; productName: string; quantity: number; recipient: string; date: string; warehouse: string; supplier: string; } const fadeIn = { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.5 } } export default function InventoryManagement() { const [inventory, setInventory] = useState([]) const [newItemName, setNewItemName] = useState("") const [newItemQuantity, setNewItemQuantity] = useState("") const [newItemWarehouse, setNewItemWarehouse] = useState("") const [newItemUnitPrice, setNewItemUnitPrice] = useState("") const [newItemSupplier, setNewItemSupplier] = useState("") const [searchTerm, setSearchTerm] = useState("") const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false) const [itemToDelete, setItemToDelete] = useState(null) const [editingItemId, setEditingItemId] = useState(null) const [editingItemName, setEditingItemName] = useState("") const [warehouses, setWarehouses] = useState([]) const [activeTab, setActiveTab] = useState("inventory") const [suppliers, setSuppliers] = useState([]) const [products, setProducts] = useState([]) const [outboundRecords, setOutboundRecords] = useState([]) const [sortConfig, setSortConfig] = useState<{ key: keyof InventoryItem | 'totalValue'; direction: 'ascending' | 'descending' } | null>(null) // Load data from localStorage on component mount useEffect(() => { const savedInventory = localStorage.getItem('inventory') const savedWarehouses = localStorage.getItem('warehouses') const savedSuppliers = localStorage.getItem('suppliers') const savedProducts = localStorage.getItem('products') const savedOutboundRecords = localStorage.getItem('outboundRecords') if (savedInventory) setInventory(JSON.parse(savedInventory)) if (savedWarehouses) setWarehouses(JSON.parse(savedWarehouses)) if (savedSuppliers) setSuppliers(JSON.parse(savedSuppliers)) if (savedProducts) setProducts(JSON.parse(savedProducts)) if (savedOutboundRecords) setOutboundRecords(JSON.parse(savedOutboundRecords)) }, []) // Save data to localStorage when it changes useEffect(() => { localStorage.setItem('inventory', JSON.stringify(inventory)) localStorage.setItem('warehouses', JSON.stringify(warehouses)) localStorage.setItem('suppliers', JSON.stringify(suppliers)) localStorage.setItem('products', JSON.stringify(products)) localStorage.setItem('outboundRecords', JSON.stringify(outboundRecords)) }, [inventory, warehouses, suppliers, products, outboundRecords]) const addItem = () => { if (newItemName && newItemQuantity && newItemWarehouse && newItemUnitPrice && newItemSupplier) { const newItem: InventoryItem = { id: Date.now(), name: newItemName, quantity: parseInt(newItemQuantity), warehouse: newItemWarehouse, unitPrice: parseFloat(newItemUnitPrice), supplier: newItemSupplier, } setInventory([...inventory, newItem]) setNewItemName("") setNewItemQuantity("") setNewItemWarehouse("") setNewItemUnitPrice("") setNewItemSupplier("") } } const updateQuantity = (id: number, change: number) => { setInventory(inventory.map(item => { if (item.id === id) { const newQuantity = Math.max(0, item.quantity + change) return { ...item, quantity: newQuantity } } return item })) } const confirmDelete = (id: number) => { setItemToDelete(id) setDeleteConfirmOpen(true) } const deleteItem = () => { if (itemToDelete !== null) { setInventory(inventory.filter(item => item.id !== itemToDelete)) setDeleteConfirmOpen(false) setItemToDelete(null) } } const startEditing = (id: number, name: string) => { setEditingItemId(id) setEditingItemName(name) } const saveEdit = () => { if (editingItemId !== null) { setInventory(inventory.map(item => { if (item.id === editingItemId) { return { ...item, name: editingItemName } } return item })) setEditingItemId(null) setEditingItemName("") } } const filteredInventory = inventory.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase()) || item.warehouse.toLowerCase().includes(searchTerm.toLowerCase()) || item.supplier.toLowerCase().includes(searchTerm.toLowerCase()) ) const sortedInventory = sortConfig !== null ? [...filteredInventory].sort((a, b) => { if (sortConfig.key === 'totalValue') { const aTotal = a.quantity * a.unitPrice; const bTotal = b.quantity * b.unitPrice; return sortConfig.direction === 'ascending' ? aTotal - bTotal : bTotal - aTotal; } if (a[sortConfig.key] < b[sortConfig.key]) { return sortConfig.direction === 'ascending' ? -1 : 1; } if (a[sortConfig.key] > b[sortConfig.key]) { return sortConfig.direction === 'ascending' ? 1 : -1; } return 0; }) : filteredInventory; const requestSort = (key: keyof InventoryItem | 'totalValue') => { let direction: 'ascending' | 'descending' = 'ascending'; if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') { direction = 'descending'; } setSortConfig({ key, direction }); } const exportData = () => { const dataStr = JSON.stringify({ inventory, warehouses, suppliers, products, outboundRecords }) const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr) const exportFileDefaultName = 'inventory_backup.json' const linkElement = document.createElement('a') linkElement.setAttribute('href', dataUri) linkElement.setAttribute('download', exportFileDefaultName) linkElement.click() } const importData = (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (file) { const reader = new FileReader() reader.onload = (e) => { try { const importedData = JSON.parse(e.target?.result as string) setInventory(importedData.inventory) setWarehouses(importedData.warehouses) setSuppliers(importedData.suppliers) setProducts(importedData.products) setOutboundRecords(importedData.outboundRecords) } catch (error) { console.error('Error parsing imported data:', error) alert('导入失败,请确保文件格式正确。') } } reader.readAsText(file) } } const getInventoryChartData = () => { return inventory.map(item => ({ name: item.name, quantity: item.quantity, totalValue: item.quantity * item.unitPrice })) } const addOutboundRecord = (productId: number, productName: string, quantity: number, recipient: string, warehouse: string, supplier: string) => { const newRecord: OutboundRecord = { id: Date.now(), productId, productName, quantity, recipient, date: new Date().toISOString(), warehouse, supplier } setOutboundRecords(prevRecords => [...prevRecords, newRecord]) // 更新库存 setInventory(prevInventory => prevInventory.map(item => item.id === productId ? { ...item, quantity: Math.max(0, item.quantity - quantity) } : item ) ) } const updateWarehouseName = (oldName: string, newName: string) => { setInventory(prevInventory => prevInventory.map(item => item.warehouse === oldName ? { ...item, warehouse: newName } : item ) ) setOutboundRecords(prevRecords => prevRecords.map(record => record.warehouse === oldName ? { ...record, warehouse: newName } : record ) ) } const updateSupplierName = (oldName: string, newName: string) => { setInventory(prevInventory => prevInventory.map(item => item.supplier === oldName ? { ...item, supplier: newName } : item ) ) setOutboundRecords(prevRecords => prevRecords.map(record => record.supplier === oldName ? { ...record, supplier: newName } : record ) ) } const updateProductName = (oldName: string, newName: string) => { setInventory(prevInventory => prevInventory.map(item => item.name === oldName ? { ...item, name: newName } : item ) ) setOutboundRecords(prevRecords => prevRecords.map(record => record.productName === oldName ? { ...record, productName: newName } : record ) ) } return (

库存管理系统

高效管理您的多仓库商品库存

库存管理 数据分析 仓库管理 供应商管理 商品管理 出库记录
入库 添加新商品到库存
setNewItemQuantity(e.target.value)} placeholder="输入数量" />
setNewItemUnitPrice(e.target.value)} placeholder="输入单价" />
库存概览 查看和管理现有库存
setSearchTerm(e.target.value)} className="mr-2" />
requestSort('name')} className="cursor-pointer">商品名称 {sortConfig?.key === 'name' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} requestSort('quantity')} className="cursor-pointer">库存数量 {sortConfig?.key === 'quantity' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} requestSort('warehouse')} className="cursor-pointer">仓库 {sortConfig?.key === 'warehouse' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} requestSort('unitPrice')} className="cursor-pointer">单价 {sortConfig?.key === 'unitPrice' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} requestSort('supplier')} className="cursor-pointer">供应商 {sortConfig?.key === 'supplier' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} requestSort('totalValue')} className="cursor-pointer">总价值 {sortConfig?.key === 'totalValue' && (sortConfig.direction === 'ascending' ? '↑' : '↓')} 操作 {sortedInventory.map((item) => ( {editingItemId === item.id ? setEditingItemName(e.target.value)} className="w-full" /> : item.name } {item.quantity} {item.warehouse} {item.unitPrice.toFixed(2)} {item.supplier} {(item.quantity * item.unitPrice).toFixed(2)}
{editingItemId === item.id ? ( ) : ( )}
))}
所有货品数量和价值图表 展示所有货品的库存数量和总价值
确认删除 您确定要删除这个商品吗?此操作无法撤销。 取消 确认删除
) } function WarehouseManagement({ warehouses, setWarehouses, updateWarehouseName }: { warehouses: string[], setWarehouses: React.Dispatch>, updateWarehouseName: (oldName: string, newName: string) => void }) { const [newWarehouse, setNewWarehouse] = useState("") const [editingWarehouse, setEditingWarehouse] = useState(null) const [editedWarehouseName, setEditedWarehouseName] = useState("") const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false) const [warehouseToDelete, setWarehouseToDelete] = useState(null) const addWarehouse = () => { if (newWarehouse && !warehouses.includes(newWarehouse)) { setWarehouses([...warehouses, newWarehouse]) setNewWarehouse("") } } const startEditing = (warehouse: string) => { setEditingWarehouse(warehouse) setEditedWarehouseName(warehouse) } const saveEdit = () => { if (editingWarehouse && editedWarehouseName) { setWarehouses(warehouses.map(w => w === editingWarehouse ? editedWarehouseName : w)) updateWarehouseName(editingWarehouse, editedWarehouseName) setEditingWarehouse(null) setEditedWarehouseName("") } } const confirmDelete = (warehouse: string) => { setWarehouseToDelete(warehouse) setDeleteConfirmOpen(true) } const deleteWarehouse = () => { if (warehouseToDelete) { setWarehouses(warehouses.filter(w => w !== warehouseToDelete)) setDeleteConfirmOpen(false) setWarehouseToDelete(null) } } return ( 仓库管理 添加、编辑或删除仓库
setNewWarehouse(e.target.value)} placeholder="输入新仓库名称" />
仓库名称 操作 {warehouses.map((warehouse) => ( {editingWarehouse === warehouse ? ( setEditedWarehouseName(e.target.value)} className="w-full" /> ) : ( warehouse )}
{editingWarehouse === warehouse ? ( ) : ( )}
))}
确认删除仓库 您确定要删除仓库 "{warehouseToDelete}" 吗?此操作无法撤销。 取消 确认删除
) } function SupplierManagement({ suppliers, setSuppliers, updateSupplierName }: { suppliers: Supplier[], setSuppliers: React.Dispatch>, updateSupplierName: (oldName: string, newName: string) => void }) { const [newSupplier, setNewSupplier] = useState("") const [editingSupplier, setEditingSupplier] = useState(null) const [editedSupplierName, setEditedSupplierName] = useState("") const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false) const [supplierToDelete, setSupplierToDelete] = useState(null) const addSupplier = () => { if (newSupplier && !suppliers.some(s => s.name === newSupplier)) { setSuppliers([...suppliers, { id: Date.now(), name: newSupplier }]) setNewSupplier("") } } const startEditing = (supplier: Supplier) => { setEditingSupplier(supplier.id) setEditedSupplierName(supplier.name) } const saveEdit = () => { if (editingSupplier !== null && editedSupplierName) { const oldName = suppliers.find(s => s.id === editingSupplier)?.name setSuppliers(suppliers.map(s => s.id === editingSupplier ? { ...s, name: editedSupplierName } : s)) if (oldName) { updateSupplierName(oldName, editedSupplierName) } setEditingSupplier(null) setEditedSupplierName("") } } const confirmDelete = (id: number) => { setSupplierToDelete(id) setDeleteConfirmOpen(true) } const deleteSupplier = () => { if (supplierToDelete !== null) { setSuppliers(suppliers.filter(s => s.id !== supplierToDelete)) setDeleteConfirmOpen(false) setSupplierToDelete(null) } } return ( 供应商管理 添加、编辑或删除供应商
setNewSupplier(e.target.value)} placeholder="输入新供应商名称" />
供应商名称 操作 {suppliers.map((supplier) => ( {editingSupplier === supplier.id ? ( setEditedSupplierName(e.target.value)} className="w-full" /> ) : ( supplier.name )}
{editingSupplier === supplier.id ? ( ) : ( )}
))}
确认删除供应商 您确定要删除这个供应商吗?此操作无法撤销。 取消 确认删除
) } function ProductManagement({ products, setProducts, updateProductName }: { products: Product[], setProducts: React.Dispatch>, updateProductName: (oldName: string, newName: string) => void }) { const [newProduct, setNewProduct] = useState("") const [editingProduct, setEditingProduct] = useState(null) const [editedProductName, setEditedProductName] = useState("") const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false) const [productToDelete, setProductToDelete] = useState(null) const addProduct = () => { if (newProduct && !products.some(p => p.name === newProduct)) { setProducts([...products, { id: Date.now(), name: newProduct }]) setNewProduct("") } } const startEditing = (product: Product) => { setEditingProduct(product.id) setEditedProductName(product.name) } const saveEdit = () => { if (editingProduct !== null && editedProductName) { const oldName = products.find(p => p.id === editingProduct)?.name setProducts(products.map(p => p.id === editingProduct ? { ...p, name: editedProductName } : p)) if (oldName) { updateProductName(oldName, editedProductName) } setEditingProduct(null) setEditedProductName("") } } const confirmDelete = (id: number) => { setProductToDelete(id) setDeleteConfirmOpen(true) } const deleteProduct = () => { if (productToDelete !== null) { setProducts(products.filter(p => p.id !== productToDelete)) setDeleteConfirmOpen(false) setProductToDelete(null) } } return ( 商品管理 添加、编辑或删除商品
setNewProduct(e.target.value)} placeholder="输入新商品名称" />
商品名称 操作 {products.map((product) => ( {editingProduct === product.id ? ( setEditedProductName(e.target.value)} className="w-full" /> ) : ( product.name )}
{editingProduct === product.id ? ( ) : ( )}
))}
确认删除商品 您确定要删除这个商品吗?此操作无法撤销。 取消 确认删除
) } function OutboundManagement({ inventory, outboundRecords, addOutboundRecord }: { inventory: InventoryItem[], setInventory: React.Dispatch>, outboundRecords: OutboundRecord[], addOutboundRecord: (productId: number, productName: string, quantity: number, recipient: string, warehouse: string, supplier: string) => void, products: Product[] }) { const [selectedProduct, setSelectedProduct] = useState("") const [outboundQuantity, setOutboundQuantity] = useState("") const [recipient, setRecipient] = useState("") const handleOutbound = () => { const product = inventory.find(item => item.name === selectedProduct) if (product && outboundQuantity && recipient) { const quantity = parseInt(outboundQuantity) if (quantity > product.quantity) { alert('出库数量不能大于库存数量!') return } addOutboundRecord(product.id, product.name, quantity, recipient, product.warehouse, product.supplier) // 清空输入框 setSelectedProduct("") setOutboundQuantity("") setRecipient("") } } return ( 出库管理 记录商品出库情况
setOutboundQuantity(e.target.value)} placeholder="输入数量" />
setRecipient(e.target.value)} placeholder="输入接收方" />
商品名称 数量 接收方 仓库 供应商 日期 {outboundRecords.map((record) => ( {record.productName} {record.quantity} {record.recipient} {record.warehouse} {record.supplier} {format(new Date(record.date), 'yyyy-MM-dd HH:mm:ss')} ))}
) }