diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..24222d0 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(docker-compose exec:*)", + "Bash(python -c:*)" + ] + } +} diff --git a/CLAUDE.md b/CLAUDE.md index cb0f8ad..437350e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -70,8 +70,7 @@ keinasystem_t02/ │ │ └── urls.py │ ├── plans/ # 作付け計画アプリ │ │ ├── models.py # Plan, Crop, Variety -│ │ ├── views.py # 作付け計画API、集計API -│ │ └── management/commands/init_crops.py # 初期データ投入 +│ │ └── views.py # 作付け計画API、集計API │ └── reports/ # 申請書生成アプリ │ ├── views.py # PDF生成API │ └── templates/ # PDF用HTMLテンプレート @@ -102,7 +101,12 @@ OfficialKyosaiField (共済マスタ) └── 31区画(水稲共済細目書用) OfficialChusankanField (中山間マスタ) -└── 71区画(中山間地域等直接支払交付金用) +├── 71区画(中山間地域等直接支払交付金用) +└── 17フィールド: c_id, chusankan_flag, oaza, aza, chiban, + branch_num, land_type, area, planting_area, + original_crop, manager, owner, slope, + base_amount, steep_slope_addition, smart_agri_addition, + payment_amount Plan (作付け計画) ├── field (FK to Field) @@ -201,6 +205,27 @@ Variety (品種マスタ) 2. **エラーハンドリング**: フロントエンドでの統一的なエラー表示が未実装 3. **テスト**: 自動テストが未実装(Phase 2で追加予定) 4. **パフォーマンス**: N+1問題が一部存在(現状は問題ないが、データ増加時に対応必要) +5. **セキュリティ**: DEFAULT_PERMISSION_CLASSES が AllowAny → IsAuthenticated に変更必要 +6. **settings.py**: LANGUAGE_CODE と TIME_ZONE が二重定義されている(前の定義を削除) +7. **PDF生成バグ**: reports/views.py で variety が null 時にクラッシュ(null チェック未実装) +8. **init_crops.py**: 不正データを含むため削除予定 +9. **PDF帳票**: 現在のテンプレートは仕様と不一致(中国語混入、セクション形式、@page未設定)→ 再設計必要 +10. **中山間モデル**: 現在6フィールド → 17フィールドに拡張必要(E-1c) + +### 🔜 次の実装タスク(優先順) + +1. **A-8**: 圃場詳細に共済/中山間情報表示(最優先) +2. **D-1〜D-4**: バグ修正(null crash, settings二重定義, AllowAny→IsAuthenticated, init_crops削除) +3. **E-1**: PDF帳票フォーマット再設計(中山間モデル拡張含む) +4. **A-3**: 前年度コピーボタン(Frontend) +5. **A-4**: 品種のインライン追加・削除 +6. **A-5**: PDFプレビュー機能 +7. **A-6**: エクスポート機能(サーバー移行時のデータ移動用) +8. **A-2**: チェックボックス・一括操作 +9. **A-1**: ダッシュボード画面 +10. **A-7**: 検索・フィルタ + +詳細は `document/06_ドキュメントvs実装_差異レポート.md` を参照 ### 📅 次のマイルストーン(Phase 2) @@ -273,6 +298,7 @@ docker-compose exec backend python manage.py migrate - **データモデル詳細**: `document/03_データ仕様書.md` - **画面設計**: `document/04_画面設計書.md` - **実装手順**: `document/00_Gemini向け統合指示書.md` +- **差異レポート・タスク一覧**: `document/06_ドキュメントvs実装_差異レポート.md` --- @@ -288,4 +314,5 @@ docker-compose exec backend python manage.py migrate ## 📝 更新履歴 +- 2026-02-17: ドキュメント一斉更新(差異レポートA〜E反映、CSV→PDF統一、M:N関係、中山間モデル17列化、インライン編集方式、Navbar追加、既知の課題・次タスク一覧追加) - 2026-02-16: 初版作成(ハイブリッドアプローチの方針決定) diff --git a/backend/apps/plans/management/commands/init_crops.py b/backend/apps/plans/management/commands/init_crops.py deleted file mode 100644 index ade6e90..0000000 --- a/backend/apps/plans/management/commands/init_crops.py +++ /dev/null @@ -1,38 +0,0 @@ -from django.core.management.base import BaseCommand -from apps.plans.models import Crop, Variety - - -class Command(BaseCommand): - help = 'Initialize crops and varieties master data' - - def handle(self, *args, **options): - crops_data = [ - { - 'name': '水稲', - 'varieties': ['コシヒカリ', 'ひとめぼれ', 'あきたこまち', 'つや姫', 'oniai'] - }, - { - 'name': '大豆', - 'varieties': ['タマホマレ', 'エンレイ', 'ミヤギром'] - }, - { - 'name': '小麦', - 'varieties': ['キタノカオリ', 'ホウライ'] - }, - { - 'name': 'そば', - 'varieties': ['信濃一号', 'はるか'] - }, - { - 'name': 'とうきび', - 'varieties': ['ゴールdent'] - }, - ] - - for crop_data in crops_data: - crop, _ = Crop.objects.get_or_create(name=crop_data['name']) - for variety_name in crop_data['varieties']: - Variety.objects.get_or_create(crop=crop, name=variety_name) - self.stdout.write(f'{crop.name}: {len(crop_data["varieties"])} varieties') - - self.stdout.write(self.style.SUCCESS('Successfully initialized crops and varieties')) diff --git a/backend/apps/reports/views.py b/backend/apps/reports/views.py index 5ef7cbd..0d2669c 100644 --- a/backend/apps/reports/views.py +++ b/backend/apps/reports/views.py @@ -1,4 +1,3 @@ -from django.shortcuts import render from django.template.loader import render_to_string from django.http import HttpResponse from weasyprint import HTML @@ -8,25 +7,25 @@ from apps.plans.models import Plan def generate_kyosai_pdf(request, year): kyosai_fields = OfficialKyosaiField.objects.all() - + data = [] for kyosai in kyosai_fields: related_fields = kyosai.fields.all() plans = Plan.objects.filter(field__in=related_fields, year=year) - + crops = {} total_area = 0 for plan in plans: - crop_name = plan.crop.name + crop_name = plan.crop.name if plan.crop else '未設定' if crop_name not in crops: crops[crop_name] = { 'name': crop_name, - 'variety': plan.variety.name, + 'variety': plan.variety.name if plan.variety else '', 'count': 0 } crops[crop_name]['count'] += 1 total_area += float(plan.field.area_tan) - + data.append({ 'kyosai': kyosai, 'fields': related_fields, @@ -34,14 +33,14 @@ def generate_kyosai_pdf(request, year): 'total_area': total_area, 'field_count': related_fields.count() }) - + html_string = render_to_string('reports/kyosai_template.html', { 'year': year, 'data': data }) - + pdf = HTML(string=html_string).write_pdf() - + response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = f'attachment; filename="kyosai_{year}.pdf"' return response @@ -49,25 +48,25 @@ def generate_kyosai_pdf(request, year): def generate_chusankan_pdf(request, year): chusankan_fields = OfficialChusankanField.objects.all() - + data = [] for chusankan in chusankan_fields: related_fields = chusankan.fields.all() plans = Plan.objects.filter(field__in=related_fields, year=year) - + crops = {} total_area = 0 for plan in plans: - crop_name = plan.crop.name + crop_name = plan.crop.name if plan.crop else '未設定' if crop_name not in crops: crops[crop_name] = { 'name': crop_name, - 'variety': plan.variety.name, + 'variety': plan.variety.name if plan.variety else '', 'count': 0 } crops[crop_name]['count'] += 1 total_area += float(plan.field.area_tan) - + data.append({ 'chusankan': chusankan, 'fields': related_fields, @@ -75,14 +74,14 @@ def generate_chusankan_pdf(request, year): 'total_area': total_area, 'field_count': related_fields.count() }) - + html_string = render_to_string('reports/chusankan_template.html', { 'year': year, 'data': data }) - + pdf = HTML(string=html_string).write_pdf() - + response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = f'attachment; filename="chusankan_{year}.pdf"' return response diff --git a/backend/keinasystem/settings.py b/backend/keinasystem/settings.py index 677fca0..7d1d492 100644 --- a/backend/keinasystem/settings.py +++ b/backend/keinasystem/settings.py @@ -110,9 +110,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/5.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'ja' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Tokyo' USE_I18N = True @@ -134,7 +134,7 @@ REST_FRAMEWORK = { 'rest_framework_simplejwt.authentication.JWTAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( - 'rest_framework.permissions.AllowAny', + 'rest_framework.permissions.IsAuthenticated', ), } @@ -148,7 +148,3 @@ CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", "http://127.0.0.1:3000", ] - -LANGUAGE_CODE = 'ja' - -TIME_ZONE = 'Asia/Tokyo' diff --git a/document/00_Gemini向け統合指示書.md b/document/00_Gemini向け統合指示書.md index 1fbc5fb..8d7a9ec 100644 --- a/document/00_Gemini向け統合指示書.md +++ b/document/00_Gemini向け統合指示書.md @@ -19,14 +19,14 @@ - PCで登録・編集、スマホで参照 ### 主要機能(Phase 1 / MVP) -1. 作付け計画の一覧表示・編集 -2. 水稲共済細目書のCSV出力 -3. 中山間交付金申請書のCSV出力 +1. 作付け計画の一覧表示・インライン編集 +2. 水稲共済細目書のPDF出力 +3. 中山間交付金申請書のPDF出力 4. 前年度作付けのコピー機能 5. 圃場情報のスマホ参照 ### 技術スタック -- **バックエンド**: Django 5.0 + Django REST Framework + GeoDjango +- **バックエンド**: Django 5.2 + Django REST Framework + GeoDjango - **フロントエンド**: Next.js 14 (App Router) + Tailwind CSS - **データベース**: PostgreSQL 16 + PostGIS 3.4 - **インフラ**: Docker Compose @@ -49,8 +49,8 @@ ### 3. データ仕様書.md - 3種類のデータ(実圃場、共済マスタ、中山間マスタ)の関係 -- 紐付けロジック(M:1関係)の詳細 -- 申請書CSV出力のアルゴリズム +- 紐付けロジック(M:N関係)の詳細 +- 申請書PDF出力のアルゴリズム - **👉 読むべき理由**: データモデルの設計ミスは後から修正困難 ### 4. 画面設計書.md @@ -149,7 +149,7 @@ volumes: #### backend/requirements.txt ```txt -Django==5.0 +Django==5.2 djangorestframework==3.14 django-cors-headers==4.3 psycopg2-binary==2.9 @@ -227,25 +227,36 @@ from django.contrib.gis.db import models class OfficialKyosaiField(models.Model): """共済マスタ(水稲共済細目用.ods)""" - k_num = models.IntegerField("耕地番号") - s_num = models.IntegerField("分筆番号") + k_num = models.CharField("耕地番号", max_length=20) + s_num = models.CharField("分筆番号", max_length=20, blank=True) address = models.CharField("地名地番", max_length=200) kanji_name = models.CharField("漢字地名", max_length=200) - area = models.FloatField("本地面積(m2)") - + area = models.IntegerField("本地面積(m2)") + class Meta: unique_together = [['k_num', 's_num']] ordering = ['k_num', 's_num'] class OfficialChusankanField(models.Model): - """中山間マスタ(中山間.ods)""" - c_id = models.IntegerField("ID", unique=True) + """中山間マスタ(中山間.ods)- 17列全て保存""" + c_id = models.CharField("ID", max_length=20, unique=True) + chusankan_flag = models.CharField("中山間", max_length=10, blank=True) oaza = models.CharField("大字", max_length=100) aza = models.CharField("字", max_length=100) - chiban = models.IntegerField("地番") + chiban = models.CharField("地番", max_length=50) + branch_num = models.CharField("枝番", max_length=20, blank=True) + land_type = models.CharField("地目", max_length=20, blank=True) area = models.IntegerField("農地面積(m2)") + planting_area = models.IntegerField("植栽面積(m2)", null=True, blank=True) + original_crop = models.CharField("作付け品目", max_length=100, blank=True) + manager = models.CharField("協定管理者", max_length=100, blank=True) + owner = models.CharField("所有者", max_length=100, blank=True) + slope = models.CharField("傾斜度", max_length=20, blank=True) + base_amount = models.IntegerField("基本金額", null=True, blank=True) + steep_slope_addition = models.IntegerField("超急傾斜加算額", null=True, blank=True) + smart_agri_addition = models.IntegerField("スマート農業加算額", null=True, blank=True) payment_amount = models.IntegerField("交付金額", null=True, blank=True) - + class Meta: ordering = ['c_id'] @@ -257,22 +268,19 @@ class Field(models.Model): area_m2 = models.IntegerField("面積(m2)") # area_tan * 1000 owner_name = models.CharField("地主", max_length=100) - # 紐付けキー(raw値) - raw_kyosai_k_num = models.IntegerField("細目_耕地番号") - raw_kyosai_s_num = models.IntegerField("細目_分筆番号") - raw_chusankan_id = models.IntegerField("中山間_ID", null=True, blank=True) - - # 外部キー(紐付け済み) - kyosai_field = models.ForeignKey( - OfficialKyosaiField, - on_delete=models.SET_NULL, - null=True, + # グループ・表示順 + group_name = models.CharField("グループ名", max_length=100, blank=True) + display_order = models.IntegerField("表示順", default=0) + + # M:N紐付け(1つの圃場が複数の申請区画に紐づく場合がある) + kyosai_fields = models.ManyToManyField( + OfficialKyosaiField, + blank=True, related_name='fields' ) - chusankan_field = models.ForeignKey( - OfficialChusankanField, - on_delete=models.SET_NULL, - null=True, + chusankan_fields = models.ManyToManyField( + OfficialChusankanField, + blank=True, related_name='fields' ) @@ -347,97 +355,52 @@ def import_kyosai_master(request): @api_view(['POST']) def import_yoshida_fields(request): - """吉田農地台帳のインポート(紐付け処理含む)""" + """吉田農地台帳のインポート(M:N紐付け処理含む)""" file = request.FILES['file'] df = pd.read_excel(file, engine='odf') - + for _, row in df.iterrows(): - # 共済マスタとの紐付け - try: - kyosai = OfficialKyosaiField.objects.get( - k_num=row['細目_耕地番号'], - s_num=row['細目_分筆番号'] - ) - except OfficialKyosaiField.DoesNotExist: - kyosai = None - - # 中山間マスタとの紐付け - chusankan = None - if pd.notna(row['中山間_ID']): - try: - chusankan = OfficialChusankanField.objects.get( - c_id=int(row['中山間_ID']) - ) - except OfficialChusankanField.DoesNotExist: - pass - # 実圃場を作成 - Field.objects.update_or_create( + field, created = Field.objects.update_or_create( name=row['名称'], defaults={ 'address': row['住所'], 'area_tan': row['面積(反)'], 'area_m2': int(row['面積(反)'] * 1000), 'owner_name': row['地主'], - 'raw_kyosai_k_num': row['細目_耕地番号'], - 'raw_kyosai_s_num': row['細目_分筆番号'], - 'raw_chusankan_id': int(row['中山間_ID']) if pd.notna(row['中山間_ID']) else None, - 'kyosai_field': kyosai, - 'chusankan_field': chusankan, } ) - + + # 共済マスタとのM:N紐付け + try: + kyosai = OfficialKyosaiField.objects.get( + k_num=str(row['細目_耕地番号']), + s_num=str(row['細目_分筆番号']) + ) + field.kyosai_fields.add(kyosai) + except OfficialKyosaiField.DoesNotExist: + pass + + # 中山間マスタとのM:N紐付け + if pd.notna(row.get('中山間_ID')): + try: + chusankan = OfficialChusankanField.objects.get( + c_id=str(int(row['中山間_ID'])) + ) + field.chusankan_fields.add(chusankan) + except OfficialChusankanField.DoesNotExist: + pass + return Response({'status': 'success', 'imported': len(df)}) ``` ### Step 5: 作付け計画API(Day 5) -#### 作物・品種の初期データ投入 +#### 作物・品種マスタについて -**apps/plans/management/commands/init_crops.py** -```python -from django.core.management.base import BaseCommand -from apps.plans.models import Crop, Variety +初期データの自動投入は行わない。作物・品種はDjango管理画面またはUIから手動で登録する運用とする。 -class Command(BaseCommand): - help = '作物・品種マスタの初期データを投入' - - def handle(self, *args, **options): - # 作物マスタと品種 - crops_data = { - '米': ['にこまる', 'たちはるか', 'たちはるか(特栽)'], - 'トウモロコシ': [], - 'エンドウ': ['久留米豊'], - '野菜': [], - 'その他': [ - '完全休耕', - '緑肥(ヘアリーベッチ)', - '緑肥(レンゲ)', - '景観作物(コスモス)', - '景観作物(ヒマワリ)' - ] - } - - for crop_name, varieties in crops_data.items(): - crop, created = Crop.objects.get_or_create(name=crop_name) - if created: - self.stdout.write(f'作物「{crop_name}」を作成') - - for variety_name in varieties: - variety, created = Variety.objects.get_or_create( - crop=crop, - name=variety_name - ) - if created: - self.stdout.write(f' 品種「{variety_name}」を追加') - - self.stdout.write(self.style.SUCCESS('初期データ投入完了')) -``` - -**実行:** -```bash -docker-compose exec backend python manage.py init_crops -``` +主な作物: 米、トウモロコシ、エンドウ、野菜、その他 #### apps/plans/views.py ```python @@ -921,23 +884,16 @@ export default function ReportsPage() { ## ⚠️ 重要な実装上の注意点 ### 1. データベース設計 -- **面積単位**: DB内部は全て `m2` で保存、表示時に `反` に変換 -- **紐付けキー**: `raw_*` フィールドと外部キー `*_field` の両方を持つ -- **ユニーク制約**: `(field, year)` で作付け計画は1つまで +- **面積単位**: DB内部は `area_m2`(IntegerField)で保存、表示用に `area_tan`(DecimalField)も保持。1反=1000m2 +- **紐付け**: Field ↔ OfficialKyosaiField、Field ↔ OfficialChusankanField は **M:N**(ManyToManyField) +- **ユニーク制約**: `(field, year)` で作付け計画は1つまで、`(k_num, s_num)` で共済区画は一意 - **品種マスタ**: `(crop, name)` で一意制約 ### 2. 作物・品種の統一 - **すべての作物で品種選択UIは統一**: 作物による操作の違いなし - **「作付けしない」系も特別扱いしない**: 「その他」という作物に統一 - **品種の追加**: その場で追加可能、データベースに永続化 -- **初期データ**: - ``` - 米: にこまる、たちはるか、たちはるか(特栽) - トウモロコシ: (ユーザーが追加) - エンドウ: 久留米豊 - 野菜: (ユーザーが追加) - その他: 完全休耕、緑肥(ヘアリーベッチ)、緑肥(レンゲ)、景観作物(コスモス)、景観作物(ヒマワリ) - ``` +- **初期データ**: なし(管理画面またはUIから登録する運用) ### 3. 集計サイドバー - **リアルタイム更新**: 作付け計画を保存するたびに自動更新 diff --git a/document/01_プロダクトビジョン.md b/document/01_プロダクトビジョン.md index 5e942e8..99b3822 100644 --- a/document/01_プロダクトビジョン.md +++ b/document/01_プロダクトビジョン.md @@ -13,7 +13,7 @@ 2. **実圃場と申請区画のずれを管理する** - 実際に作業する圃場(39筆)と、申請書上の区画(共済31区画、中山間71区画)が異なる - - 複数の実圃場が1つの申請区画に紐づく関係(M:1)を明示的に管理 + - 実圃場と申請区画の紐づき関係(M:N)を明示的に管理 - 紐付けは半自動化するが、手動修正も可能にする 3. **将来の拡張を見据えた設計** @@ -95,7 +95,7 @@ **パフォーマンス:** - 圃場一覧の表示: 1秒以内 -- 申請書CSVの生成: 3秒以内 +- 申請書PDFの生成: 3秒以内 - スマホでの圃場詳細表示: 2秒以内 --- @@ -140,7 +140,7 @@ **Phase 1(MVP): 2025年2月まで** - 作付け計画の登録・編集 -- 申請書(水稲共済・中山間)のCSV出力 +- 申請書(水稲共済・中山間)のPDF出力 - 圃場一覧の参照(PC/スマホ) **Phase 2: 2025年3月~** diff --git a/document/03_データ仕様書.md b/document/03_データ仕様書.md index d48319c..b2b596b 100644 --- a/document/03_データ仕様書.md +++ b/document/03_データ仕様書.md @@ -1,5 +1,8 @@ # データ仕様書 +> **最終更新**: 2026-02-16 +> **変更履歴**: M:N関係に更新、中山間モデル全17列対応、面積単位統一、帳票仕様追加 + ## 📊 データ構造の全体像 このシステムで扱うデータは3種類: @@ -9,53 +12,80 @@ 3. **中山間マスタ**(中山間.ods)- 申請書用の区画 **紐付けの関係:** -- 実圃場 → 共済区画: **M対1**(複数の実圃場が1つの共済区画に対応) -- 実圃場 → 中山間区画: **M対1**(複数の実圃場が1つの中山間区画に対応) +- 実圃場 ↔ 共済区画: **M対N**(複数の実圃場が1つの共済区画に対応、また1つの実圃場が複数の共済区画に対応するケースもある) +- 実圃場 ↔ 中山間区画: **M対N**(同上) ```mermaid erDiagram - 実圃場 }o--|| 共済区画 : "紐づく(M:1)" - 実圃場 }o--|| 中山間区画 : "紐づく(M:1)" + 実圃場 }o--o{ 共済区画 : "紐づく(M:N)" + 実圃場 }o--o{ 中山間区画 : "紐づく(M:N)" 実圃場 ||--o{ 作付け計画 : "持つ(1:N)" - + 作付け計画 }o--|| 作物 : "参照" + 作付け計画 }o--o| 品種 : "参照(任意)" + 作物 ||--o{ 品種 : "持つ" + 実圃場 { int id PK string 名称 string 住所 - float 面積_反 + decimal 面積_反 + int 面積_m2 string 地主 - int 細目_耕地番号 "共済紐付けキー" - int 細目_分筆番号 "共済紐付けキー" - int 中山間_ID "中山間紐付けキー" + string グループ名 + int 表示順 + string 細目_耕地番号 "共済紐付けキー(raw)" + string 細目_分筆番号 "共済紐付けキー(raw)" + string 中山間_ID "中山間紐付けキー(raw)" } - + 共済区画 { int id PK string 地名_地番 int 耕地番号 int 分筆番号 - float 本地面積_m2 + decimal 本地面積_m2 string 漢字地名 } - + 中山間区画 { int id PK - int ID + string 中山間ID + string 中山間フラグ string 大字 string 字 - int 地番 + string 地番 + string 枝番 + string 地目 int 農地面積_m2 + int 植栽面積_m2 + string 作付け品目_元 + string 協定管理者 + string 所有者 + string 傾斜度 + int 基本金額 + decimal 超急傾斜加算額 + decimal スマート農業加算額 int 交付金額 } - + 作付け計画 { int id PK int 実圃場_id FK int 年度 - string 作物 - string 品種 - date 播種日 - date 収穫日 + int 作物_id FK + int 品種_id FK_nullable + text 備考 + } + + 作物 { + int id PK + string 作物名 + } + + 品種 { + int id PK + int 作物_id FK + string 品種名 } ``` @@ -79,6 +109,24 @@ erDiagram | 細目_分筆番号 | int | ○ | 共済マスタとの紐付けキー(2/2) | 1 | | 中山間_ID | int | △ | 中山間マスタとの紐付けキー | 50 | +### DBモデル(Field) + +| フィールド名 | データ型 | 説明 | +|-------------|---------|------| +| name | CharField(100) | 圃場名 | +| address | CharField(255) | 住所 | +| area_tan | DecimalField(6,4) | 面積(反) | +| area_m2 | IntegerField | 面積(m2)= area_tan × 1000 | +| owner_name | CharField(100) | 所有者名 | +| group_name | CharField(50), nullable | グループ名(エリアや用途による分類) | +| display_order | IntegerField, default=0 | リスト表示時の順序 | +| raw_kyosai_k_num | CharField(20), nullable | 細目_耕地番号(インポート元の値) | +| raw_kyosai_s_num | CharField(20), nullable | 細目_分筆番号(インポート元の値) | +| raw_chusankan_id | CharField(20), nullable | 中山間_ID(インポート元の値) | +| kyosai_fields | ManyToManyField → OfficialKyosaiField | 関連共済マスタ(M:N) | +| chusankan_fields | ManyToManyField → OfficialChusankanField | 関連中山間マスタ(M:N) | +| location | PointField, nullable | 位置情報(Phase 1では未使用) | + ### データサンプル ``` 名称 住所 面積(反) 細目_耕地番号 細目_分筆番号 中山間_ID @@ -90,7 +138,9 @@ erDiagram ### 特記事項 - **中山間_IDは一部NULL**: 39筆中2筆が中山間の対象外(`NaN`) - **同じ共済区画に複数の実圃場**: 例えば共済キー「2-2」には3つの実圃場が紐づく -- **面積単位**: DB内部では「反」と「m2」の両方を保持する(変換: 1反=1000m2) +- **1つの実圃場が複数の申請区画に紐づくケースもある**: M:N関係で対応 +- **面積単位**: DB内部では「反(DecimalField)」と「m2(IntegerField)」の両方を保持する(変換: 1反=1000m2) +- **グループ機能**: group_name でエリア分け、display_order で表示順を制御 --- @@ -110,6 +160,18 @@ erDiagram | 本地面積 (m2) | float | ○ | 申請上の面積(単位: m2) | 25.4 | | 漢字地名 | string | ○ | 漢字表記の地名 | "四万十町 笹ヶ谷 374-1" | +### DBモデル(OfficialKyosaiField) + +| フィールド名 | データ型 | 説明 | +|-------------|---------|------| +| k_num | IntegerField | 耕地番号 | +| s_num | IntegerField | 分筆番号 | +| address | CharField(200) | 地名地番 | +| kanji_name | CharField(200) | 漢字地名 | +| area | IntegerField | 本地面積(m2) | + +**制約:** (k_num, s_num) のペアで一意(unique_together) + ### データサンプル ``` 地名 地番 耕地番号 分筆番号 本地面積(m2) 漢字地名 @@ -129,97 +191,114 @@ erDiagram ### ファイル情報 - **行数:** 71行(71区画) -- **列数:** 17列(うち使用するのは一部) +- **列数:** 17列(全列をDBに保存) -### カラム定義(主要なもの) +### カラム定義(全17列) | カラム名 | データ型 | 必須 | 説明 | 例 | |---------|---------|-----|------|---| -| ID | int | ○ | 中山間区画の識別子 | 50 | +| ID | int | ○ | 中山間区画の識別子 | 1 | +| 中山間 | string | ○ | 中山間フラグ | "〇" | | 大字 | string | ○ | 大字名 | "口神ノ川" | | 字 | string | ○ | 字名 | "壱町切" | -| 地番 | int | ○ | 地番 | 1694 | -| 農地面積 | int | ○ | 面積(単位: m2) | 2900 | -| 作付け品目 | string | △ | (役場が記入、システムでは上書き) | "ニラ" | -| 交付金額 | int | △ | 交付金額 | 37700 | +| 地番 | string | ○ | 地番(数値でないケースあり:イ、ロ等) | "1694" | +| 枝番 | string | △ | 枝番(-, 1, イ, ロ等) | "-" | +| 地目 | string | ○ | 地目 | "田" | +| 農地面積 | int | ○ | 農地面積(m2) | 2900 | +| 植栽面積 | int | ○ | 植栽面積(m2) | 2748 | +| 作付け品目 | string | △ | 役場が記入した作付け品目 | "ニラ" | +| 協定管理者 | string | ○ | 協定管理者名 | "神山倫子" | +| 所有者 | string | △ | 所有者名(NULLあり) | "谷脇史男" | +| 傾斜度 | string | ○ | 傾斜度 | "1/29" | +| 基本金額 | int | ○ | 基本金額(円) | 23200 | +| 超急傾斜加算額 | decimal | △ | 超急傾斜加算額(円) | 0.0 | +| スマート農業加算額 | decimal | △ | スマート農業加算額(円) | 14500 | +| 交付金額 | int | ○ | 交付金額合計(円) | 37700 | + +### DBモデル(OfficialChusankanField) + +| フィールド名 | データ型 | 説明 | +|-------------|---------|------| +| c_id | CharField(20), unique | 中山間ID | +| chusankan_flag | CharField(10), nullable | 中山間フラグ(〇等) | +| oaza | CharField(100) | 大字 | +| aza | CharField(100) | 字 | +| chiban | CharField(50) | 地番(文字列:イ、ロ等があるため) | +| branch_num | CharField(20), nullable | 枝番(-, 1, イ, ロ等) | +| land_type | CharField(20), nullable | 地目(田, 畑等) | +| area | IntegerField | 農地面積(m2) | +| planting_area | IntegerField, nullable | 植栽面積(m2) | +| original_crop | CharField(100), nullable | 作付け品目(役場記入の元データ) | +| manager | CharField(100), nullable | 協定管理者 | +| owner | CharField(100), nullable | 所有者 | +| slope | CharField(20), nullable | 傾斜度 | +| base_amount | IntegerField, nullable | 基本金額(円) | +| steep_slope_addition | DecimalField, nullable | 超急傾斜加算額(円) | +| smart_agri_addition | DecimalField, nullable | スマート農業加算額(円) | +| payment_amount | IntegerField, nullable | 交付金額(円) | ### データサンプル ``` -ID 大字 字 地番 農地面積 作付け品目 交付金額 -50 口神ノ川 笹ヶ谷 374 2698 米 xxxxxx +ID 中山間 大字 字 地番 枝番 地目 農地面積 植栽面積 作付け品目 協定管理者 所有者 傾斜度 基本金額 交付金額 +1 〇 口神ノ川 壱町切 1694 - 田 2900 2748 ニラ 神山倫子 1/29 23200 37700 +2 〇 口神ノ川 大窪 490 1 田 652 490 野菜 谷脇誠一 谷脇史男 1/20 15204 18824 ``` ### 特記事項 -- **使用する列は限定的**: システムでは主に「ID」「大字」「字」「地番」「農地面積」を使用 -- **作付け品目は上書き**: 役場が記入した「作付け品目」は参考情報で、システムで上書きする +- **全17列をDBに保存**: 将来どの列が必要になるかわからないため全保存 +- **地番・枝番は文字列型**: 「イ」「ロ」などの非数値データが入る +- **作付け品目は参考情報**: 役場が記入した値。システムの作付け計画(Plan)とは別 - **面積の不整合は許容**: 共済マスタと同様、実圃場との差異は受け入れる --- ## 4. 作付け計画データ(システム内部) -### テーブル定義 +### DBモデル(Plan) -| カラム名 | データ型 | 必須 | 説明 | -|---------|---------|-----|------| -| id | int | ○ | 主キー(自動採番) | -| field_id | int | ○ | 実圃場ID(外部キー) | -| year | int | ○ | 年度(2025など) | -| crop | string | ○ | 作物(「米」「トウモロコシ」など) | -| variety | string | △ | 品種(「にこまる」など) | -| planting_date | date | △ | 播種日/定植日(Phase 2) | -| harvest_date | date | △ | 収穫日(Phase 2) | -| notes | text | △ | 備考 | +| フィールド名 | データ型 | 必須 | 説明 | +|-------------|---------|-----|------| +| id | int (自動) | ○ | 主キー | +| field | FK → Field | ○ | 実圃場(外部キー) | +| year | IntegerField | ○ | 年度(2025など) | +| crop | FK → Crop, nullable | △ | 作物(外部キー) | +| variety | FK → Variety, nullable | △ | 品種(外部キー、NULLあり) | +| notes | TextField, nullable | △ | 備考 | ### 制約 -- **ユニーク制約**: (field_id, year) - 1つの圃場に対して1年度につき1つの作付け計画のみ +- **ユニーク制約**: (field, year) - 1つの圃場に対して1年度につき1つの作付け計画のみ - Phase 2で二毛作対応する場合は、この制約を見直す +### 備考 +- planting_date(播種日)、harvest_date(収穫日)は Phase 2 で追加予定 +- crop, variety は外部キー(文字列ではなくリレーション) + --- ## 5. 作物マスタ -### 作物リスト -- 米 -- トウモロコシ -- エンドウ -- 野菜 -- その他 +### DBモデル(Crop) -### 品種の登録方法 +| フィールド名 | データ型 | 説明 | +|-------------|---------|------| +| id | int (自動) | 主キー | +| name | CharField(50), unique | 作物名 | -**すべての作物で統一されたUI:** -- プリセット品種から選択 -- その場で新しい品種を追加可能 -- 作物による操作の違いなし +### DBモデル(Variety) -### プリセット品種の例 +| フィールド名 | データ型 | 説明 | +|-------------|---------|------| +| id | int (自動) | 主キー | +| crop | FK → Crop | 所属する作物 | +| name | CharField(100) | 品種名 | -#### 米 -- にこまる -- たちはるか -- たちはるか(特栽) +**制約:** (crop, name) のペアで一意 -#### トウモロコシ -- (ユーザーが追加) - -#### エンドウ -- 久留米豊 - -#### 野菜 -- (ユーザーが追加) - -#### その他 -- 完全休耕 -- 緑肥(ヘアリーベッチ) -- 緑肥(レンゲ) -- 景観作物(コスモス) -- 景観作物(ヒマワリ) - -### 実装上の注意 -- すべての作物で `Variety` テーブルに品種を登録 -- 「作付けしない」系を特別扱いしない -- UIは完全に統一 +### 作物・品種の管理方針 +- 初期データは投入しない(管理画面またはUIから登録) +- すべての作物で品種選択UIは統一 +- 「作付けしない」系も特別扱いしない(「その他」作物の品種として扱う) +- 品種の追加・削除は作付け計画画面から可能 --- @@ -233,31 +312,31 @@ ID 大字 字 地番 農地面積 作付け品目 交付金額 2. **中山間マスタのインポート** - `中山間.ods` を読み込み - - `OfficialChusankanField` テーブルに保存 + - `OfficialChusankanField` テーブルに全17列を保存 3. **実圃場データのインポート** - `吉田農地台帳.ods` を読み込み - `Field` テーブルに保存 - - 同時に共済・中山間マスタとの紐付けを確立: - - `細目_耕地番号` + `細目_分筆番号` → `OfficialKyosaiField.id` を外部キーとして保存 - - `中山間_ID` → `OfficialChusankanField.id` を外部キーとして保存 + - 同時に共済・中山間マスタとの紐付けを確立(ManyToMany): + - `細目_耕地番号` + `細目_分筆番号` → `OfficialKyosaiField` を検索して M:N 関連に追加 + - `中山間_ID` → `OfficialChusankanField` を検索して M:N 関連に追加 ### 紐付けロジック ```python -# 共済マスタとの紐付け +# 共済マスタとの紐付け(M:N) kyosai_record = OfficialKyosaiField.objects.get( k_num=row['細目_耕地番号'], s_num=row['細目_分筆番号'] ) -field.kyosai_field_ref = kyosai_record.id +field.kyosai_fields.add(kyosai_record) -# 中山間マスタとの紐付け +# 中山間マスタとの紐付け(M:N) if pd.notna(row['中山間_ID']): chusankan_record = OfficialChusankanField.objects.get( - c_id=int(row['中山間_ID']) + c_id=str(int(row['中山間_ID'])) ) - field.chusankan_field_ref = chusankan_record.id + field.chusankan_fields.add(chusankan_record) ``` --- @@ -268,115 +347,50 @@ if pd.notna(row['中山間_ID']): **出力形式:** - A4サイズ、縦向き -- ヘッダー: 「水稲共済細目書(◯◯年度)」 -- 表形式(罫線あり) +- ヘッダー: 「水稲共済細目書(YYYY年度)」 +- 表形式(罫線あり)、1行1区画(31行) - フォントサイズ: 10pt -- ページ番号(複数ページの場合) +- ページ番号あり **表の列:** -``` -耕地番号 | 分筆番号 | 地名地番 | 漢字地名 | 本地面積(m2) | 作付品目 | 品種 | 備考 - 1 | 1 | 四万十町... | 四万十町... | 2.2 | 米 |にこまる| - 2 | 1 | 四万十町... | 四万十町... | 25.4 | 米 |にこまる| - 2 | 2 | 四万十町... | 四万十町... | 12.0 |米,野菜|にこまる,トマト|複数圃場 -``` + +| 列名 | データ元 | 備考 | +|------|---------|------| +| 漢字地名 | OfficialKyosaiField.kanji_name | 例: 四万十町 笹ヶ谷 374-1 | +| 耕地-分筆 | k_num + "-" + s_num | 例: 2-1 | +| 本地面積 (m2) | OfficialKyosaiField.area | | +| 作付品目 | Plan.crop.name | システムの作付け計画から | +| 品種 | Plan.variety.name | 〃 | +| 圃場名称 | Field.name | 吉田農地台帳の名称 | **集計ロジック:** -```python -def generate_kyosai_pdf(year): - # 1. データ集約(CSVと同じロジック) - output_rows = [] - for kyosai in OfficialKyosaiField.objects.all().order_by('k_num', 's_num'): - fields = Field.objects.filter(kyosai_field_ref=kyosai.id) - plans = Plan.objects.filter(field__in=fields, year=year) - - crops = list(set([p.crop.name for p in plans if p.crop])) - varieties = list(set([p.variety.name for p in plans if p.variety])) - - row = { - '耕地番号': kyosai.k_num, - '分筆番号': kyosai.s_num, - '地名地番': kyosai.address, - '漢字地名': kyosai.kanji_name, - '本地面積(m2)': kyosai.area, - '作付品目': ','.join(crops) if crops else '未設定', - '品種': ','.join(varieties) if varieties else '', - '備考': f'{len(fields)}筆合算' if len(fields) > 1 else '' - } - output_rows.append(row) - - # 2. HTMLテンプレートで表を生成 - html = render_to_string('reports/kyosai_template.html', { - 'year': year, - 'rows': output_rows - }) - - # 3. HTML → PDF変換 - pdf = HTML(string=html).write_pdf() - return pdf -``` - -**HTMLテンプレート例(reports/kyosai_template.html):** -```html - - - - - - - -

