300 lines
10 KiB
JavaScript
300 lines
10 KiB
JavaScript
import React, { useState } from 'react';
|
||
|
||
const InventoryManagement = () => {
|
||
const [inventory, setInventory] = useState([
|
||
{
|
||
id: 1,
|
||
product: 'لپتاپ ایسوس',
|
||
code: 'LAP001',
|
||
currentStock: 5,
|
||
minStock: 2,
|
||
maxStock: 20,
|
||
unit: 'عدد',
|
||
lastUpdate: '1403/01/15'
|
||
},
|
||
{
|
||
id: 2,
|
||
product: 'موبایل سامسونگ',
|
||
code: 'MOB002',
|
||
currentStock: 12,
|
||
minStock: 5,
|
||
maxStock: 50,
|
||
unit: 'عدد',
|
||
lastUpdate: '1403/01/14'
|
||
},
|
||
{
|
||
id: 3,
|
||
product: 'کتاب برنامهنویسی',
|
||
code: 'BOK003',
|
||
currentStock: 25,
|
||
minStock: 10,
|
||
maxStock: 100,
|
||
unit: 'جلد',
|
||
lastUpdate: '1403/01/13'
|
||
}
|
||
]);
|
||
|
||
const [showAdjustmentForm, setShowAdjustmentForm] = useState(false);
|
||
const [selectedProduct, setSelectedProduct] = useState(null);
|
||
const [adjustmentData, setAdjustmentData] = useState({
|
||
type: 'افزایش',
|
||
quantity: '',
|
||
reason: ''
|
||
});
|
||
|
||
const handleAdjustmentChange = (e) => {
|
||
const { name, value } = e.target;
|
||
setAdjustmentData(prev => ({
|
||
...prev,
|
||
[name]: value
|
||
}));
|
||
};
|
||
|
||
const handleStockAdjustment = (e) => {
|
||
e.preventDefault();
|
||
const adjustmentQuantity = parseInt(adjustmentData.quantity);
|
||
const newStock = adjustmentData.type === 'افزایش'
|
||
? selectedProduct.currentStock + adjustmentQuantity
|
||
: selectedProduct.currentStock - adjustmentQuantity;
|
||
|
||
if (newStock < 0) {
|
||
alert('موجودی نمیتواند منفی باشد!');
|
||
return;
|
||
}
|
||
|
||
setInventory(inventory.map(item =>
|
||
item.id === selectedProduct.id
|
||
? {
|
||
...item,
|
||
currentStock: newStock,
|
||
lastUpdate: new Date().toLocaleDateString('fa-IR')
|
||
}
|
||
: item
|
||
));
|
||
|
||
setShowAdjustmentForm(false);
|
||
setSelectedProduct(null);
|
||
setAdjustmentData({ type: 'افزایش', quantity: '', reason: '' });
|
||
};
|
||
|
||
const handleCancelAdjustment = () => {
|
||
setShowAdjustmentForm(false);
|
||
setSelectedProduct(null);
|
||
setAdjustmentData({ type: 'افزایش', quantity: '', reason: '' });
|
||
};
|
||
|
||
const getStockStatus = (current, min, max) => {
|
||
if (current <= min) return { status: 'کم', color: 'bg-red-100 text-red-800' };
|
||
if (current >= max) return { status: 'زیاد', color: 'bg-yellow-100 text-yellow-800' };
|
||
return { status: 'مناسب', color: 'bg-green-100 text-green-800' };
|
||
};
|
||
|
||
const lowStockItems = inventory.filter(item => item.currentStock <= item.minStock);
|
||
const totalValue = inventory.reduce((sum, item) => {
|
||
// Assuming average price for calculation
|
||
const avgPrice = item.product === 'لپتاپ ایسوس' ? 15000000 :
|
||
item.product === 'موبایل سامسونگ' ? 8000000 : 150000;
|
||
return sum + (item.currentStock * avgPrice);
|
||
}, 0);
|
||
|
||
const formatPrice = (price) => {
|
||
return new Intl.NumberFormat('fa-IR').format(price) + ' ریال';
|
||
};
|
||
|
||
return (
|
||
<div className="farsi-text">
|
||
<div className="flex justify-between items-center mb-6">
|
||
<h1 className="text-3xl font-bold text-gray-900">مدیریت انبار</h1>
|
||
<button
|
||
onClick={() => setShowAdjustmentForm(true)}
|
||
className="btn-primary"
|
||
>
|
||
تنظیم موجودی
|
||
</button>
|
||
</div>
|
||
|
||
{/* Inventory Summary */}
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
|
||
<div className="card">
|
||
<div className="flex items-center">
|
||
<div className="bg-blue-500 rounded-full p-3 text-white text-2xl ml-4">
|
||
📦
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">کل کالاها</p>
|
||
<p className="text-2xl font-bold text-gray-900">{inventory.length}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="card">
|
||
<div className="flex items-center">
|
||
<div className="bg-red-500 rounded-full p-3 text-white text-2xl ml-4">
|
||
⚠️
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">کمبود موجودی</p>
|
||
<p className="text-2xl font-bold text-gray-900">{lowStockItems.length}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="card">
|
||
<div className="flex items-center">
|
||
<div className="bg-green-500 rounded-full p-3 text-white text-2xl ml-4">
|
||
💰
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">ارزش کل انبار</p>
|
||
<p className="text-lg font-bold text-gray-900">{formatPrice(totalValue)}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="card">
|
||
<div className="flex items-center">
|
||
<div className="bg-purple-500 rounded-full p-3 text-white text-2xl ml-4">
|
||
📊
|
||
</div>
|
||
<div>
|
||
<p className="text-sm font-medium text-gray-600">کل موجودی</p>
|
||
<p className="text-2xl font-bold text-gray-900">
|
||
{inventory.reduce((sum, item) => sum + item.currentStock, 0)}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Low Stock Alert */}
|
||
{lowStockItems.length > 0 && (
|
||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
|
||
<h3 className="text-red-800 font-bold mb-2">هشدار کمبود موجودی</h3>
|
||
<div className="space-y-2">
|
||
{lowStockItems.map(item => (
|
||
<div key={item.id} className="text-red-700">
|
||
{item.product} - موجودی فعلی: {item.currentStock} {item.unit} (حداقل: {item.minStock})
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Stock Adjustment Form Modal */}
|
||
{showAdjustmentForm && (
|
||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||
<div className="bg-white rounded-lg p-6 w-full max-w-md">
|
||
<h2 className="text-xl font-bold mb-4">تنظیم موجودی</h2>
|
||
<form onSubmit={handleStockAdjustment} className="space-y-4">
|
||
<div>
|
||
<label className="form-label">کالا</label>
|
||
<select
|
||
value={selectedProduct?.id || ''}
|
||
onChange={(e) => {
|
||
const product = inventory.find(item => item.id === parseInt(e.target.value));
|
||
setSelectedProduct(product);
|
||
}}
|
||
className="form-input"
|
||
required
|
||
>
|
||
<option value="">انتخاب کنید</option>
|
||
{inventory.map(item => (
|
||
<option key={item.id} value={item.id}>
|
||
{item.product} (موجودی فعلی: {item.currentStock})
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label className="form-label">نوع تنظیم</label>
|
||
<select
|
||
name="type"
|
||
value={adjustmentData.type}
|
||
onChange={handleAdjustmentChange}
|
||
className="form-input"
|
||
>
|
||
<option value="افزایش">افزایش موجودی</option>
|
||
<option value="کاهش">کاهش موجودی</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label className="form-label">تعداد</label>
|
||
<input
|
||
type="number"
|
||
name="quantity"
|
||
value={adjustmentData.quantity}
|
||
onChange={handleAdjustmentChange}
|
||
className="form-input"
|
||
required
|
||
min="1"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="form-label">دلیل</label>
|
||
<textarea
|
||
name="reason"
|
||
value={adjustmentData.reason}
|
||
onChange={handleAdjustmentChange}
|
||
className="form-input"
|
||
rows="3"
|
||
placeholder="دلیل تنظیم موجودی..."
|
||
/>
|
||
</div>
|
||
<div className="flex space-x-2 space-x-reverse">
|
||
<button type="submit" className="btn-success flex-1">
|
||
اعمال تغییرات
|
||
</button>
|
||
<button type="button" onClick={handleCancelAdjustment} className="btn-secondary flex-1">
|
||
انصراف
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Inventory Table */}
|
||
<div className="card">
|
||
<div className="overflow-x-auto">
|
||
<table className="table">
|
||
<thead>
|
||
<tr>
|
||
<th>نام کالا</th>
|
||
<th>کد کالا</th>
|
||
<th>موجودی فعلی</th>
|
||
<th>حداقل</th>
|
||
<th>حداکثر</th>
|
||
<th>وضعیت</th>
|
||
<th>آخرین بروزرسانی</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{inventory.map(item => {
|
||
const stockStatus = getStockStatus(item.currentStock, item.minStock, item.maxStock);
|
||
return (
|
||
<tr key={item.id}>
|
||
<td>{item.product}</td>
|
||
<td>
|
||
<span className="bg-gray-100 px-2 py-1 rounded text-sm">
|
||
{item.code}
|
||
</span>
|
||
</td>
|
||
<td className="font-bold">{item.currentStock} {item.unit}</td>
|
||
<td>{item.minStock} {item.unit}</td>
|
||
<td>{item.maxStock} {item.unit}</td>
|
||
<td>
|
||
<span className={`px-2 py-1 rounded-full text-xs ${stockStatus.color}`}>
|
||
{stockStatus.status}
|
||
</span>
|
||
</td>
|
||
<td>{item.lastUpdate}</td>
|
||
</tr>
|
||
);
|
||
})}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default InventoryManagement;
|