UPDATE
This commit is contained in:
@@ -0,0 +1,487 @@
|
||||
# Fertilization Recommendation Result API Spec
|
||||
|
||||
این فایل مشخص میکند که فرانتاند برای صفحه `SmartFertilizationRecommendation` دقیقاً چه خروجیای از بکاند نیاز دارد، مخصوصاً برای:
|
||||
|
||||
- Hero Card
|
||||
- ماشینحساب مساحت مزرعه
|
||||
- آنالیز ترکیبات
|
||||
- مراحل مصرف
|
||||
- نکات ایمنی
|
||||
- کودهای جایگزین
|
||||
- Bottom Sheet جزئیات
|
||||
|
||||
نکته مهم: برای ماشینحساب، فرانتاند **نباید** مقدار را از رشتههایی مثل `150 kg/ha` parse کند. بکاند باید مقادیر عددی استاندارد و مستقل برگرداند.
|
||||
|
||||
---
|
||||
|
||||
## هدف اصلی
|
||||
|
||||
برای اینکه ماشینحساب مقدار مصرف دقیق کار کند، بکاند باید علاوه بر متن نمایشی، **مقدار عددی پایه** را نیز برگرداند.
|
||||
|
||||
فرمول مورد نیاز فرانت:
|
||||
|
||||
```text
|
||||
مقدار کل = مقدار مصرف در هر متر مربع × مساحت مزرعه
|
||||
```
|
||||
|
||||
یا اگر واحد پایه بر حسب هکتار ارسال شود:
|
||||
|
||||
```text
|
||||
مقدار کل = مقدار مصرف در هکتار × مساحت (هکتار)
|
||||
```
|
||||
|
||||
اما پیشنهاد قطعی برای فرانت این است که بکاند هر دو را بدهد:
|
||||
|
||||
- `base_amount_per_hectare`
|
||||
- `base_amount_per_square_meter`
|
||||
|
||||
تا هیچ تبدیل واحدی در UI لازم نباشد.
|
||||
|
||||
---
|
||||
|
||||
## Endpoint پیشنهادی
|
||||
|
||||
```text
|
||||
POST /api/fertilization/recommend/
|
||||
```
|
||||
|
||||
یا اگر ساختار فعلی پروژه حفظ شود:
|
||||
|
||||
```text
|
||||
POST /api/fertilization-recommendation/recommend/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Request پیشنهادی
|
||||
|
||||
```json
|
||||
{
|
||||
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||||
"crop_id": "wheat",
|
||||
"growth_stage": "flowering",
|
||||
"area": {
|
||||
"value": 2.5,
|
||||
"unit": "hectare"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### توضیح فیلدهای Request
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `farm_uuid` | string | بله | شناسه مزرعه |
|
||||
| `crop_id` | string | بله | شناسه محصول |
|
||||
| `growth_stage` | string | بله | مرحله رشد محصول |
|
||||
| `area.value` | number | اختیاری | مساحت مزرعه برای محاسبه مستقیم مقدار کل |
|
||||
| `area.unit` | string | اختیاری | واحد مساحت؛ ترجیحاً `hectare` یا `square_meter` |
|
||||
|
||||
اگر `area` ارسال نشود، فرانت با دادههای پایه محاسبه را خودش انجام میدهد.
|
||||
|
||||
---
|
||||
|
||||
## Response پیشنهادی
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"recommendation_id": "fert-rec-001",
|
||||
"crop": {
|
||||
"id": "wheat",
|
||||
"name": "گندم"
|
||||
},
|
||||
"growth_stage": {
|
||||
"id": "flowering",
|
||||
"name": "گلدهی"
|
||||
},
|
||||
"primary_recommendation": {
|
||||
"fertilizer_code": "npk-20-20-20",
|
||||
"fertilizer_name": "کود کامل 20-20-20",
|
||||
"display_title": "کود کامل 20-20-20",
|
||||
"fertilizer_type": "NPK",
|
||||
"npk_ratio": {
|
||||
"n": 20,
|
||||
"p": 20,
|
||||
"k": 20,
|
||||
"label": "20-20-20"
|
||||
},
|
||||
"application_method": {
|
||||
"id": "foliar_fertigation",
|
||||
"label": "محلول پاشی / آب آبیاری"
|
||||
},
|
||||
"application_interval": {
|
||||
"value": 14,
|
||||
"unit": "day",
|
||||
"label": "هر 14 روز"
|
||||
},
|
||||
"dosage": {
|
||||
"base_amount_per_hectare": 150,
|
||||
"base_amount_per_square_meter": 0.015,
|
||||
"unit": "kg",
|
||||
"label": "150 کیلوگرم در هکتار",
|
||||
"calculation_basis": "product"
|
||||
},
|
||||
"total_amount": {
|
||||
"value": 375,
|
||||
"unit": "kg",
|
||||
"label": "375 کیلوگرم"
|
||||
},
|
||||
"reasoning": "این ترکیب برای مرحله گلدهی به دلیل نیاز متعادل به ازت، فسفر و پتاسیم پیشنهاد شده است.",
|
||||
"summary": "مناسب برای حفظ رشد رویشی و پشتیبانی از گلدهی"
|
||||
},
|
||||
"nutrient_analysis": {
|
||||
"macro": [
|
||||
{
|
||||
"key": "n",
|
||||
"name": "نیتروژن (N)",
|
||||
"value": 20,
|
||||
"unit": "percent",
|
||||
"description": "نیتروژن برای رشد رویشی و افزایش سطح برگ ضروری است."
|
||||
},
|
||||
{
|
||||
"key": "p",
|
||||
"name": "فسفر (P)",
|
||||
"value": 20,
|
||||
"unit": "percent",
|
||||
"description": "فسفر برای توسعه ریشه و انتقال انرژی اهمیت دارد."
|
||||
},
|
||||
{
|
||||
"key": "k",
|
||||
"name": "پتاسیم (K)",
|
||||
"value": 20,
|
||||
"unit": "percent",
|
||||
"description": "پتاسیم به کیفیت محصول و مقاومت به تنش کمک میکند."
|
||||
}
|
||||
],
|
||||
"micro": [
|
||||
{
|
||||
"key": "fe",
|
||||
"name": "آهن",
|
||||
"value": 0.5,
|
||||
"unit": "percent",
|
||||
"description": "آهن در تولید کلروفیل و جلوگیری از زردی موثر است."
|
||||
},
|
||||
{
|
||||
"key": "zn",
|
||||
"name": "روی",
|
||||
"value": 1,
|
||||
"unit": "percent",
|
||||
"description": "روی در رشد متعادل و فعالیت آنزیمها نقش دارد."
|
||||
}
|
||||
]
|
||||
},
|
||||
"application_guide": {
|
||||
"safety_warning": "هنگام محلول پاشی از دستکش و ماسک استفاده کنید و در ساعات خنک روز مصرف انجام شود.",
|
||||
"steps": [
|
||||
{
|
||||
"step_number": 1,
|
||||
"title": "آماده سازی",
|
||||
"description": "مقدار توصیه شده از کود را در یک سطل آب تمیز حل کنید."
|
||||
},
|
||||
{
|
||||
"step_number": 2,
|
||||
"title": "ترکیب",
|
||||
"description": "محلول را به مخزن اصلی سم پاش یا سیستم آبیاری اضافه کنید و خوب هم بزنید."
|
||||
},
|
||||
{
|
||||
"step_number": 3,
|
||||
"title": "مصرف",
|
||||
"description": "به صورت یکنواخت روی گیاه اسپری کنید یا در سیستم آبیاری تزریق نمایید."
|
||||
}
|
||||
]
|
||||
},
|
||||
"alternative_recommendations": [
|
||||
{
|
||||
"fertilizer_code": "npk-10-52-10",
|
||||
"fertilizer_name": "کود 10-52-10",
|
||||
"fertilizer_type": "NPK (فسفر بالا)",
|
||||
"usage_method": "محلول پاشی",
|
||||
"description": "برای تقویت ریشه و پشتیبانی از گلدهی در صورت نبود پیشنهاد اصلی مناسب است."
|
||||
},
|
||||
{
|
||||
"fertilizer_code": "npk-12-12-36",
|
||||
"fertilizer_name": "کود 12-12-36",
|
||||
"fertilizer_type": "NPK (پتاس بالا)",
|
||||
"usage_method": "تزریق در آبیاری",
|
||||
"description": "برای بهبود کیفیت محصول و افزایش پتاسیم قابل استفاده است."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای ضروری برای فرانت
|
||||
|
||||
### 1) اطلاعات اصلی پیشنهاد
|
||||
|
||||
این فیلدها برای Hero Card لازماند.
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `primary_recommendation.fertilizer_name` | string | بله | نام اصلی کود |
|
||||
| `primary_recommendation.display_title` | string | بهتر است | عنوان نمایشی اگر با نام اصلی فرق دارد |
|
||||
| `primary_recommendation.fertilizer_type` | string | بله | نوع کود مثل NPK |
|
||||
| `primary_recommendation.npk_ratio.label` | string | بله | متن آماده برای نمایش مثل `20-20-20` |
|
||||
| `primary_recommendation.npk_ratio.n` | number | بله | درصد نیتروژن |
|
||||
| `primary_recommendation.npk_ratio.p` | number | بله | درصد فسفر |
|
||||
| `primary_recommendation.npk_ratio.k` | number | بله | درصد پتاسیم |
|
||||
| `primary_recommendation.application_method.label` | string | بله | روش مصرف نمایشی |
|
||||
| `primary_recommendation.application_interval.label` | string | بله | فاصله مصرف نمایشی |
|
||||
| `primary_recommendation.reasoning` | string | بله | دلیل توصیه برای بخش توضیحات |
|
||||
|
||||
### 2) فیلدهای ضروری برای ماشینحساب
|
||||
|
||||
این بخش مهمترین قسمت برای بکاند است.
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `primary_recommendation.dosage.base_amount_per_hectare` | number | بله | مقدار پایه مصرف در هر هکتار |
|
||||
| `primary_recommendation.dosage.base_amount_per_square_meter` | number | بله | مقدار پایه مصرف در هر متر مربع |
|
||||
| `primary_recommendation.dosage.unit` | string | بله | واحد مقدار مصرف؛ مثل `kg` یا `liter` |
|
||||
| `primary_recommendation.dosage.label` | string | بله | متن آماده برای نمایش مثل `150 کیلوگرم در هکتار` |
|
||||
| `primary_recommendation.total_amount.value` | number | اختیاری | اگر بکاند بر اساس مساحت ورودی مقدار کل را حساب کند |
|
||||
| `primary_recommendation.total_amount.unit` | string | اختیاری | واحد مقدار کل |
|
||||
| `primary_recommendation.total_amount.label` | string | اختیاری | متن نمایشی مقدار کل |
|
||||
|
||||
### چرا `base_amount_per_square_meter` لازم است؟
|
||||
|
||||
چون شما گفتید ماشینحساب باید مقدار **کیلوگرم در هر متر مربع** را از بکاند بگیرد.
|
||||
|
||||
پس بکاند باید این مقدار را صریح برگرداند، نه اینکه فرانت از `kg/ha` خودش تبدیل کند.
|
||||
|
||||
نمونه:
|
||||
|
||||
```json
|
||||
{
|
||||
"base_amount_per_hectare": 150,
|
||||
"base_amount_per_square_meter": 0.015,
|
||||
"unit": "kg"
|
||||
}
|
||||
```
|
||||
|
||||
تبدیل مرجع:
|
||||
|
||||
```text
|
||||
1 hectare = 10,000 square meters
|
||||
150 kg/ha = 0.015 kg/m²
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای آنالیز ترکیبات
|
||||
|
||||
برای اینکه فرانت مجبور به parse کردن متن `npkRatio` نباشد، بکاند باید آنالیز را ساختارمند بفرستد.
|
||||
|
||||
### ماکرو
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `nutrient_analysis.macro[].key` | string | بله | کلید استاندارد مثل `n`, `p`, `k` |
|
||||
| `nutrient_analysis.macro[].name` | string | بله | نام نمایشی فارسی |
|
||||
| `nutrient_analysis.macro[].value` | number | بله | درصد عنصر |
|
||||
| `nutrient_analysis.macro[].unit` | string | بله | معمولاً `percent` |
|
||||
| `nutrient_analysis.macro[].description` | string | بهتر است | توضیح برای Bottom Sheet |
|
||||
|
||||
### ریزمغذیها
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `nutrient_analysis.micro[].key` | string | بله | مثل `fe`, `zn`, `mn`, `b` |
|
||||
| `nutrient_analysis.micro[].name` | string | بله | نام فارسی عنصر |
|
||||
| `nutrient_analysis.micro[].value` | number | بله | درصد عنصر |
|
||||
| `nutrient_analysis.micro[].unit` | string | بله | معمولاً `percent` |
|
||||
| `nutrient_analysis.micro[].description` | string | بهتر است | توضیح برای Bottom Sheet |
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای دستورالعمل مصرف
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `application_guide.safety_warning` | string | بله | متن هشدار ایمنی |
|
||||
| `application_guide.steps[].step_number` | number | بله | شماره مرحله |
|
||||
| `application_guide.steps[].title` | string | بله | عنوان مرحله |
|
||||
| `application_guide.steps[].description` | string | بله | توضیح مرحله |
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای کودهای جایگزین
|
||||
|
||||
| فیلد | نوع | اجباری | توضیح |
|
||||
|------|-----|--------|-------|
|
||||
| `alternative_recommendations[].fertilizer_code` | string | بله | شناسه یکتا |
|
||||
| `alternative_recommendations[].fertilizer_name` | string | بله | نام کود جایگزین |
|
||||
| `alternative_recommendations[].fertilizer_type` | string | بله | نوع کود |
|
||||
| `alternative_recommendations[].usage_method` | string | بله | روش مصرف |
|
||||
| `alternative_recommendations[].description` | string | بله | توضیح برای Bottom Sheet |
|
||||
|
||||
---
|
||||
|
||||
## فیلدهای لازم برای Bottom Sheet
|
||||
|
||||
برای باز شدن Bottom Sheet روی مواد غذایی و کودهای جایگزین، بهتر است توضیح آماده از بکاند بیاید.
|
||||
|
||||
| بخش | فیلد پیشنهادی |
|
||||
|-----|---------------|
|
||||
| مواد اصلی | `nutrient_analysis.macro[].description` |
|
||||
| ریزمغذیها | `nutrient_analysis.micro[].description` |
|
||||
| کود جایگزین | `alternative_recommendations[].description` |
|
||||
|
||||
این باعث میشود فرانت مجبور نباشد متنهای توضیحی hard-code کند.
|
||||
|
||||
---
|
||||
|
||||
## فرمت واحدها
|
||||
|
||||
پیشنهاد میشود بکاند از مقادیر استاندارد زیر استفاده کند:
|
||||
|
||||
### واحد مقدار کود
|
||||
|
||||
- `kg`
|
||||
- `gram`
|
||||
- `liter`
|
||||
- `milliliter`
|
||||
|
||||
### واحد مساحت
|
||||
|
||||
- `hectare`
|
||||
- `square_meter`
|
||||
|
||||
### واحد درصد عناصر
|
||||
|
||||
- `percent`
|
||||
|
||||
### واحد فاصله مصرف
|
||||
|
||||
- `day`
|
||||
- `week`
|
||||
|
||||
---
|
||||
|
||||
## قوانین پیشنهادی برای بکاند
|
||||
|
||||
### 1) متن نمایشی و مقدار عددی را با هم برگردانید
|
||||
|
||||
اشتباه:
|
||||
|
||||
```json
|
||||
{
|
||||
"amountPerHectare": "150 kg/ha"
|
||||
}
|
||||
```
|
||||
|
||||
صحیح:
|
||||
|
||||
```json
|
||||
{
|
||||
"dosage": {
|
||||
"base_amount_per_hectare": 150,
|
||||
"base_amount_per_square_meter": 0.015,
|
||||
"unit": "kg",
|
||||
"label": "150 کیلوگرم در هکتار"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2) هیچ داده مهمی فقط داخل `reasoning` دفن نشود
|
||||
|
||||
مواردی مثل:
|
||||
|
||||
- درصد N, P, K
|
||||
- درصد ریزمغذیها
|
||||
- مقدار مصرف پایه
|
||||
- روش مصرف
|
||||
|
||||
باید فیلد مستقل داشته باشند، نه فقط متن آزاد.
|
||||
|
||||
### 3) نام مرحله رشد و نام محصول را هم برگردانید
|
||||
|
||||
تا Header صفحه بدون lookup اضافه ساخته شود.
|
||||
|
||||
---
|
||||
|
||||
## حداقل خروجی لازم برای نسخه فعلی فرانت
|
||||
|
||||
اگر بکاند بخواهد فقط حداقل دادهی لازم را برگرداند، این ساختار minimum پیشنهاد میشود:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"crop": {
|
||||
"id": "wheat",
|
||||
"name": "گندم"
|
||||
},
|
||||
"growth_stage": {
|
||||
"id": "flowering",
|
||||
"name": "گلدهی"
|
||||
},
|
||||
"primary_recommendation": {
|
||||
"fertilizer_name": "کود کامل 20-20-20",
|
||||
"fertilizer_type": "NPK",
|
||||
"npk_ratio": {
|
||||
"n": 20,
|
||||
"p": 20,
|
||||
"k": 20,
|
||||
"label": "20-20-20"
|
||||
},
|
||||
"application_method": {
|
||||
"label": "محلول پاشی / آب آبیاری"
|
||||
},
|
||||
"application_interval": {
|
||||
"label": "هر 14 روز"
|
||||
},
|
||||
"dosage": {
|
||||
"base_amount_per_hectare": 150,
|
||||
"base_amount_per_square_meter": 0.015,
|
||||
"unit": "kg",
|
||||
"label": "150 کیلوگرم در هکتار"
|
||||
},
|
||||
"reasoning": "توضیحات توصیه"
|
||||
},
|
||||
"nutrient_analysis": {
|
||||
"macro": [
|
||||
{ "key": "n", "name": "نیتروژن (N)", "value": 20, "unit": "percent" },
|
||||
{ "key": "p", "name": "فسفر (P)", "value": 20, "unit": "percent" },
|
||||
{ "key": "k", "name": "پتاسیم (K)", "value": 20, "unit": "percent" }
|
||||
],
|
||||
"micro": []
|
||||
},
|
||||
"application_guide": {
|
||||
"safety_warning": "هشدار ایمنی",
|
||||
"steps": [
|
||||
{ "step_number": 1, "title": "آماده سازی", "description": "..." },
|
||||
{ "step_number": 2, "title": "ترکیب", "description": "..." },
|
||||
{ "step_number": 3, "title": "مصرف", "description": "..." }
|
||||
]
|
||||
},
|
||||
"alternative_recommendations": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## نتیجه نهایی
|
||||
|
||||
برای اینکه UI فعلی بدون parse کردن رشتهها و بدون hard-code اضافی درست کار کند، بکاند باید حداقل این موارد را صریح برگرداند:
|
||||
|
||||
1. نام کود
|
||||
2. نوع کود
|
||||
3. نسبت NPK به صورت عددی و متنی
|
||||
4. روش مصرف
|
||||
5. فاصله مصرف
|
||||
6. مقدار پایه در هکتار
|
||||
7. مقدار پایه در متر مربع
|
||||
8. واحد مقدار مصرف
|
||||
9. استدلال توصیه
|
||||
10. آنالیز ماکرو و ریزمغذیها به صورت ساختارمند
|
||||
11. هشدار ایمنی
|
||||
12. مراحل مصرف
|
||||
13. کودهای جایگزین با توضیح
|
||||
|
||||
اگر خواستی، قدم بعدی میتوانم همین فایل را به یک قرارداد نهایی هماهنگ با TypeScript interface های `src/libs/api/services/fertilizationRecommendationService.ts` هم تبدیل کنم.
|
||||
@@ -4,11 +4,6 @@
|
||||
*/
|
||||
|
||||
import { apiClient } from "../client";
|
||||
import type {
|
||||
RecommendationTaskInitResponse,
|
||||
RecommendationTaskStatusResponse,
|
||||
} from "./recommendationTask";
|
||||
import { normalizeRecommendationTaskStatus } from "./recommendationTask";
|
||||
|
||||
const PREFIX = "/api/fertilization-recommendation";
|
||||
const RECOMMEND_PREFIX = "/api/fertilization";
|
||||
@@ -40,12 +35,95 @@ export interface FertilizationConfigResponse {
|
||||
cropOptions: CropOption[];
|
||||
}
|
||||
|
||||
export interface FertilizationPlan {
|
||||
npkRatio: string;
|
||||
amountPerHectare: string;
|
||||
applicationMethod: string;
|
||||
applicationInterval: string;
|
||||
export interface FertilizationNpkRatio {
|
||||
n: number;
|
||||
p: number;
|
||||
k: number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface FertilizationApplicationMethod {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface FertilizationApplicationInterval {
|
||||
label: string;
|
||||
unit: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface FertilizationDosage {
|
||||
label: string;
|
||||
unit: string;
|
||||
calculation_basis: string;
|
||||
base_amount_per_hectare: number;
|
||||
base_amount_per_square_meter: number;
|
||||
}
|
||||
|
||||
export interface FertilizationPrimaryRecommendation {
|
||||
fertilizer_code: string;
|
||||
fertilizer_name: string;
|
||||
display_title: string;
|
||||
fertilizer_type: string;
|
||||
reasoning: string;
|
||||
summary: string;
|
||||
npk_ratio: FertilizationNpkRatio;
|
||||
application_method: FertilizationApplicationMethod;
|
||||
application_interval: FertilizationApplicationInterval;
|
||||
dosage: FertilizationDosage;
|
||||
}
|
||||
|
||||
export interface FertilizationNutrientItem {
|
||||
key: string;
|
||||
name: string;
|
||||
unit: string;
|
||||
description: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface FertilizationApplicationStep {
|
||||
step_number: number;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface FertilizationApplicationGuide {
|
||||
safety_warning: string;
|
||||
steps: FertilizationApplicationStep[];
|
||||
}
|
||||
|
||||
export interface FertilizationAlternativeRecommendation {
|
||||
fertilizer_code: string;
|
||||
fertilizer_name: string;
|
||||
fertilizer_type: string;
|
||||
usage_method: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface FertilizationSection {
|
||||
title: string;
|
||||
icon: string;
|
||||
type: string;
|
||||
content?: string;
|
||||
items?: string[];
|
||||
applicationMethod?: string;
|
||||
fertilizerType?: string;
|
||||
validityPeriod?: string;
|
||||
amount?: string;
|
||||
expandableExplanation?: string;
|
||||
timing?: string;
|
||||
}
|
||||
|
||||
export interface FertilizationRecommendationResult {
|
||||
primary_recommendation: FertilizationPrimaryRecommendation;
|
||||
nutrient_analysis: {
|
||||
macro: FertilizationNutrientItem[];
|
||||
micro: FertilizationNutrientItem[];
|
||||
};
|
||||
application_guide: FertilizationApplicationGuide;
|
||||
alternative_recommendations: FertilizationAlternativeRecommendation[];
|
||||
sections: FertilizationSection[];
|
||||
}
|
||||
|
||||
export interface FertilizationRecommendPayload {
|
||||
@@ -58,17 +136,9 @@ export interface FertilizationRecommendPayload {
|
||||
waterEC?: string;
|
||||
}
|
||||
|
||||
export interface FertilizationRecommendationResult {
|
||||
plan: FertilizationPlan;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export type FertilizationRecommendResponse =
|
||||
| FertilizationRecommendationResult
|
||||
| RecommendationTaskInitResponse;
|
||||
|
||||
interface ApiResponse<T> {
|
||||
status: string;
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
@@ -77,26 +147,6 @@ async function unwrap<T>(promise: Promise<ApiResponse<T>>): Promise<T> {
|
||||
return res.data;
|
||||
}
|
||||
|
||||
function normalizeTaskInitResponse(
|
||||
task: RecommendationTaskInitResponse,
|
||||
): RecommendationTaskInitResponse {
|
||||
return {
|
||||
...task,
|
||||
status: normalizeRecommendationTaskStatus(task.status),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeRecommendationResult(
|
||||
result: FertilizationRecommendationResult,
|
||||
): FertilizationRecommendationResult {
|
||||
return result.status
|
||||
? {
|
||||
...result,
|
||||
status: normalizeRecommendationTaskStatus(result.status),
|
||||
}
|
||||
: result;
|
||||
}
|
||||
|
||||
export const fertilizationRecommendationService = {
|
||||
getConfig(farmUuid: string): Promise<FertilizationConfigResponse> {
|
||||
return unwrap(
|
||||
@@ -108,39 +158,12 @@ export const fertilizationRecommendationService = {
|
||||
|
||||
recommend(
|
||||
payload?: FertilizationRecommendPayload,
|
||||
): Promise<FertilizationRecommendResponse> {
|
||||
): Promise<FertilizationRecommendationResult> {
|
||||
return unwrap(
|
||||
apiClient.post<ApiResponse<FertilizationRecommendResponse>>(
|
||||
apiClient.post<ApiResponse<FertilizationRecommendationResult>>(
|
||||
`${RECOMMEND_PREFIX}/recommend/`,
|
||||
payload ?? {},
|
||||
),
|
||||
).then((response) =>
|
||||
"task_id" in response
|
||||
? normalizeTaskInitResponse(response)
|
||||
: normalizeRecommendationResult(response),
|
||||
);
|
||||
},
|
||||
|
||||
getRecommendStatus(
|
||||
taskId: string,
|
||||
farmUuid: string,
|
||||
): Promise<
|
||||
RecommendationTaskStatusResponse<FertilizationRecommendationResult>
|
||||
> {
|
||||
return unwrap(
|
||||
apiClient.get<
|
||||
ApiResponse<
|
||||
RecommendationTaskStatusResponse<FertilizationRecommendationResult>
|
||||
>
|
||||
>(
|
||||
`${PREFIX}/recommend/status/${taskId}/?farm_uuid=${encodeURIComponent(farmUuid)}`,
|
||||
),
|
||||
).then((response) => ({
|
||||
...response,
|
||||
status: normalizeRecommendationTaskStatus(response.status),
|
||||
result: response.result
|
||||
? normalizeRecommendationResult(response.result)
|
||||
: undefined,
|
||||
}));
|
||||
},
|
||||
};
|
||||
|
||||
+653
-194
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user