水稲共済細目書({{ year }}年度)

- - - - - - - - - - - - - - - {% for row in rows %} - - - - - - - - - - - {% endfor %} - -
耕地番号分筆番号地名地番漢字地名本地面積(m2)作付品目品種備考
{{ row.耕地番号 }}{{ row.分筆番号 }}{{ row.地名地番 }}{{ row.漢字地名 }}{{ row.本地面積(m2) }}{{ row.作付品目 }}{{ row.品種 }}{{ row.備考 }}
- - -``` +1. 共済マスタ(31区画)をループ +2. 各共済区画に紐づく実圃場を取得(M:N関係) +3. 紐づく実圃場の作付け情報を集約(作物名・品種名・圃場名をカンマ区切り) +4. HTMLテンプレートで表を生成 → WeasyPrint で PDF変換 +5. 複数の実圃場が紐づく場合 → 作物・品種・圃場名をカンマ区切りで列挙 +6. 作付け未設定の場合 → 「未設定」と表示 ### 中山間交付金申請 **出力形式:** -- A4サイズ、縦向き -- ヘッダー: 「中山間地域等直接支払交付金(◯◯年度)」 -- 表形式(罫線あり) +- A4サイズ、横向き(列が多いため) +- ヘッダー: 「中山間地域等直接支払交付金(YYYY年度)」 +- 表形式(罫線あり)、1行1区画(71行) +- ページ番号あり **表の列:** -``` -ID | 大字 | 字 | 地番 | 農地面積(m2) | 作付品目 | 品種 | 備考 -50 | 口神ノ川 | 笹ヶ谷 | 374 | 2698 | 米,野菜 | にこまる,トマト | 7筆合算 -``` + +| 列名 | データ元 | 備考 | +|------|---------|------| +| 所在地 | 大字+字+地番+枝番 連結 | 例: 口神ノ川 壱町切 1694 | +| 植栽面積 | OfficialChusankanField.planting_area | m2 | +| 作付け品目(元) | OfficialChusankanField.original_crop | 役場記入の値 | +| 協定管理者 | OfficialChusankanField.manager | | +| 所有者 | OfficialChusankanField.owner | | +| 作物 | Plan.crop.name | システムの作付け計画から | +| 品種 | Plan.variety.name | 〃 | +| 圃場名称 | Field.name | 吉田農地台帳の名称 | **集計ロジック:** - 水稲共済と同様、中山間マスタをループして実圃場を集約 → HTMLテンプレート → PDF @@ -395,7 +409,7 @@ ID | 大字 | 字 | 地番 | 農地面積(m2) | 作付品目 | 品種 | 備考 - または、全削除→再インポートの2段階処理 ### バックアップ -- 全テーブルをCSV/Excelでエクスポート可能にする +- 全テーブルをCSV/Excelでエクスポート可能にする(サーバー移行時にも利用) - 最低5年分のデータを保持(補助金監査対応) --- @@ -404,15 +418,17 @@ ID | 大字 | 字 | 地番 | 農地面積(m2) | 作付品目 | 品種 | 備考 システム内部では以下のように統一: -| 表示単位 | DB保存 | 変換式 | -|---------|--------|--------| -| 反(たん) | m2 | 1反 = 1000m2 | -| アール(a) | m2 | 1a = 100m2 | -| ヘクタール(ha) | m2 | 1ha = 10000m2 | +| 用途 | 単位 | DB型 | 変換式 | +|-----|------|------|--------| +| 実圃場の面積(DB保存) | 反 + m2 | DecimalField + IntegerField | 1反 = 1000m2 | +| 共済マスタの面積(DB保存) | m2 | IntegerField | - | +| 中山間マスタの面積(DB保存) | m2 | IntegerField | - | +| 画面表示 | 反 | - | area_m2 / 1000 | **実装方針:** -- DB内部は全て `m2` で保存(整数型) -- 表示時にユーザー設定に応じて変換(デフォルトは「反」) +- 実圃場: `area_tan`(DecimalField)と `area_m2`(IntegerField)の両方を保持 +- 共済・中山間マスタ: `area` は m2(IntegerField)で保存 +- 表示時は「反」に統一(1反 = 10a = 1000m2) - 入力時は「反」で受け付け、内部で `m2` に変換 --- diff --git a/document/04_画面設計書.md b/document/04_画面設計書.md index 82738da..23a2289 100644 --- a/document/04_画面設計書.md +++ b/document/04_画面設計書.md @@ -1,5 +1,8 @@ # 画面設計書 +> **最終更新**: 2026-02-16 +> **変更履歴**: 実装済み機能との差異を解消(B-1〜B-5, C-6, E-1 反映) + ## 🎨 デザイン原則(再掲) 1. **シンプル・イズ・ベスト**: 1画面1機能 @@ -10,28 +13,57 @@ --- +## 🧭 共通ナビゲーション(Navbar) + +### PC レイアウト + +上部に水平ナビゲーションバーを常時表示。ブランド名「KeinaSystem」と主要画面へのリンクを配置。 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] [帳票出力] [データ取込] [ログアウト] │ +└──────────────────────────────────────────────────────────────┘ +``` + +### ナビゲーション項目 + +| アイコン | ラベル | パス | 説明 | +|---------|--------|------|------| +| 🌾 (Wheat) | 作付け計画 | `/allocation` | 作付け計画編集画面(メイン) | +| 📍 (MapPin) | 圃場管理 | `/fields` | 圃場一覧・編集 | +| 📄 (FileText) | 帳票出力 | `/reports` | 申請書PDFダウンロード | +| ⬆️ (Upload) | データ取込 | `/import` | マスタインポート | + +### 仕様 +- アクティブなページのリンクは緑背景でハイライト +- ログアウトボタンは右端に配置 +- スマホではレスポンシブにタブバーまたはハンバーガーメニューに切り替え + +--- + ## 📱 画面一覧 ### Phase 1(MVP) -1. **ログイン画面** -2. **ダッシュボード**(将来拡張用、Phase 1では簡易版) -3. **作付け計画一覧**(メイン画面) -4. **作付け計画編集**(モーダル/サイドパネル) -5. **圃場詳細**(スマホ参照用) -6. **申請書ダウンロード** -7. **データ管理**(インポート・エクスポート) +1. **ログイン画面** (`/login`) +2. **ダッシュボード** (`/`) — 将来拡張用、Phase 1では簡易版 +3. **作付け計画一覧・編集** (`/allocation`) — メイン画面、インライン編集方式 +4. **圃場管理一覧** (`/fields`) — 圃場の一覧表示・グループ管理・表示順管理 +5. **圃場詳細・編集** (`/fields/[id]`) — 個別圃場の情報編集 +6. **圃場新規作成** (`/fields/new`) — 手動での圃場登録 +7. **申請書ダウンロード** (`/reports`) — PDFダウンロード +8. **データ取込** (`/import`) — インポート ### Phase 2以降 -8. 栽培履歴入力 -9. 作業カレンダー -10. 資材計画 +9. 栽培履歴入力 +10. 作業カレンダー +11. 資材計画 --- ## 画面1: ログイン画面 ### 目的 -シンプルな認証(メール+パスワード) +シンプルな認証(ユーザー名+パスワード) ### レイアウト(PC/スマホ共通) @@ -42,7 +74,7 @@ │ 作付け計画管理システム │ │ │ │ ┌───────────────────────┐ │ -│ │ メールアドレス │ │ +│ │ ユーザー名 │ │ │ │ [___________________] │ │ │ └───────────────────────┘ │ │ │ @@ -57,9 +89,9 @@ ``` ### 機能要件 -- [ ] メールアドレスとパスワードで認証 -- [ ] ログイン成功 → ダッシュボードへ遷移 -- [ ] ログイン失敗 → エラーメッセージ表示 +- [x] ユーザー名とパスワードで認証(JWT) +- [x] ログイン成功 → 作付け計画画面へ遷移 +- [x] ログイン失敗 → エラーメッセージ表示 - [ ] 「パスワードを忘れた」リンク(Phase 2) --- @@ -69,11 +101,15 @@ ### 目的 システムの入り口(Phase 1では簡易版、将来拡張) -### レイアウト(PC) +### 現在の実装 +- `/` アクセス時、トークンの有無で `/allocation`(ログイン済み)か `/login`(未ログイン)にリダイレクト +- ダッシュボード画面自体は未実装 + +### レイアウト(将来実装予定、PC) ``` ┌────────────────────────────────────────────────────┐ -│ 🌾 Keina System 2025年度 ▼ 👤ログアウト │ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] ... │ ├────────────────────────────────────────────────────┤ │ │ │ 📊 概要 │ @@ -94,54 +130,55 @@ └────────────────────────────────────────────────────┘ ``` -### 機能要件(Phase 1) +### 機能要件(将来実装予定) - [ ] 年度選択(ドロップダウン) - [ ] 作付け状況のサマリー表示 - [ ] 「作付け計画を編集」→ 画面3へ -- [ ] 「申請書ダウンロード」→ 画面6へ +- [ ] 「申請書ダウンロード」→ 画面7へ +- [ ] 将来の機能追加時にボタンを追加していく想定 --- -## 画面3: 作付け計画一覧(メイン画面) +## 画面3: 作付け計画一覧・編集(メイン画面) ### 目的 -全圃場の作付け状況を一覧で確認・編集 +全圃場の作付け状況を一覧で確認し、**インライン**で直接編集 + +### 編集方式 +**インライン編集**を採用(モーダルではない)。テーブル行内のドロップダウンで作物・品種を選択し、変更は即座にAPIに保存される。 ### レイアウト(PC) ``` ┌──────────────────────────────────────────────────────────────────┐ -│ 🌾 Keina System > 作付け計画一覧 2025年度 ▼ 👤ログアウト │ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] [帳票出力] [データ取込] │ ├──────┬───────────────────────────────────────────────────────────┤ │ │ │ -│ 📊 │ 🔍 [検索: 圃場名・住所_____________] 🔽絞込: [全て▼] │ +│ 📊 │ 年度: [2025 ▼] 並び順: [カスタム順 ▼] │ │ 集計 │ │ -│ │ ☐ 未割当のみ表示 [📋 前年度をコピー] [📊 申請書作成] │ -│ ────────────────────────────────────────────────────────────────│ -│ 米 │ No. ☐ 名称 住所 面積 作付 品種 操作 │ -│15.3反│ ────────────────────────────────────────────────────────│ -│┣にこ │ 1 ☐ おまけ 口神ノ川... 0.2反 米 にこまる [編集]│ -││10.2反│ 2 ☐ 口神1反 口神ノ川... 1.2反 米 にこまる [編集]│ -│┗たち │ 3 ☐ 口神北東 口神ノ川... 0.4反 野菜 トマト [編集]│ -││5.1反│ 4 ☐ 口神北中 口神ノ川... 0.4反 ❗未設定 [割当]│ -│ │ 5 ☐ 口神北西 口神ノ川... 0.5反 その他 完全休耕 [編集]│ -│野菜 │ │ -│3.2反 │ ... (39行) │ -│ │ │ -│その他│ ────────────────────────────────────────────────────────│ -│1.5反 │ ページ: 1 / 2 表示件数: [25件▼] │ +│ │ ──────────────────────────────────────────────────────── │ +│ ──── │ グループ 圃場名 面積 作物 品種 備考 順序│ +│ 合計 │ ──────────────────────────────────────────────────────── │ +│20.0反│ [口神_▼] おまけ 0.2反 [米 ▼] [にこまる▼] [___] ↑↓│ +│ │ [口神_▼] 口神1反 1.2反 [米 ▼] [にこまる▼] [___] ↑↓│ +│ 米 │ [口神_▼] 口神北東 0.4反 [野菜 ▼] [トマト▼] [___] ↑↓│ +│15.3反│ [南__▼] 口神北中 0.4反 [-- ▼] [---------] [___] ↑↓│ +│┣にこ │ [南__▼] 口神北西 0.5反 [その他 ▼] [完全休耕▼] [___] ↑↓│ +││10.2反│ │ +│┗たち │ ... (39行) │ +││5.1反│ │ │ │ │ │未設定│ │ │2.0反❗ │ └──────┴───────────────────────────────────────────────────────────┘ ``` -**サイドバー(開閉可能):** +**サイドバー(集計パネル、開閉可能):** ``` ┌──────────────┐ -│ [≡] 集計 │← トグルボタンで開閉 +│ 集計 [×] │← 閉じるボタン ├──────────────┤ -│ 合計 40.0反 │ +│ 合計 20.0反 │ │ │ │ 米 │ │ 15.3反 │ @@ -152,87 +189,55 @@ │ │ │ 野菜 │ │ 3.2反 │ -│ ├トマト │ -│ │ 1.8反 │ -│ └キュウリ │ -│ 1.4反 │ -│ │ -│ トウモロコシ │ -│ 2.5反 │ -│ │ -│ エンドウ │ -│ 1.8反 │ │ │ │ その他 │ │ 1.5反 │ -│ ├完全休耕 │ -│ │ 0.8反 │ -│ └緑肥 │ -│ 0.7反 │ │ │ │ ❗未設定 │ │ 2.0反 │ └──────────────┘ ``` -**サイドバー閉じた状態:** -``` -┌───┐ -│[☰]│← クリックで開く -└───┘ -``` - ### レイアウト(スマホ) ``` -┌────────────────────────────────┐ -│ 🌾 作付け計画 2025年度 ▼ ☰ │ -├────────────────────────────────┤ -│ 🔍 [検索_______________] [🔽] │ -│ │ -│ [📊 集計を表示] [前年度コピー]│← 集計はモーダル -├────────────────────────────────┤ -│ ┌────────────────────────────┐│ -│ │ おまけ ││ -│ │ 口神ノ川足川 351 ││ -│ │ 0.2反 | 米(にこまる) ││ -│ │ [編集] ││ -│ └────────────────────────────┘│ -│ │ -│ ┌────────────────────────────┐│ -│ │ 口神 北中 ││ -│ │ 口神ノ川198... ││ -│ │ 0.4反 | ❗未設定 ││ -│ │ [割当] ││ -│ └────────────────────────────┘│ -│ │ -│ ... (39圃場) │ -└────────────────────────────────┘ +┌────────────────────────────────────┐ +│ 🌾 作付け計画 [2025▼] [集計] ☰ │ +├────────────────────────────────────┤ +│ 並び順: [カスタム順 ▼] │ +├────────────────────────────────────┤ +│ ┌────────────────────────────────┐│ +│ │ おまけ 0.2反 ││ +│ │ グループ: [口神___▼] ││ +│ │ 作物: [米 ▼] 品種: [にこまる▼]││ +│ │ 備考: [___________________] ││ +│ └────────────────────────────────┘│ +│ │ +│ ┌────────────────────────────────┐│ +│ │ 口神 北中 0.4反 ││ +│ │ グループ: [南___▼] ││ +│ │ 作物: [-- ▼] 品種: [------] ││ +│ │ 備考: [___________________] ││ +│ └────────────────────────────────┘│ +│ │ +│ ... (39圃場) │ +└────────────────────────────────────┘ ``` -**スマホ: 集計モーダル** +**スマホ: 集計モーダル**([集計]ボタンで表示) ``` ┌────────────────────────────────┐ │ 集計 [×] │ ├────────────────────────────────┤ -│ │ -│ 合計面積: 40.0反 │ +│ 合計面積: 20.0反 │ │ │ │ 米: 15.3反 │ │ ├ にこまる: 10.2反 │ │ └ たちはるか: 5.1反 │ │ │ │ 野菜: 3.2反 │ -│ ├ トマト: 1.8反 │ -│ └ キュウリ: 1.4反 │ -│ │ -│ トウモロコシ: 2.5反 │ -│ │ -│ エンドウ: 1.8反 │ │ │ │ その他: 1.5反 │ -│ ├ 完全休耕: 0.8反 │ -│ └ 緑肥: 0.7反 │ │ │ │ ❗未設定: 2.0反 │ │ │ @@ -241,221 +246,184 @@ ``` ### 機能要件 -- [ ] 全圃場を一覧表示(39行) -- [ ] 各行に以下を表示: - - チェックボックス(一括操作用) - - 名称 - - 住所 +- [x] 全圃場を一覧表示(39行) +- [x] 各行に以下を表示: + - グループ名(インライン編集可能、datalist補完付き) + - 圃場名 - 面積(反) - - 作付け作物(未設定の場合は警告色) - - 品種 - - [編集]ボタン -- [ ] 検索機能: - - 圃場名・住所で部分一致検索 - - リアルタイム絞り込み -- [ ] フィルタ機能: - - 作物で絞り込み(米、野菜、休耕など) - - 「未割当のみ」トグル -- [ ] 一括操作: - - 複数行を選択 → 「一括割当」ボタン表示 - - 同じ作物を一括で割り当て -- [ ] [前年度をコピー]ボタン: - - 確認ダイアログ表示 - - 前年度の作付けを全圃場にコピー -- [ ] [申請書作成]ボタン: - - 画面6へ遷移 -- [ ] **集計サイドバー(PC)**: - - トグルボタンで開閉 + - 作物(ドロップダウン、インライン選択) + - 品種(ドロップダウン、作物選択後に有効化) + - 備考(テキスト入力) + - 表示順変更ボタン(↑↓、カスタム順モード時のみ) +- [x] 年度切り替え(ドロップダウン) +- [x] 並び替え機能: + - カスタム順(display_order) + - グループ順(group_name) + - 作付け順(crop別) +- [x] **インライン即時保存**: 作物・品種・備考を変更すると即座にAPIに保存(画面遷移なし、スクロール位置維持) +- [x] **集計サイドバー(PC)**: + - 閉じるボタンで非表示可能 - 作物別の合計面積 - - 品種別の内訳(ツリー表示) + - 品種別の内訳(ツリー表示、展開可能) - 未設定の面積を警告表示 -- [ ] **集計モーダル(スマホ)**: - - [📊 集計を表示]ボタンでモーダル表示 - - PC版と同じ内容を縦スクロール表示 + - 作付け変更時にリアルタイム更新 +- [x] **集計モーダル(スマホ)**: + - [集計]ボタンでサイドパネル表示 + - PC版と同じ内容 +- [ ] 検索機能(圃場名・住所で部分一致検索)— **未実装** +- [ ] フィルタ機能(作物で絞り込み、未割当のみトグル)— **未実装** +- [ ] チェックボックスによる一括操作 — **未実装** +- [ ] [前年度をコピー]ボタン — **Backend APIあり、Frontendボタン未実装** ### デザインノート -- **未割当の強調**: 赤または黄色の背景色 -- **チェックボックスの位置**: 行の左端(スマホでも押しやすい) -- **スマホ版**: カード型レイアウト(1圃場1カード) -- **サイドバーの幅**: 200px(固定) -- **集計の更新**: 作付け計画を編集するたびにリアルタイム更新 +- **未割当の強調**: 作物未設定の行は目立つ表示 +- **即時保存**: ユーザーが選択を変更するたびにバックグラウンドで保存(ローディングスピナーなし) +- **スクロール維持**: 保存時に画面がリセットされない +- **サイドバーの幅**: 約200px(固定) --- -## 画面4: 作付け計画編集(モーダル) +## 画面4: 圃場管理一覧 ### 目的 -個別の圃場に作物を割り当てる +圃場マスタの管理(一覧表示、グループ編集、表示順変更、削除) -### レイアウト(PC - モーダルウィンドウ) +### レイアウト(PC) + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] [帳票出力] [データ取込] │ +├──────────────────────────────────────────────────────────────────┤ +│ │ +│ 並び順: [表示順 ▼] [+ 新規作成] │ +│ │ +│ ───────────────────────────────────────────────────────────── │ +│ 順序 圃場名 グループ 住所 面積(反) 面積(m2) 所有者 操作│ +│ ───────────────────────────────────────────────────────────── │ +│ 1 おまけ [口神___▼] 口神ノ川足川... 0.2 200 吉田 ✏️🗑│ +│ 2 口神1反 [口神___▼] 口神ノ川... 1.2 1200 吉田 ✏️🗑│ +│ 3 口神北東 [口神___▼] 口神ノ川... 0.4 400 吉田 ✏️🗑│ +│ 4 口神北中 [南_____▼] 口神ノ川... 0.4 400 吉田 ✏️🗑│ +│ │ +│ ... (39行) │ +│ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +### 機能要件 +- [x] 全圃場を一覧表示(テーブル形式) +- [x] 表示列: 順序番号、圃場名、グループ名、住所、面積(反)、面積(m2)、所有者、操作 +- [x] **グループ名のインライン編集**: datalist による候補表示付きテキスト入力 +- [x] **表示順変更**: ↑↓ ボタンで順序入れ替え(表示順モード時) +- [x] 並び順の切り替え(グループ順、表示順、登録順) +- [x] [新規作成]ボタン → 画面6へ遷移 +- [x] [✏️ 編集]ボタン → 画面5(圃場詳細)へ遷移 +- [x] [🗑 削除]ボタン → 確認ダイアログ後に削除 + +--- + +## 画面5: 圃場詳細・編集 + +### 目的 +個別の圃場情報を確認・編集。田んぼにいるときにスマホで確認する用途も想定。 + +### レイアウト(PC/スマホ共通) ``` ┌────────────────────────────────────┐ -│ 作付け計画を編集 [×] │ +│ ← 一覧に戻る │ ├────────────────────────────────────┤ │ │ -│ 圃場: 口神 北中 │ -│ 住所: 口神ノ川198(笹ヶ谷374-1) │ -│ 面積: 0.4反 (400m2) │ +│ 圃場名 │ +│ [口神 北中________________] │ │ │ -│ ───────────────────────────────── │ +│ 住所 │ +│ [口神ノ川198(笹ヶ谷374-1)__] │ │ │ -│ 作物 * │ -│ ┌────────────────────────────────┐│ -│ │ [米 ▼] ││ -│ └────────────────────────────────┘│ +│ 面積(反) │ +│ [0.4___] │ │ │ -│ 品種 * │ -│ ┌────────────────────────────────┐│ -│ │ [にこまる ▼] ││ -│ │ - にこまる ││ -│ │ - たちはるか ││ -│ │ - たちはるか(特栽) ││ -│ └────────────────────────────────┘│ -│ [+ 新しい品種を追加] │ +│ 面積(m2) │ +│ [400___] │ │ │ -│ 備考 │ -│ ┌────────────────────────────────┐│ -│ │ [_____________________________]││ -│ └────────────────────────────────┘│ +│ 所有者 │ +│ [吉田___] │ │ │ -│ [キャンセル] [保存] │ +│ グループ名 │ +│ [口神___] │ │ │ -└────────────────────────────────────┘ -``` - -### 作物選択のドロップダウン - -``` -┌────────────────────────────────────┐ -│ • 米 │ -│ • トウモロコシ │ -│ • エンドウ │ -│ • 野菜 │ -│ • その他 │ -└────────────────────────────────────┘ -``` - -### 品種選択(すべての作物で統一) - -**作物=「米」の場合:** -``` -┌────────────────────────────────────┐ -│ • にこまる │ -│ • たちはるか │ -│ • たちはるか(特栽) │ -│ ──────────────────────────────── │ -│ [+ 新しい品種を追加] │ -└────────────────────────────────────┘ - -クリックすると: -┌────────────────────────────────────┐ -│ 新しい品種名を入力: │ -│ [___________________________] │ +│ 📋 共済情報(Phase 1 予定) │ +│ 紐づき共済区画: 2件 │ +│ • 耕地2-1: 四万十町 笹ヶ谷 374-1 │ +│ • 耕地2-2: 四万十町 笹ヶ谷 374-2 │ +│ │ +│ 📋 中山間情報(Phase 1 予定) │ +│ 紐づき中山間区画: 1件 │ +│ • ID50: 口神ノ川 壱町切 1694 │ +│ │ +│ [保存] │ │ │ -│ [キャンセル] [追加] │ -└────────────────────────────────────┘ -``` - -**作物=「トウモロコシ」の場合:** -``` -┌────────────────────────────────────┐ -│ (まだ品種が登録されていません) │ -│ ──────────────────────────────── │ -│ [+ 新しい品種を追加] │ -└────────────────────────────────────┘ -``` - -**作物=「その他」の場合:** -``` -┌────────────────────────────────────┐ -│ • 完全休耕 │ -│ • 緑肥(ヘアリーベッチ) │ -│ • 緑肥(レンゲ) │ -│ • 景観作物(コスモス) │ -│ • 景観作物(ヒマワリ) │ -│ ──────────────────────────────── │ -│ [+ 新しい品種を追加] │ └────────────────────────────────────┘ ``` ### 機能要件 -- [ ] 作物をドロップダウンで選択 -- [ ] **すべての作物で品種選択UIは統一** - - プリセット品種のドロップダウン - - [+ 新しい品種を追加]ボタンは常に表示 - - 作物による操作の違いなし -- [ ] 新しい品種の追加: - - [+ 新しい品種を追加]をクリック - - インライン入力フィールド表示 - - 入力後、その場でプリセットに追加 - - データベースに永続化(次回から選択可能) -- [ ] 備考欄(任意) -- [ ] [保存]ボタン → 作付け計画を保存して一覧に戻る -- [ ] [キャンセル]ボタン → 変更を破棄して一覧に戻る -- [ ] **集計のリアルタイム更新**: - - 保存すると、サイドバーの集計が即座に更新される - -### 一括割当の場合 -- モーダルのタイトルを「一括割当」に変更 -- 「圃場: 5件選択中」と表示 -- 保存時、選択中の全圃場に同じ作付けを適用 - -### デザインノート -- **UIの統一性**: どの作物を選んでも操作フローが同じ -- **品種の追加**: その場で追加できる(別画面に遷移しない) -- **プリセットの管理**: 一度追加した品種は、全ユーザーで共有(マスタ化) - ---- - -## 画面5: 圃場詳細(スマホ参照用) - -### 目的 -田んぼにいるときに、その圃場の情報を確認 - -### レイアウト(スマホ) - -``` -┌────────────────────────────────┐ -│ ← 一覧に戻る 2025年度 │ -├────────────────────────────────┤ -│ │ -│ 口神 北中 │ -│ │ -│ 📍 住所 │ -│ 口神ノ川198(笹ヶ谷374-1) │ -│ │ -│ 📏 面積 │ -│ 0.4反 (400m2) │ -│ │ -│ 🌾 今年の作付け │ -│ 米(にこまる) │ -│ │ -│ 📋 共済情報 │ -│ 耕地番号: 2 / 分筆: 2 │ -│ │ -│ 📋 中山間情報 │ -│ ID: 50 │ -│ │ -│ ───────────────────────────── │ -│ │ -│ 📅 過去の作付け履歴(Phase 2) │ -│ • 2024年: 米(にこまる) │ -│ • 2023年: 米(にこまる) │ -│ • 2022年: 休耕 │ -│ │ -└────────────────────────────────┘ -``` - -### 機能要件 -- [ ] 圃場の基本情報を見やすく表示 -- [ ] 文字サイズ: 18px以上(スマホで見やすく) -- [ ] 余白: 十分に確保(誤タップ防止) +- [x] 圃場の基本情報を編集フォームで表示 +- [x] 編集可能フィールド: 圃場名、住所、面積(反)、面積(m2)、所有者、グループ名 +- [x] [保存]ボタン → PATCH API で更新 +- [x] [← 一覧に戻る] → `/fields` へ遷移 +- [x] エラーメッセージ表示 +- [ ] **共済/中山間情報の表示** — **未実装(A-8: 最優先で実装予定)** + - 紐づいている共済区画の一覧(耕地番号-分筆、漢字地名) + - 紐づいている中山間区画の一覧(ID、所在地) - [ ] 将来的に栽培履歴も表示(Phase 2) --- -## 画面6: 申請書ダウンロード +## 画面6: 圃場新規作成 + +### 目的 +手動で圃場を1件ずつ新規登録(インポート以外の方法) + +### レイアウト + +``` +┌────────────────────────────────────┐ +│ ← 一覧に戻る │ +├────────────────────────────────────┤ +│ │ +│ 圃場名 │ +│ [____________________________] │ +│ │ +│ 住所 │ +│ [____________________________] │ +│ │ +│ 面積(反) │ +│ [________] │ +│ │ +│ 面積(m2) │ +│ [________] │ +│ │ +│ 所有者 │ +│ [____________________________] │ +│ │ +│ [作成] │ +│ │ +└────────────────────────────────────┘ +``` + +### 機能要件 +- [x] 各フィールドを入力して圃場を新規作成 +- [x] [作成]ボタン → POST API で作成 +- [x] 作成成功 → 圃場一覧へ遷移 +- [x] バリデーションエラー → エラーメッセージ表示 + +### 補足 +- インポート(ODS/Excel)との使い分け: 大量登録はインポート、1件追加は手動作成 +- グループ名は新規作成時には設定不可(作成後に圃場一覧から設定) + +--- + +## 画面7: 申請書ダウンロード ### 目的 水稲共済細目書・中山間交付金のPDFをダウンロード @@ -464,7 +432,7 @@ ``` ┌────────────────────────────────────────────────────┐ -│ 🌾 Keina System > 申請書ダウンロード 👤ログアウト │ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] ... │ ├────────────────────────────────────────────────────┤ │ │ │ 年度: [2025年度 ▼] │ @@ -472,7 +440,6 @@ │ ┌────────────────────────────────────────────────┐│ │ │ 📄 水稲共済細目書 ││ │ │ ││ -│ │ 提出時期: 2月・5月(年2回) ││ │ │ 区画数: 31区画 ││ │ │ ││ │ │ ⚠️ 未割当の圃場: 4筆 ││ @@ -484,7 +451,6 @@ │ ┌────────────────────────────────────────────────┐│ │ │ 📄 中山間地域等直接支払交付金 ││ │ │ ││ -│ │ 提出時期: 5月(年1回) ││ │ │ 区画数: 71区画 ││ │ │ ││ │ │ ✅ 全て割当済み ││ @@ -496,95 +462,128 @@ ``` ### 機能要件 -- [ ] 年度を選択 -- [ ] 各申請書について: - - 区画数を表示 - - 未割当の警告(ある場合) - - [プレビュー]ボタン → 新しいタブでPDFプレビュー - - [PDFダウンロード]ボタン → ファイルダウンロード +- [x] 年度を選択 +- [x] 各申請書について: + - [x] [PDFダウンロード]ボタン → ファイルダウンロード +- [ ] 区画数の表示 — **未実装** +- [ ] 未割当の警告表示 — **未実装** +- [ ] [プレビュー]ボタン → 新しいタブでPDF表示 — **未実装(A-5)** - [ ] ダウンロードされるPDFのファイル名: - 水稲共済: `水稲共済細目書_2025年度.pdf` - 中山間: `中山間交付金_2025年度.pdf` - [ ] PDFはA4サイズ、印刷してそのまま提出可能 -### プレビュー機能 +--- -[プレビュー]ボタンをクリックすると、新しいタブでPDFを表示: +## 画面7-A: PDF帳票フォーマット仕様 -``` -┌────────────────────────────────────────────────────┐ -│ ← 戻る 水稲共済細目書_2025年度.pdf [印刷] [⬇] │ -├────────────────────────────────────────────────────┤ -│ │ -│ 水稲共済細目書(2025年度) │ -│ │ -│ ┌────────────────────────────────────────────────┐│ -│ │ 耕地 分筆 地名地番 面積 作付 品種 ││ -│ │ ──────────────────────────────────────────── ││ -│ │ 1 1 四万十町 ... 2.2 米 にこまる ││ -│ │ 2 1 四万十町 ... 25.4 米 にこまる ││ -│ │ 2 2 四万十町 ... 12.0 米,野菜 ... ││ -│ │ ││ -│ │ ... (31行) ││ -│ └────────────────────────────────────────────────┘│ -│ │ -│ 1 / 2 │ -└────────────────────────────────────────────────────┘ -``` +### 7-A-1: 水稲共済細目書 PDF -- [ ] ブラウザの標準PDFビューアで表示 -- [ ] 印刷ボタンで直接印刷可能 -- [ ] ダウンロードボタンでローカル保存 +**基本仕様:** +- 用紙: A4 縦 +- 表形式(1行1区画、全31行) +- ヘッダー: 「水稲共済細目書(YYYY年度)」 +- ページ番号あり +- 印刷してそのまま提出可能 + +**列定義:** + +| # | 列名 | データ元 | 備考 | +|---|------|---------|------| +| 1 | 漢字地名 | OfficialKyosaiField.kanji_name | 例: 四万十町 笹ヶ谷 374-1 | +| 2 | 耕地-分筆 | k_num + "-" + s_num | 例: 2-1 | +| 3 | 本地面積 (m2) | OfficialKyosaiField.area | 内部 m2 で保存 | +| 4 | 作付品目 | Plan.crop.name | 作付け計画から取得 | +| 5 | 品種 | Plan.variety.name | 〃(nullの場合は空欄) | +| 6 | 圃場名称 | Field.name | 吉田農地台帳の名称 | + +**複数圃場紐づき時の扱い:** +- 1つの共済区画に複数の実圃場(Field)が紐づく場合 → 作物・品種・圃場名をカンマ区切りで列挙 +- 例: 「米, 野菜」「にこまる, トマト」「口神北東, 口神北中」 + +**未設定時の扱い:** +- 作付け未設定の場合 → 作付品目列に「未設定」と表示 --- -## 画面7: データ管理 +### 7-A-2: 中山間地域等直接支払交付金 PDF + +**基本仕様:** +- 用紙: A4 横(列が多いため) +- 表形式(1行1区画、全71行) +- ヘッダー: 「中山間地域等直接支払交付金(YYYY年度)」 +- ページ番号あり +- 印刷してそのまま提出可能 + +**列定義:** + +| # | 列名 | データ元 | 備考 | +|---|------|---------|------| +| 1 | 所在地 | 大字+字+地番+枝番 連結 | 例: 口神ノ川 壱町切 1694 | +| 2 | 植栽面積 | OfficialChusankanField.planting_area | m2 | +| 3 | 作付け品目(元) | OfficialChusankanField.original_crop | ODS「作付け品目」列(役場記入の値) | +| 4 | 協定管理者 | OfficialChusankanField.manager | | +| 5 | 所有者 | OfficialChusankanField.owner | | +| 6 | 作物 | Plan.crop.name | 作付け計画から取得 | +| 7 | 品種 | Plan.variety.name | 〃(nullの場合は空欄) | +| 8 | 圃場名称 | Field.name | 吉田農地台帳の名称 | + +**複数圃場紐づき時の扱い:** +- 共済と同様、カンマ区切りで列挙 + +--- + +## 画面8: データ取込 ### 目的 -圃場マスタや申請マスタのインポート・エクスポート +圃場マスタや申請マスタのインポート ### レイアウト(PC) ``` ┌────────────────────────────────────────────────────┐ -│ 🌾 Keina System > データ管理 👤ログアウト │ +│ 🌾 KeinaSystem [作付け計画] [圃場管理] ... │ ├────────────────────────────────────────────────────┤ │ │ │ 📥 データインポート │ │ │ -│ タブ: [吉田農地台帳] [共済マスタ] [中山間マスタ] │ -│ │ │ ┌────────────────────────────────────────────────┐│ -│ │ 吉田農地台帳 (実圃場データ) ││ -│ │ ││ -│ │ 最終更新: 2025/02/01 ││ -│ │ 登録圃場数: 39筆 ││ +│ │ 吉田農地台帳(圃場マスタ) ││ │ │ ││ │ │ ファイルを選択: [ファイルを選択] 📎 ││ │ │ ││ │ │ ⚠️ 既存データは上書きされます ││ │ │ ││ -│ │ [プレビュー] [インポート実行] ││ +│ │ [インポート実行] ││ +│ └────────────────────────────────────────────────┘│ +│ │ +│ ┌────────────────────────────────────────────────┐│ +│ │ 共済マスタ ││ +│ │ ││ +│ │ ファイルを選択: [ファイルを選択] 📎 ││ +│ │ [インポート実行] ││ +│ └────────────────────────────────────────────────┘│ +│ │ +│ ┌────────────────────────────────────────────────┐│ +│ │ 中山間マスタ ││ +│ │ ││ +│ │ ファイルを選択: [ファイルを選択] 📎 ││ +│ │ [インポート実行] ││ │ └────────────────────────────────────────────────┘│ │ │ │ 📤 データエクスポート │ -│ │ │ • [全圃場データ (CSV)] ※バックアップ用 │ │ • [作付け計画 (CSV)] ※バックアップ用 │ -│ • [バックアップ (全データ ZIP)] │ -│ │ -│ 📄 申請書PDF生成 │ -│ → 「申請書ダウンロード」画面へ │ │ │ └────────────────────────────────────────────────────┘ ``` ### 機能要件 -- [ ] 3種類のマスタをタブで切り替え -- [ ] ファイルアップロード(ODS/Excel対応) -- [ ] プレビュー機能(インポート前に確認) -- [ ] インポート実行(確認ダイアログ付き) -- [ ] エクスポート機能(CSV/ZIP) +- [x] 3種類のマスタを縦並びで表示(タブではなく各セクション形式) +- [x] ファイルアップロード(ODS/Excel対応) +- [x] インポート実行(結果メッセージ表示) +- [ ] プレビュー機能(インポート前に確認)— **未実装** +- [ ] エクスポート機能(CSV)— **未実装(A-6)** --- @@ -595,7 +594,7 @@ ``` プライマリカラー(緑系): #2E7D32 濃い緑(ヘッダー、ボタン) - #4CAF50 緑(アクセント) + #4CAF50 緑(アクセント、アクティブなナビ項目) #81C784 淡い緑(ホバー) セカンダリカラー(土系): @@ -620,8 +619,8 @@ ``` フォント: - システムフォント優先 - - 日本語: "Hiragino Sans", "Yu Gothic", sans-serif - - 英数字: "Roboto", "Helvetica", sans-serif + - 日本語: "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif + - 英数字: Inter, "Roboto", "Helvetica", sans-serif サイズ: - 見出し(h1): 28px / 太字 @@ -663,10 +662,11 @@ PC: 1024px〜 - **ホバー**: 10%明るく、カーソルpointer - **押下**: 5%暗く、影を小さく -### モーダル -- **背景**: 半透明黒(opacity: 0.5) -- **アニメーション**: フェードイン(0.2秒) -- **閉じる**: 背景クリック or [×]ボタン or Escキー +### インライン編集(作付け計画) +- **ドロップダウン**: 選択変更と同時にバックグラウンド保存 +- **テキスト入力**: blur(フォーカスアウト)時に保存 +- **保存中**: ローディングスピナーは表示しない(スクロールリセット防止のため) +- **エラー時**: トースト通知でエラー表示 ### トースト通知 - **位置**: 画面右上 @@ -690,5 +690,5 @@ PC: 1024px〜 - **オートコンプリート**: 有効化 ### ナビゲーション -- **ハンバーガーメニュー**: 右上に配置 -- **戻るボタン**: 画面左上に配置 +- **Navbar**: PC版と同じ項目をレスポンシブに配置 +- **戻るボタン**: 画面左上に配置(詳細画面など) diff --git a/document/05_実装優先順位.md b/document/05_実装優先順位.md index 354a792..62c0a66 100644 --- a/document/05_実装優先順位.md +++ b/document/05_実装優先順位.md @@ -8,15 +8,15 @@ - [ ] ログイン・認証機能 - [ ] 作付け計画の一覧表示(PC/スマホ) - [ ] 作付け計画の編集(個別・一括) -- [ ] 水稲共済細目書のCSV出力 -- [ ] 中山間交付金のCSV出力 +- [ ] 水稲共済細目書のPDF出力 +- [ ] 中山間交付金のPDF出力 - [ ] 前年度作付けのコピー機能 - [ ] 3種類のマスタデータインポート ### 品質基準 - [ ] PCで快適に操作できる(レスポンス1秒以内) - [ ] スマホで見やすい(文字16px以上) -- [ ] 出力されるCSVが正確(手動検証でOK) +- [ ] 出力されるPDFが正確(手動検証でOK) ### ユーザビリティ基準 - [ ] 作付け計画の登録が10分以内で完了 @@ -84,10 +84,7 @@ ### Day 5-6: 作付け計画機能(コア機能) **Day 5: 作付け計画API** -- [ ] Django: 作物・品種マスタの初期データ投入 - - 作物: 米、トウモロコシ、エンドウ、野菜、その他 - - 品種: 米(にこまる等)、その他(完全休耕等) -- [ ] Django: 作付け計画API +- [ ] Django: 作付け計画API(作物・品種はUIまたは管理画面から登録) - 一覧取得 (`GET /api/plans/?year=2025`) - 作成・更新 (`POST /api/plans/`, `PATCH /api/plans/{id}/`) - 一括更新 (`POST /api/plans/bulk/`) @@ -105,13 +102,11 @@ - 作物別・品種別の合計面積 - リアルタイム更新 - **スマホ: 集計モーダル表示** -- [ ] Next.js: 作付け計画編集モーダル - - 作物選択(ドロップダウン) - - **品種選択(統一UI)** - - プリセット品種のドロップダウン - - [+ 新しい品種を追加]ボタン - - すべての作物で同じ操作 - - 一括割当対応 +- [ ] Next.js: 作付け計画インライン編集 + - 作物選択(テーブル内ドロップダウン) + - 品種選択(テーブル内ドロップダウン、作物選択後に有効化) + - 備考入力(テーブル内テキスト) + - 変更即時保存(バックグラウンド、スクロール維持) - [ ] Next.js: 前年度コピーボタン - [ ] 動作確認: 作付け計画を実際に入力 @@ -170,7 +165,7 @@ | 項目 | 採用技術 | 理由 | |------|---------|------| -| フレームワーク | Django 5.0 | 安定性、豊富なエコシステム | +| フレームワーク | Django 5.2 | 安定性、豊富なエコシステム | | REST API | Django REST Framework | 標準的なAPI構築ツール | | 認証 | djoser + SimpleJWT | JWT認証の簡単な実装 | | GIS | GeoDjango (PostGIS) | 地理情報の扱いに最適 | @@ -207,8 +202,8 @@ ### しっかり作り込むもの - 作付け計画一覧: 検索・フィルタ・ソート機能 -- 編集モーダル: 入力バリデーション、エラー表示 -- 申請書CSV: 正確なデータ集計ロジック +- インライン編集: 即時保存、スクロール維持 +- 申請書PDF: 正確なデータ集計ロジック、A4印刷対応 ### Phase 2以降に回すもの - 栽培履歴(播種日、作業記録) @@ -305,7 +300,7 @@ ### コミットメッセージ ``` feat: 作付け計画一覧APIを実装 -fix: 共済CSVの面積計算バグを修正 +fix: 共済PDFの面積計算バグを修正 docs: READMEにセットアップ手順を追加 style: Tailwindクラスを整理 ``` @@ -321,6 +316,6 @@ style: Tailwindクラスを整理 完成したら、以下を実施: 1. **使用感チェック**: 実際に作付け計画を入力してみる -2. **申請書検証**: 出力されたCSVを役場の書式と照合 +2. **申請書検証**: 出力されたPDFを役場の書式と照合 3. **改善点の洗い出し**: 「ここがもっとこうだったら...」を記録 4. **Phase 2の要件整理**: 栽培履歴機能の詳細を詰める diff --git a/document/06_ドキュメントvs実装_差異レポート.md b/document/06_ドキュメントvs実装_差異レポート.md index 37e5434..d03fef5 100644 --- a/document/06_ドキュメントvs実装_差異レポート.md +++ b/document/06_ドキュメントvs実装_差異レポート.md @@ -353,10 +353,84 @@ IsAuthenticated に変更 セキュリティ必須 --- -## E.追加で修正の要望 -### E-1.PDF出力される帳票のフォーマットが気に入らないです。 -ここ未定義なので、まずは仕様を決めましょう +## E. 追加で修正の要望 +### E-1: PDF帳票フォーマットの再設計 + +**現状の問題:** +- タイトルに中国語「申请书」が混入 +- セクション分け形式(表形式でない) +- `@page` 指定なし(A4サイズ・余白未設定) +- 面積が ha 表示 + +**対応方針:** 表形式(1行1区画)で、紙の書式に合わせる + +--- + +#### E-1a: 水稲共済細目書 PDF + +**フォーマット:** A4縦、表形式、31行 + +| # | 列名 | データ元 | 備考 | +|---|------|---------|------| +| 1 | 漢字地名 | OfficialKyosaiField.kanji_name | 例: 四万十町 笹ヶ谷 374-1 | +| 2 | 耕地-分筆 | k_num + "-" + s_num | 例: 2-1 | +| 3 | 本地面積 (m2) | OfficialKyosaiField.area | 内部 m2 で保存 | +| 4 | 作付品目 | Plan.crop.name | システムの作付け計画から | +| 5 | 品種 | Plan.variety.name | 〃 | +| 6 | 圃場名称 | Field.name | 吉田農地台帳の名称。複数圃場の場合はカンマ区切り | + +**補足:** +- 1つの共済区画に複数の実圃場が紐づく場合 → 作物・品種・圃場名をカンマ区切りで列挙 +- 作付け未設定の場合 → 「未設定」と表示 +- ヘッダー: 「水稲共済細目書(YYYY年度)」 +- ページ番号あり + +--- + +#### E-1b: 中山間交付金 PDF + +**フォーマット:** A4横(列が多いため)、表形式、71行 + +| # | 列名 | データ元 | 備考 | +|---|------|---------|------| +| 1 | 所在地 | 大字+字+地番+枝番 連結 | 例: 口神ノ川 壱町切 1694 | +| 2 | 植栽面積 | OfficialChusankanField.planting_area | ODS「植栽面積」列 | +| 3 | 作付け品目(元) | OfficialChusankanField.original_crop | ODS「作付け品目」列(役場記入) | +| 4 | 協定管理者 | OfficialChusankanField.manager | ODS「協定管理者」列 | +| 5 | 所有者 | OfficialChusankanField.owner | ODS「所有者」列 | +| 6 | 作物 | Plan.crop.name | システムの作付け計画から | +| 7 | 品種 | Plan.variety.name | 〃 | +| 8 | 圃場名称 | Field.name | 吉田農地台帳の名称 | + +**補足:** +- 1つの中山間区画に複数の実圃場が紐づく場合 → 作物・品種・圃場名をカンマ区切り +- ヘッダー: 「中山間地域等直接支払交付金(YYYY年度)」 +- ページ番号あり + +--- + +#### E-1c: OfficialChusankanField モデル拡張 + +現在のモデルに存在しない列を追加する(ODSの17列全部を保存): + +| 追加フィールド | ODS列名 | 型 | +|--------------|---------|---| +| chusankan_flag | 中山間 | CharField (〇など) | +| branch_num | 枝番 | CharField (-, 1, イ, ロ等) | +| land_type | 地目 | CharField (田, 畑等) | +| planting_area | 植栽面積 | IntegerField (m2) | +| original_crop | 作付け品目 | CharField (役場記入) | +| manager | 協定管理者 | CharField | +| owner | 所有者 | CharField (nullable) | +| slope | 傾斜度 | CharField (1/20等) | +| base_amount | 基本金額 | IntegerField | +| steep_slope_addition | 超急傾斜加算額 | DecimalField | +| smart_agri_addition | スマート農業加算額 | DecimalField | + +※ 既存フィールド: c_id, oaza, aza, chiban, area(農地面積), payment_amount(交付金額) + +--- ## 対応の進め方