Files
accounting_front/src/components/InventoryManagement.js
2025-10-11 20:29:31 +03:30

300 lines
10 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;