From 5145217481a867757e4c944adb0839252bdc34fe Mon Sep 17 00:00:00 2001 From: Akira Date: Mon, 2 Mar 2026 10:50:56 +0900 Subject: [PATCH] =?UTF-8?q?=E6=96=BD=E8=82=A5=E8=A8=88=E7=94=BB=E3=81=AE?= =?UTF-8?q?=E8=A8=88=E7=AE=97=E8=A8=AD=E5=AE=9A=E3=82=92=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E3=83=BB=E5=BE=A9=E5=85=83=E3=81=97=E3=80=81=E6=9C=AA=E5=85=A5?= =?UTF-8?q?=E5=8A=9B=E5=9C=83=E5=A0=B4=E3=81=AE=E3=81=BF=E8=A8=88=E7=AE=97?= =?UTF-8?q?=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FertilizationPlanにcalc_settings JSONFieldを追加(migration 0004) - 編集画面を開くと前回の計算方式・パラメータが復元される - 「未入力圃場のみ」チェックで既存値を保持したまま新規圃場だけ計算可能 Co-Authored-By: Claude Sonnet 4.6 --- .../0004_fertilizationplan_calc_settings.py | 16 +++++++ backend/apps/fertilizer/models.py | 1 + backend/apps/fertilizer/serializers.py | 4 +- .../_components/FertilizerEditPage.tsx | 47 +++++++++++++++---- frontend/src/types/index.ts | 1 + 5 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 backend/apps/fertilizer/migrations/0004_fertilizationplan_calc_settings.py diff --git a/backend/apps/fertilizer/migrations/0004_fertilizationplan_calc_settings.py b/backend/apps/fertilizer/migrations/0004_fertilizationplan_calc_settings.py new file mode 100644 index 0000000..ba475e4 --- /dev/null +++ b/backend/apps/fertilizer/migrations/0004_fertilizationplan_calc_settings.py @@ -0,0 +1,16 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fertilizer', '0003_distributionplan_distributiongroup_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='fertilizationplan', + name='calc_settings', + field=models.JSONField(blank=True, default=list, verbose_name='計算設定'), + ), + ] diff --git a/backend/apps/fertilizer/models.py b/backend/apps/fertilizer/models.py index b50da4c..e758521 100644 --- a/backend/apps/fertilizer/models.py +++ b/backend/apps/fertilizer/models.py @@ -34,6 +34,7 @@ class FertilizationPlan(models.Model): 'plans.Variety', on_delete=models.PROTECT, related_name='fertilization_plans', verbose_name='品種' ) + calc_settings = models.JSONField(default=list, blank=True, verbose_name='計算設定') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) diff --git a/backend/apps/fertilizer/serializers.py b/backend/apps/fertilizer/serializers.py index 7308b07..02e4191 100644 --- a/backend/apps/fertilizer/serializers.py +++ b/backend/apps/fertilizer/serializers.py @@ -31,7 +31,7 @@ class FertilizationPlanSerializer(serializers.ModelSerializer): model = FertilizationPlan fields = [ 'id', 'name', 'year', 'variety', 'variety_name', 'crop_name', - 'entries', 'field_count', 'fertilizer_count', 'created_at', 'updated_at' + 'calc_settings', 'entries', 'field_count', 'fertilizer_count', 'created_at', 'updated_at' ] def get_variety_name(self, obj): @@ -53,7 +53,7 @@ class FertilizationPlanWriteSerializer(serializers.ModelSerializer): class Meta: model = FertilizationPlan - fields = ['id', 'name', 'year', 'variety', 'entries'] + fields = ['id', 'name', 'year', 'variety', 'calc_settings', 'entries'] def create(self, validated_data): entries_data = validated_data.pop('entries', []) diff --git a/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx b/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx index 1701ef9..0b2d029 100644 --- a/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx +++ b/frontend/src/app/fertilizer/_components/FertilizerEditPage.tsx @@ -91,7 +91,13 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { const fertIds = Array.from(new Set(plan.entries.map((e) => e.fertilizer))); const ferts = fertsRes.data.filter((f: Fertilizer) => fertIds.includes(f.id)); setPlanFertilizers(ferts); - setCalcSettings(ferts.map((f: Fertilizer) => ({ fertilizer_id: f.id, method: 'per_tan' as CalcMethod, param: '' }))); + // 保存済み計算設定を復元、なければデフォルト値 + setCalcSettings(ferts.map((f: Fertilizer) => { + const saved = plan.calc_settings?.find((s) => s.fertilizer_id === f.id); + return saved + ? { fertilizer_id: f.id, method: saved.method as CalcMethod, param: saved.param } + : { fertilizer_id: f.id, method: 'per_tan' as CalcMethod, param: '' }; + })); const fieldIds = Array.from(new Set(plan.entries.map((e) => e.field))); const fields = fieldsRes.data.filter((f: Field) => fieldIds.includes(f.id)); @@ -172,17 +178,29 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { setAdjusted((prev) => { const next = { ...prev }; delete next[id]; return next; }); }; + const [calcNewOnly, setCalcNewOnly] = useState(true); + // ─── 自動計算 const runCalc = async (setting: CalcSetting) => { if (!setting.param) return alert('パラメータを入力してください'); if (selectedFields.length === 0) return alert('対象圃場を選択してください'); + const targetFields = calcNewOnly + ? selectedFields.filter((f) => { + const hasAdjusted = adjusted[f.id]?.[setting.fertilizer_id] !== undefined; + const hasCalc = calcMatrix[f.id]?.[setting.fertilizer_id] !== undefined; + return !hasAdjusted && !hasCalc; + }) + : selectedFields; + + if (targetFields.length === 0) return alert('未入力の圃場がありません。「全圃場」で実行してください。'); + try { const res = await api.post('/fertilizer/calculate/', { method: setting.method, param: parseFloat(setting.param), fertilizer_id: setting.fertilizer_id, - field_ids: selectedFields.map((f) => f.id), + field_ids: targetFields.map((f) => f.id), }); const results: { field_id: number; bags: number }[] = res.data; @@ -311,7 +329,7 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) { setSaving(true); try { - const payload = { name, year, variety: varietyId, entries }; + const payload = { name, year, variety: varietyId, calc_settings: calcSettings, entries }; if (isNew) { await api.post('/fertilizer/plans/', payload); } else { @@ -481,12 +499,23 @@ export default function FertilizerEditPage({ planId }: { planId?: number }) {

自動計算設定

- +
+ + +
{planFertilizers.length === 0 ? (

肥料を追加してください

diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index b722e9f..82229ba 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -84,6 +84,7 @@ export interface FertilizationPlan { variety: number; variety_name: string; crop_name: string; + calc_settings: { fertilizer_id: number; method: string; param: string }[]; entries: FertilizationEntry[]; field_count: number; fertilizer_count: number;