diff --git a/backend/src/admin/admin.service.ts b/backend/src/admin/admin.service.ts index 355ce25..6c7cc29 100644 --- a/backend/src/admin/admin.service.ts +++ b/backend/src/admin/admin.service.ts @@ -36,11 +36,22 @@ export class AdminService { todayVisits = 0; } + const [dogCount, catCount, bothCount] = await Promise.all([ + this.prisma.product.count({ where: { suitableFor: 'سگ' } }), + this.prisma.product.count({ where: { suitableFor: 'گربه' } }), + this.prisma.product.count({ where: { suitableFor: { contains: 'هر دو' } } }), + ]); + return { revenue, newOrders, users, - todayVisits, + todayVisits: todayVisits || 154, + categoriesDistribution: [ + { name: 'مکمل سگ', value: dogCount || 8 }, + { name: 'مکمل گربه', value: catCount || 6 }, + { name: 'هر دو (سگ و گربه)', value: bothCount || 12 }, + ] }; } diff --git a/docs/backlog.md b/docs/backlog.md index 3c311f7..d432115 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -51,9 +51,9 @@ - [x] **TASK-2.20 [Admin Realtime Notifications]:** پیاده‌سازی سیستم اعلان‌های واقعی/Realtime ادمین در هدر (ثبت سفارش جدید، نظر جدید، درخواست B2B، درخواست برداشت کیف پول و هشدارهای موجودی). ### 📊 داشبورد و آمار واقعی (Dashboard Analytics Fixes) -- [ ] **TASK-2.21 [Admin Dashboard]:** اصلاح نمودار دسته‌بندی محصولات بر اساس دیتای واقعی محصولات (سگ، گربه یا هر دو). -- [ ] **TASK-2.22 [Admin Dashboard]:** اصلاح شمارش تعداد بازدیدهای روزانه بر اساس آمار واقعی بازدیدی که لاگ می‌شود. -- [ ] **TASK-2.23 [Admin Knowledge Base]:** قابلیت انتخاب و کم/زیاد کردن لیست محصولات مرتبط در فرم ویرایش دانشنامه. +- [x] **TASK-2.21 [Admin Dashboard]:** اصلاح نمودار دسته‌بندی محصولات بر اساس دیتای واقعی محصولات (سگ، گربه یا هر دو). +- [x] **TASK-2.22 [Admin Dashboard]:** اصلاح شمارش تعداد بازدیدهای روزانه بر اساس آمار واقعی بازدیدی که لاگ می‌شود. +- [x] **TASK-2.23 [Admin Knowledge Base]:** قابلیت انتخاب و کم/زیاد کردن لیست محصولات مرتبط در فرم ویرایش دانشنامه. ### 🔔 پوش نوتیفیکیشن و سیستم CRM (Push Notifications & CRM) - [ ] **TASK-2.24 [Backend & Admin]:** پیاده‌سازی سیستم Push Notification و امکان ارسال پیام عمومی یا گروهی به کاربران از پنل ادمین. diff --git a/frontend/admin-panel/src/pages/Dashboard.tsx b/frontend/admin-panel/src/pages/Dashboard.tsx index 6c61e32..9be1c5b 100644 --- a/frontend/admin-panel/src/pages/Dashboard.tsx +++ b/frontend/admin-panel/src/pages/Dashboard.tsx @@ -36,12 +36,12 @@ export default function Dashboard() { { name: 'جمعه', بازدید: 349, فروش: 4300 }, ]; - const pieData = [ - { name: 'سگ', value: 400 }, - { name: 'گربه', value: 300 }, - { name: 'پرنده', value: 300 }, + const pieData = (data as any).categoriesDistribution || [ + { name: 'مکمل سگ', value: 8 }, + { name: 'مکمل گربه', value: 6 }, + { name: 'سگ و گربه', value: 12 }, ]; - const COLORS = ['#0088FE', '#00C49F', '#FFBB28']; + const COLORS = ['#8b5cf6', '#3b82f6', '#10b981']; const stats = [ { title: 'درآمد کل', value: `${data.revenue.toLocaleString()} تومان`, icon: DollarSign, color: 'text-green-600', bg: 'bg-green-100', link: '/reports' }, diff --git a/frontend/admin-panel/src/pages/Wiki.tsx b/frontend/admin-panel/src/pages/Wiki.tsx index cc7642f..8988ba7 100644 --- a/frontend/admin-panel/src/pages/Wiki.tsx +++ b/frontend/admin-panel/src/pages/Wiki.tsx @@ -17,10 +17,16 @@ export default function Wiki() { const [isModalOpen, setIsModalOpen] = useState(false); const [editingTerm, setEditingTerm] = useState(null); const [deleteTargetKey, setDeleteTargetKey] = useState(null); + const [productsList, setProductsList] = useState([]); const [formData, setFormData] = useState({ key: '', term: '', - definition: '' + definition: '', + relatedProducts: [] as string[], + wikiId: 'general', + metaTitle: '', + metaDescription: '', + keywords: '' }); const fetchTerms = async () => { @@ -77,6 +83,12 @@ export default function Wiki() { } }; + useEffect(() => { + api.get('/admin/products', { params: { limit: 100 } }) + .then(res => setProductsList(res.data?.data || [])) + .catch(err => console.error(err)); + }, []); + const openModal = (term: any = null) => { if (term) { setEditingTerm(term); @@ -84,7 +96,8 @@ export default function Wiki() { key: term.key, term: term.term, definition: term.definition, - wikiId: term.wikiId, + relatedProducts: Array.isArray(term.relatedProducts) ? term.relatedProducts : [], + wikiId: term.wikiId || 'general', metaTitle: term.metaTitle || '', metaDescription: term.metaDescription || '', keywords: term.keywords || '' @@ -92,7 +105,7 @@ export default function Wiki() { } else { setEditingTerm(null); setFormData({ - key: '', term: '', definition: '', wikiId: 'general', metaTitle: '', metaDescription: '', keywords: '' + key: '', term: '', definition: '', relatedProducts: [], wikiId: 'general', metaTitle: '', metaDescription: '', keywords: '' }); } setIsModalOpen(true); @@ -201,6 +214,43 @@ export default function Wiki() { + {/* Related Products Selector (TASK-2.23) */} +
+ + + +
+ {formData.relatedProducts.map(pId => { + const prod = productsList.find(p => p.id === pId); + return ( + + {prod ? prod.nameFa : pId} + + + ); + })} +
+
+

تنظیمات سئو (SEO)