This commit is contained in:
2026-04-30 02:09:56 +03:30
parent 04d678fda4
commit 9946f01cca
7 changed files with 2238 additions and 301 deletions
@@ -0,0 +1,709 @@
# Yield & Harvest Backend Requirements
این سند مشخص می‌کند صفحه `yield-harvest` برای کامل شدن تمام کارت‌ها چه داده‌ای از بک‌اند نیاز دارد، هر فیلد دقیقاً کجا مصرف می‌شود، و چه بخش‌هایی هنوز در فرانت mock هستند.
## هدف
در حال حاضر صفحه `yield-harvest` از این فایل‌ها ساخته می‌شود:
- `src/views/dashboards/farm/PlantProductionPage.tsx`
- `src/views/dashboards/farm/YieldHarvestPageWrapper.tsx`
- `src/views/dashboards/farm/YieldSeasonHighlightsCard.tsx`
- `src/views/dashboards/farm/FarmOverviewKPIs.tsx`
- `src/views/dashboards/farm/HarvestPredictionCard.tsx`
- `src/views/dashboards/farm/HarvestReadinessZonesCard.tsx`
- `src/views/dashboards/farm/YieldQualityBandsCard.tsx`
- `src/views/dashboards/farm/HarvestOperationsCard.tsx`
- `src/views/dashboards/farm/YieldPredictionChart.tsx`
هدف این سند این است که تیم بک‌اند دقیقاً بداند:
- هر کارت چه payloadی می‌خواهد
- کدام فیلدها اجباری هستند
- کدام مقادیر باید `number` باشند و کدام‌ها `string`
- چه endpointی بهتر است این اطلاعات را برگرداند
---
## وضعیت فعلی فرانت
### داده‌هایی که همین الان از API خوانده می‌شوند
فرانت الان از `src/libs/api/services/yieldHarvestService.ts` این endpoint را صدا می‌زند:
`GET /api/yield-harvest/summary/?farm_uuid=<uuid>`
و فقط این سه بخش را map می‌کند:
- `yield_prediction`
- `harvest_prediction_card`
- `yield_prediction_chart`
### داده‌هایی که هنوز mock هستند
این کارت‌ها هنوز با داده mock رندر می‌شوند و برای production باید از بک‌اند بیایند:
- `YieldSeasonHighlightsCard`
- `HarvestReadinessZonesCard`
- `YieldQualityBandsCard`
- `HarvestOperationsCard`
### نکته مهم درباره Plant Simulator
کامپوننت `src/views/dashboards/farm/plantSimulator/PlantSimulator.tsx` فعلاً self-contained است و برای نمایش فعلی به API نیاز ندارد.
پس اگر هدف فعلی فقط کامل شدن کارت‌های اطلاعاتی صفحه است، برای simulator نیازی به endpoint جدید نیست.
---
## پیشنهاد اصلی
بهترین راه این است که همان endpoint فعلی صفحه توسعه پیدا کند و تمام data blockهای موردنیاز را یکجا برگرداند:
`GET /api/yield-harvest/summary/`
### query params
- `farm_uuid` - اجباری
### query params پیشنهادی برای آینده
- `season_year` - برای انتخاب فصل یا سال زراعی
- `crop_name` - اگر یک مزرعه چند محصول داشته باشد
- `lang` - اگر بخواهید backend متن‌های آماده UI را چندزبانه برگرداند
---
## payload کامل پیشنهادی
نمونه response کامل که تمام کارت‌های فعلی صفحه را پوشش می‌دهد:
```json
{
"code": 200,
"msg": "success",
"data": {
"farm_uuid": "11111111-1111-1111-1111-111111111111",
"season_highlights_card": {
"title": "اتاق فرمان برداشت این فصل",
"subtitle": "خلاصه سریع وضعیت عملکرد، کیفیت و بهترین پنجره فروش برای مزرعه انتخاب شده.",
"seasonLabel": "فصل 1404",
"badges": ["کیفیت ممتاز", "آماده بسته بندی", "ریسک پایین"],
"spotlight": {
"title": "پنجره طلایی فروش",
"value": "3 روز اول بعد از برداشت",
"caption": "در این بازه برآورد قیمت فروش حدود 8٪ بهتر از میانگین هفتگی است."
},
"metrics": [
{
"label": "سطح قابل برداشت",
"value": "18.6 هکتار",
"caption": "4 قطعه در اولویت نخست قرار دارند.",
"avatarIcon": "tabler-map-2",
"avatarColor": "success"
},
{
"label": "گرید ممتاز",
"value": "46%",
"caption": "بالاترین سهم کیفیت مربوط به قطعه A2 است.",
"avatarIcon": "tabler-rosette-discount-check",
"avatarColor": "warning"
},
{
"label": "درآمد هدف",
"value": "1.84 میلیارد",
"caption": "با فرض فروش در بازه پیشنهادی مدل.",
"avatarIcon": "tabler-cash-banknote",
"avatarColor": "primary"
}
]
},
"yield_prediction": {
"kpis": [
{
"id": "predicted-yield",
"title": "عملکرد پیش بینی شده",
"subtitle": "فصل جاری",
"stats": "42.8 تن",
"avatarColor": "primary",
"avatarIcon": "tabler-chart-arcs",
"chipText": "+12%",
"chipColor": "success"
},
{
"id": "harvest-readiness",
"title": "آمادگی برداشت",
"subtitle": "میانگین مزرعه",
"stats": "84%",
"avatarColor": "success",
"avatarIcon": "tabler-plant-2",
"chipText": "روی برنامه",
"chipColor": "success"
},
{
"id": "quality-score",
"title": "امتیاز کیفیت",
"subtitle": "برآورد هوش مصنوعی",
"stats": "91/100",
"avatarColor": "info",
"avatarIcon": "tabler-stars",
"chipText": "+4 واحد",
"chipColor": "success"
},
{
"id": "loss-risk",
"title": "ریسک افت محصول",
"subtitle": "آب و هوا و آفات",
"stats": "6.5%",
"avatarColor": "warning",
"avatarIcon": "tabler-alert-triangle",
"chipText": "پایین",
"chipColor": "warning"
}
]
},
"harvest_prediction_card": {
"dateFormatted": "28 شهریور",
"daysUntil": 18,
"description": "با توجه به روند رشد، الگوی آبیاری و وضعیت دمایی اخیر، این مزرعه در هفته آخر شهریور به نقطه ایده آل برداشت می رسد."
},
"harvest_readiness_zones": {
"averageReadiness": "84%",
"blocks": [
{
"name": "قطعه A1",
"cultivar": "گندم سیروان",
"readiness": 92,
"harvestDate": "26 شهریور",
"expectedYield": "12.4 تن",
"moisture": "11.8%"
},
{
"name": "قطعه A2",
"cultivar": "گندم پیشگام",
"readiness": 87,
"harvestDate": "27 شهریور",
"expectedYield": "10.1 تن",
"moisture": "12.3%"
}
]
},
"yield_quality_bands": {
"bands": [
{
"label": "گرید ممتاز",
"share": 46,
"volume": "19.7 تن",
"premium": "+18% قیمت",
"color": "#2e7d32"
},
{
"label": "گرید درجه یک",
"share": 34,
"volume": "14.5 تن",
"premium": "+9% قیمت",
"color": "#0288d1"
},
{
"label": "گرید فرآوری",
"share": 20,
"volume": "8.6 تن",
"premium": "فروش پایه",
"color": "#ed6c02"
}
],
"stats": [
{ "label": "میانگین بریکس", "value": "14.8" },
{ "label": "یکنواختی دانه", "value": "89%" },
{ "label": "ضایعات قابل انتظار", "value": "2.1%" },
{ "label": "پتانسیل صادرات", "value": "بالا" }
]
},
"harvest_operations_card": {
"summary": "اگر برداشت از قطعات A1 و A2 در دو شیفت اول انجام شود، کیفیت ممتاز حفظ می شود و فشار روی مرحله سورتینگ متعادل می ماند.",
"steps": [
{
"title": "برداشت قطعات اولویت دار",
"note": "تمرکز ابتدا روی A1 و سپس A2 باشد تا گرید ممتاز در دمای پایین صبح جمع آوری شود.",
"status": "امروز",
"statusColor": "success"
},
{
"title": "سورت و تفکیک بر اساس کیفیت",
"note": "محصول ممتاز از جریان فرآوری جدا شود تا فروش با قیمت پریمیوم حفظ شود.",
"status": "بعد از برداشت",
"statusColor": "primary"
},
{
"title": "انتقال سریع به انبار خنک",
"note": "انتقال نهایی حداکثر تا 6 ساعت پس از برداشت انجام شود.",
"status": "ضروری",
"statusColor": "warning"
}
],
"outputs": [
{ "label": "شیفت پیشنهادی", "value": "2 شیفت" },
{ "label": "ظرفیت سورتینگ", "value": "15 تن/روز" },
{ "label": "نیروی مورد نیاز", "value": "12 نفر" },
{ "label": "مدت تا ارسال", "value": "6 ساعت" }
]
},
"yield_prediction_chart": {
"categories": ["فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان"],
"series": [
{
"name": "سال قبل",
"data": [9, 11, 13, 16, 19, 24, 28, 31]
},
{
"name": "سال جاری",
"data": [10, 12, 15, 18, 23, 29, 34, 39]
}
],
"summary": [
{
"title": "بیشترین خروجی پیش بینی شده",
"subtitle": "بهترین ماه برداشت",
"amount": "39 تن",
"avatarColor": "success",
"avatarIcon": "tabler-trending-up"
},
{
"title": "رشد این فصل",
"subtitle": "نسبت به سال قبل",
"amount": "+11.2 تن",
"avatarColor": "primary",
"avatarIcon": "tabler-chart-line"
}
]
}
}
}
```
---
## توضیح کامل هر کارت
## 1) Season Highlights Card
کامپوننت: `src/views/dashboards/farm/YieldSeasonHighlightsCard.tsx`
### حداقل داده لازم برای رندر
- `title`
- `subtitle`
- `spotlight`
- `metrics[]`
اگر `title` خالی باشد یا `spotlight` وجود نداشته باشد یا `metrics` خالی باشد، کارت رندر نمی‌شود.
### فیلدها
- `title`: تیتر اصلی کارت
- `subtitle`: توضیح متنی زیر تیتر
- `seasonLabel`: چیپ فصل، مثل `فصل 1404`
- `badges[]`: لیبل‌های کوتاه وضعیت
- `spotlight.title`: عنوان بخش برجسته
- `spotlight.value`: مقدار اصلی بخش برجسته
- `spotlight.caption`: توضیح تکمیلی
- `metrics[]`: آرایه کارت‌های کوچک پایین
### ساختار `metrics[]`
هر آیتم این فیلدها را نیاز دارد:
- `label`: عنوان metric
- `value`: مقدار اصلی metric
- `caption`: توضیح کوتاه زیر metric
- `avatarIcon`: نام icon از Tabler
- `avatarColor`: یکی از این مقادیر:
- `primary`
- `success`
- `info`
- `warning`
### نکته بک‌اند
این کارت فعلاً به API وصل نیست و باید یا:
- به همین summary endpoint اضافه شود
- یا یک endpoint جدا برای page header/hero داشته باشد
پیشنهاد بهتر: در همان `summary` برگردد.
---
## 2) KPI Row
کامپوننت: `src/views/dashboards/farm/FarmOverviewKPIs.tsx`
### ساختار موردنیاز
```json
{
"yield_prediction": {
"kpis": [
{
"id": "predicted-yield",
"title": "عملکرد پیش بینی شده",
"subtitle": "فصل جاری",
"stats": "42.8 تن",
"avatarColor": "primary",
"avatarIcon": "tabler-chart-arcs",
"chipText": "+12%",
"chipColor": "success"
}
]
}
}
```
### فیلدهای هر KPI
- `id` - اجباری و یکتا
- `title` - اجباری
- `subtitle` - اجباری
- `stats` - اجباری
- `avatarColor` - اختیاری
- `avatarIcon` - اختیاری
- `chipText` - اختیاری
- `chipColor` - اختیاری
### مقدارهای مجاز
- `avatarColor` بهتر است یکی از این‌ها باشد:
- `primary`
- `secondary`
- `success`
- `info`
- `warning`
- `chipColor` بهتر است یکی از این‌ها باشد:
- `success`
- `warning`
### نکته مهم
فرانت برای نمایش کامل این ردیف، `yield_prediction.kpis[]` می‌خواهد.
اگر بک‌اند فقط یک object تکی برگرداند، فقط یک کارت KPI نمایش داده می‌شود.
---
## 3) Harvest Prediction Card
کامپوننت: `src/views/dashboards/farm/HarvestPredictionCard.tsx`
### ساختار موردنیاز
```json
{
"harvest_prediction_card": {
"dateFormatted": "28 شهریور",
"daysUntil": 18,
"description": "..."
}
}
```
### فیلدها
- `dateFormatted` - تاریخ برداشت به صورت آماده نمایش
- `daysUntil` - عدد با type `number`
- `description` - توضیح متنی
### رفتار UI
- اگر `daysUntil > 0` باشد، چیپ تعداد روز باقی‌مانده نمایش داده می‌شود
- اگر `daysUntil` صفر یا منفی باشد، چیپ نمایش داده نمی‌شود
### نکته بک‌اند
- `daysUntil` حتماً `number` باشد، نه string
- `dateFormatted` چون مستقیم در UI چاپ می‌شود بهتر است آماده نمایش باشد
---
## 4) Harvest Readiness Zones Card
کامپوننت: `src/views/dashboards/farm/HarvestReadinessZonesCard.tsx`
### ساختار موردنیاز
```json
{
"harvest_readiness_zones": {
"averageReadiness": "84%",
"blocks": [
{
"name": "قطعه A1",
"cultivar": "گندم سیروان",
"readiness": 92,
"harvestDate": "26 شهریور",
"expectedYield": "12.4 تن",
"moisture": "11.8%"
}
]
}
}
```
### فیلدهای سطح کارت
- `averageReadiness` - مقدار آماده نمایش برای چیپ بالای کارت
- `blocks[]` - آرایه قطعات مزرعه
### فیلدهای هر block
- `name` - نام قطعه
- `cultivar` - رقم یا cultivar
- `readiness` - درصد آمادگی با type `number`
- `harvestDate` - تاریخ پیشنهادی برداشت
- `expectedYield` - عملکرد پیش‌بینی‌شده به صورت string
- `moisture` - رطوبت محصول/دانه به صورت string
### نکات مهم
- اگر `blocks.length === 0` باشد کارت اصلاً رندر نمی‌شود
- `readiness` باید بین `0..100` باشد چون در progress bar استفاده می‌شود
- رنگ چیپ تاریخ برداشت از روی `readiness` در فرانت تعیین می‌شود:
- `>= 85` -> `success`
- `>= 70` -> `warning`
- کمتر از `70` -> `info`
---
## 5) Yield Quality Bands Card
کامپوننت: `src/views/dashboards/farm/YieldQualityBandsCard.tsx`
### ساختار موردنیاز
```json
{
"yield_quality_bands": {
"bands": [
{
"label": "گرید ممتاز",
"share": 46,
"volume": "19.7 تن",
"premium": "+18% قیمت",
"color": "#2e7d32"
}
],
"stats": [
{
"label": "میانگین بریکس",
"value": "14.8"
}
]
}
}
```
### فیلدهای `bands[]`
- `label` - نام گرید کیفیت
- `share` - درصد سهم از کل برداشت با type `number`
- `volume` - حجم محصول این گرید
- `premium` - اثر قیمتی یا برچسب تجاری
- `color` - رنگ نوار، ترجیحاً hex
### فیلدهای `stats[]`
- `label`
- `value`
### نکات مهم
- اگر `bands.length === 0` باشد کارت رندر نمی‌شود
- `share` باید `number` باشد و بهتر است در بازه `0..100` باشد
- `color` باید color-valid باشد چون مستقیم برای style استفاده می‌شود
---
## 6) Harvest Operations Card
کامپوننت: `src/views/dashboards/farm/HarvestOperationsCard.tsx`
### ساختار موردنیاز
```json
{
"harvest_operations_card": {
"summary": "....",
"steps": [
{
"title": "برداشت قطعات اولویت دار",
"note": "....",
"status": "امروز",
"statusColor": "success"
}
],
"outputs": [
{
"label": "شیفت پیشنهادی",
"value": "2 شیفت"
}
]
}
}
```
### فیلدها
- `summary` - متن خلاصه بالای کارت
- `steps[]` - لیست مراحل عملیاتی
- `outputs[]` - خروجی‌های خلاصه پایین کارت
### فیلدهای هر step
- `title`
- `note`
- `status`
- `statusColor`
### مقدارهای مجاز `statusColor`
- `primary`
- `success`
- `info`
- `warning`
### فیلدهای هر output
- `label`
- `value`
### نکات مهم
- اگر `steps.length === 0` باشد کارت رندر نمی‌شود
- `summary` اختیاری است ولی بهتر است همیشه مقدار داشته باشد
---
## 7) Yield Prediction Chart
کامپوننت: `src/views/dashboards/farm/YieldPredictionChart.tsx`
### ساختار موردنیاز
```json
{
"yield_prediction_chart": {
"categories": ["فروردین", "اردیبهشت", "خرداد"],
"series": [
{
"name": "سال قبل",
"data": [9, 11, 13]
},
{
"name": "سال جاری",
"data": [10, 12, 15]
}
],
"summary": [
{
"title": "بیشترین خروجی پیش بینی شده",
"subtitle": "بهترین ماه برداشت",
"amount": "39 تن",
"avatarColor": "success",
"avatarIcon": "tabler-trending-up"
}
]
}
}
```
### فیلدهای chart
- `categories[]` - labelهای محور X
- `series[]` - سری‌های نمودار
- `summary[]` - لیست خلاصه پایین نمودار
### فیلدهای هر series
- `name`
- `data[]` - فقط `number`
### فیلدهای هر summary item
- `title`
- `subtitle`
- `amount`
- `avatarColor`
- `avatarIcon`
### نکات مهم
- اگر `series.length === 0` باشد خود chart رندر نمی‌شود
- `categories.length` باید با طول `data[]` هر series سازگار باشد
- مقادیر `data[]` حتماً عددی باشند، نه string
---
## قوانین مشترک برای بک‌اند
برای اینکه این صفحه بدون mapping پیچیده و bug کار کند، این قواعد را رعایت کنید:
- همه درصدها و مقادیری که در chart یا progress bar استفاده می‌شوند باید `number` باشند
- همه متن‌های آماده نمایش مثل `12.4 تن`، `26 شهریور`، `11.8%` می‌توانند `string` باشند
- color fieldها باید مقدار معتبر UI داشته باشند
- icon fieldها باید از icon nameهای معتبر Tabler باشند
- اگر API wrapper دارید، ساختار `code/msg/data` مشکلی ندارد
- همه timestampها در صورت نیاز آینده بهتر است ISO 8601 باشند
- داده‌ها باید بر اساس `farm_uuid` فیلتر شوند
---
## حداقل داده‌ای که برای حذف کامل mockها لازم است
برای اینکه این صفحه دیگر به هیچ mockی وابسته نباشد، بک‌اند باید این 7 بلوک را برگرداند:
- `season_highlights_card`
- `yield_prediction`
- `harvest_prediction_card`
- `harvest_readiness_zones`
- `yield_quality_bands`
- `harvest_operations_card`
- `yield_prediction_chart`
اگر فقط این سه بخش برگردند:
- `yield_prediction`
- `harvest_prediction_card`
- `yield_prediction_chart`
باز هم صفحه ناقص می‌ماند چون سه کارت تحلیلی و کارت hero هنوز از mock استفاده می‌کنند.
---
## نکات اتصال فرانت
بعد از آماده شدن بک‌اند، فرانت باید این mappingها را کامل کند:
- `season_highlights_card` -> `YieldSeasonHighlightsCard`
- `yield_prediction.kpis` -> `FarmOverviewKPIs`
- `harvest_prediction_card` -> `HarvestPredictionCard`
- `harvest_readiness_zones` -> `HarvestReadinessZonesCard`
- `yield_quality_bands` -> `YieldQualityBandsCard`
- `harvest_operations_card` -> `HarvestOperationsCard`
- `yield_prediction_chart` -> `YieldPredictionChart`
### نکته فنی مهم
در `src/libs/api/services/yieldHarvestService.ts` الان `yield_prediction` به شکل یک کارت تکی normalize می‌شود.
اگر بک‌اند `yield_prediction.kpis[]` برگرداند، بهتر است این service به‌روزرسانی شود تا کل آرایه KPIها بدون wrap اضافه عبور کند.
---
## جمع بندی نهایی
اگر بک‌اند یک summary کامل برای صفحه `yield-harvest` برگرداند، فرانت می‌تواند تمام کارت‌های صفحه را بدون mock و بدون محاسبه‌ی اضافه سمت کلاینت رندر کند.
بهترین قرارداد برای این صفحه:
- یک endpoint summary
- یک payload شامل 7 بلوک اصلی
- typeهای عددی برای chart/progress
- stringهای آماده نمایش برای متن‌ها، تاریخ‌ها و واحدها
این ساختار هم برای وضعیت فعلی فرانت کافی است، هم برای توسعه بعدی صفحه.