ドキュメント更新(6ファイル)

03_データ仕様書.md — 全面書き直し(M:N関係、中山間17列モデル、面積単位、PDF出力仕様)
04_画面設計書.md — 全面書き直し(Navbar追加、圃場管理/新規作成画面追加、インライン編集方式、PDF帳票フォーマット仕様 E-1)
01_プロダクトビジョン.md — CSV→PDF、M:1→M:N
05_実装優先順位.md — CSV→PDF、Django 5.0→5.2、モーダル→インライン、init_crops削除
00_Gemini向け統合指示書.md — CSV→PDF、Django 5.2、M:N関係、中山間17列モデル、init_crops削除、IsAuthenticated
CLAUDE.md — 既知の課題一覧、次タスク優先順追加、中山間モデル拡張、差異レポートリンク
コード修正(4件)
D-1: reports/views.py — plan.crop / plan.variety の null チェック追加
D-2: init_crops.py を削除
D-3: settings.py — LANGUAGE_CODE/TIME_ZONE の二重定義を解消
D-4: settings.py — AllowAny → IsAuthenticated に変更
次のタスクは CLAUDE.md の優先順リストに従うと A-8(圃場詳細に共済/中山間情報表示)です。続けますか?
This commit is contained in:
Akira
2026-02-17 10:56:09 +09:00
parent 9c21caa017
commit 50e23872f3
11 changed files with 771 additions and 738 deletions

View File

@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(docker-compose exec:*)",
"Bash(python -c:*)"
]
}
}

View File

@@ -70,8 +70,7 @@ keinasystem_t02/
│ │ └── urls.py │ │ └── urls.py
│ ├── plans/ # 作付け計画アプリ │ ├── plans/ # 作付け計画アプリ
│ │ ├── models.py # Plan, Crop, Variety │ │ ├── models.py # Plan, Crop, Variety
│ │ ── views.py # 作付け計画API、集計API │ │ ── views.py # 作付け計画API、集計API
│ │ └── management/commands/init_crops.py # 初期データ投入
│ └── reports/ # 申請書生成アプリ │ └── reports/ # 申請書生成アプリ
│ ├── views.py # PDF生成API │ ├── views.py # PDF生成API
│ └── templates/ # PDF用HTMLテンプレート │ └── templates/ # PDF用HTMLテンプレート
@@ -102,7 +101,12 @@ OfficialKyosaiField (共済マスタ)
└── 31区画水稲共済細目書用 └── 31区画水稲共済細目書用
OfficialChusankanField (中山間マスタ) 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 (作付け計画) Plan (作付け計画)
├── field (FK to Field) ├── field (FK to Field)
@@ -201,6 +205,27 @@ Variety (品種マスタ)
2. **エラーハンドリング**: フロントエンドでの統一的なエラー表示が未実装 2. **エラーハンドリング**: フロントエンドでの統一的なエラー表示が未実装
3. **テスト**: 自動テストが未実装Phase 2で追加予定 3. **テスト**: 自動テストが未実装Phase 2で追加予定
4. **パフォーマンス**: N+1問題が一部存在現状は問題ないが、データ増加時に対応必要 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 ### 📅 次のマイルストーンPhase 2
@@ -273,6 +298,7 @@ docker-compose exec backend python manage.py migrate
- **データモデル詳細**: `document/03_データ仕様書.md` - **データモデル詳細**: `document/03_データ仕様書.md`
- **画面設計**: `document/04_画面設計書.md` - **画面設計**: `document/04_画面設計書.md`
- **実装手順**: `document/00_Gemini向け統合指示書.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: 初版作成(ハイブリッドアプローチの方針決定) - 2026-02-16: 初版作成(ハイブリッドアプローチの方針決定)

View File

@@ -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'))

View File

@@ -1,4 +1,3 @@
from django.shortcuts import render
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.http import HttpResponse from django.http import HttpResponse
from weasyprint import HTML from weasyprint import HTML
@@ -8,25 +7,25 @@ from apps.plans.models import Plan
def generate_kyosai_pdf(request, year): def generate_kyosai_pdf(request, year):
kyosai_fields = OfficialKyosaiField.objects.all() kyosai_fields = OfficialKyosaiField.objects.all()
data = [] data = []
for kyosai in kyosai_fields: for kyosai in kyosai_fields:
related_fields = kyosai.fields.all() related_fields = kyosai.fields.all()
plans = Plan.objects.filter(field__in=related_fields, year=year) plans = Plan.objects.filter(field__in=related_fields, year=year)
crops = {} crops = {}
total_area = 0 total_area = 0
for plan in plans: for plan in plans:
crop_name = plan.crop.name crop_name = plan.crop.name if plan.crop else '未設定'
if crop_name not in crops: if crop_name not in crops:
crops[crop_name] = { crops[crop_name] = {
'name': crop_name, 'name': crop_name,
'variety': plan.variety.name, 'variety': plan.variety.name if plan.variety else '',
'count': 0 'count': 0
} }
crops[crop_name]['count'] += 1 crops[crop_name]['count'] += 1
total_area += float(plan.field.area_tan) total_area += float(plan.field.area_tan)
data.append({ data.append({
'kyosai': kyosai, 'kyosai': kyosai,
'fields': related_fields, 'fields': related_fields,
@@ -34,14 +33,14 @@ def generate_kyosai_pdf(request, year):
'total_area': total_area, 'total_area': total_area,
'field_count': related_fields.count() 'field_count': related_fields.count()
}) })
html_string = render_to_string('reports/kyosai_template.html', { html_string = render_to_string('reports/kyosai_template.html', {
'year': year, 'year': year,
'data': data 'data': data
}) })
pdf = HTML(string=html_string).write_pdf() pdf = HTML(string=html_string).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf') response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="kyosai_{year}.pdf"' response['Content-Disposition'] = f'attachment; filename="kyosai_{year}.pdf"'
return response return response
@@ -49,25 +48,25 @@ def generate_kyosai_pdf(request, year):
def generate_chusankan_pdf(request, year): def generate_chusankan_pdf(request, year):
chusankan_fields = OfficialChusankanField.objects.all() chusankan_fields = OfficialChusankanField.objects.all()
data = [] data = []
for chusankan in chusankan_fields: for chusankan in chusankan_fields:
related_fields = chusankan.fields.all() related_fields = chusankan.fields.all()
plans = Plan.objects.filter(field__in=related_fields, year=year) plans = Plan.objects.filter(field__in=related_fields, year=year)
crops = {} crops = {}
total_area = 0 total_area = 0
for plan in plans: for plan in plans:
crop_name = plan.crop.name crop_name = plan.crop.name if plan.crop else '未設定'
if crop_name not in crops: if crop_name not in crops:
crops[crop_name] = { crops[crop_name] = {
'name': crop_name, 'name': crop_name,
'variety': plan.variety.name, 'variety': plan.variety.name if plan.variety else '',
'count': 0 'count': 0
} }
crops[crop_name]['count'] += 1 crops[crop_name]['count'] += 1
total_area += float(plan.field.area_tan) total_area += float(plan.field.area_tan)
data.append({ data.append({
'chusankan': chusankan, 'chusankan': chusankan,
'fields': related_fields, 'fields': related_fields,
@@ -75,14 +74,14 @@ def generate_chusankan_pdf(request, year):
'total_area': total_area, 'total_area': total_area,
'field_count': related_fields.count() 'field_count': related_fields.count()
}) })
html_string = render_to_string('reports/chusankan_template.html', { html_string = render_to_string('reports/chusankan_template.html', {
'year': year, 'year': year,
'data': data 'data': data
}) })
pdf = HTML(string=html_string).write_pdf() pdf = HTML(string=html_string).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf') response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="chusankan_{year}.pdf"' response['Content-Disposition'] = f'attachment; filename="chusankan_{year}.pdf"'
return response return response

View File

@@ -110,9 +110,9 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/ # 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 USE_I18N = True
@@ -134,7 +134,7 @@ REST_FRAMEWORK = {
'rest_framework_simplejwt.authentication.JWTAuthentication', 'rest_framework_simplejwt.authentication.JWTAuthentication',
), ),
'DEFAULT_PERMISSION_CLASSES': ( 'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny', 'rest_framework.permissions.IsAuthenticated',
), ),
} }
@@ -148,7 +148,3 @@ CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", "http://localhost:3000",
"http://127.0.0.1:3000", "http://127.0.0.1:3000",
] ]
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

View File

@@ -19,14 +19,14 @@
- PCで登録・編集、スマホで参照 - PCで登録・編集、スマホで参照
### 主要機能Phase 1 / MVP ### 主要機能Phase 1 / MVP
1. 作付け計画の一覧表示・編集 1. 作付け計画の一覧表示・インライン編集
2. 水稲共済細目書のCSV出力 2. 水稲共済細目書のPDF出力
3. 中山間交付金申請書のCSV出力 3. 中山間交付金申請書のPDF出力
4. 前年度作付けのコピー機能 4. 前年度作付けのコピー機能
5. 圃場情報のスマホ参照 5. 圃場情報のスマホ参照
### 技術スタック ### 技術スタック
- **バックエンド**: Django 5.0 + Django REST Framework + GeoDjango - **バックエンド**: Django 5.2 + Django REST Framework + GeoDjango
- **フロントエンド**: Next.js 14 (App Router) + Tailwind CSS - **フロントエンド**: Next.js 14 (App Router) + Tailwind CSS
- **データベース**: PostgreSQL 16 + PostGIS 3.4 - **データベース**: PostgreSQL 16 + PostGIS 3.4
- **インフラ**: Docker Compose - **インフラ**: Docker Compose
@@ -49,8 +49,8 @@
### 3. データ仕様書.md ### 3. データ仕様書.md
- 3種類のデータ実圃場、共済マスタ、中山間マスタの関係 - 3種類のデータ実圃場、共済マスタ、中山間マスタの関係
- 紐付けロジックM:1関係)の詳細 - 紐付けロジックM:N関係)の詳細
- 申請書CSV出力のアルゴリズム - 申請書PDF出力のアルゴリズム
- **👉 読むべき理由**: データモデルの設計ミスは後から修正困難 - **👉 読むべき理由**: データモデルの設計ミスは後から修正困難
### 4. 画面設計書.md ### 4. 画面設計書.md
@@ -149,7 +149,7 @@ volumes:
#### backend/requirements.txt #### backend/requirements.txt
```txt ```txt
Django==5.0 Django==5.2
djangorestframework==3.14 djangorestframework==3.14
django-cors-headers==4.3 django-cors-headers==4.3
psycopg2-binary==2.9 psycopg2-binary==2.9
@@ -227,25 +227,36 @@ from django.contrib.gis.db import models
class OfficialKyosaiField(models.Model): class OfficialKyosaiField(models.Model):
"""共済マスタ(水稲共済細目用.ods""" """共済マスタ(水稲共済細目用.ods"""
k_num = models.IntegerField("耕地番号") k_num = models.CharField("耕地番号", max_length=20)
s_num = models.IntegerField("分筆番号") s_num = models.CharField("分筆番号", max_length=20, blank=True)
address = models.CharField("地名地番", max_length=200) address = models.CharField("地名地番", max_length=200)
kanji_name = models.CharField("漢字地名", max_length=200) kanji_name = models.CharField("漢字地名", max_length=200)
area = models.FloatField("本地面積(m2)") area = models.IntegerField("本地面積(m2)")
class Meta: class Meta:
unique_together = [['k_num', 's_num']] unique_together = [['k_num', 's_num']]
ordering = ['k_num', 's_num'] ordering = ['k_num', 's_num']
class OfficialChusankanField(models.Model): class OfficialChusankanField(models.Model):
"""中山間マスタ(中山間.ods""" """中山間マスタ(中山間.ods- 17列全て保存"""
c_id = models.IntegerField("ID", unique=True) 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) oaza = models.CharField("大字", max_length=100)
aza = 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)") 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) payment_amount = models.IntegerField("交付金額", null=True, blank=True)
class Meta: class Meta:
ordering = ['c_id'] ordering = ['c_id']
@@ -257,22 +268,19 @@ class Field(models.Model):
area_m2 = models.IntegerField("面積(m2)") # area_tan * 1000 area_m2 = models.IntegerField("面積(m2)") # area_tan * 1000
owner_name = models.CharField("地主", max_length=100) owner_name = models.CharField("地主", max_length=100)
# 紐付けキーraw値 # グループ・表示順
raw_kyosai_k_num = models.IntegerField("細目_耕地番号") group_name = models.CharField("グループ名", max_length=100, blank=True)
raw_kyosai_s_num = models.IntegerField("細目_分筆番号") display_order = models.IntegerField("表示順", default=0)
raw_chusankan_id = models.IntegerField("中山間_ID", null=True, blank=True)
# M:N紐付け1つの圃場が複数の申請区画に紐づく場合がある
# 外部キー(紐付け済み) kyosai_fields = models.ManyToManyField(
kyosai_field = models.ForeignKey( OfficialKyosaiField,
OfficialKyosaiField, blank=True,
on_delete=models.SET_NULL,
null=True,
related_name='fields' related_name='fields'
) )
chusankan_field = models.ForeignKey( chusankan_fields = models.ManyToManyField(
OfficialChusankanField, OfficialChusankanField,
on_delete=models.SET_NULL, blank=True,
null=True,
related_name='fields' related_name='fields'
) )
@@ -347,97 +355,52 @@ def import_kyosai_master(request):
@api_view(['POST']) @api_view(['POST'])
def import_yoshida_fields(request): def import_yoshida_fields(request):
"""吉田農地台帳のインポート(紐付け処理含む)""" """吉田農地台帳のインポート(M:N紐付け処理含む)"""
file = request.FILES['file'] file = request.FILES['file']
df = pd.read_excel(file, engine='odf') df = pd.read_excel(file, engine='odf')
for _, row in df.iterrows(): 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['名称'], name=row['名称'],
defaults={ defaults={
'address': row['住所'], 'address': row['住所'],
'area_tan': row['面積(反)'], 'area_tan': row['面積(反)'],
'area_m2': int(row['面積(反)'] * 1000), 'area_m2': int(row['面積(反)'] * 1000),
'owner_name': row['地主'], '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)}) return Response({'status': 'success', 'imported': len(df)})
``` ```
### Step 5: 作付け計画APIDay 5 ### Step 5: 作付け計画APIDay 5
#### 作物・品種の初期データ投入 #### 作物・品種マスタについて
**apps/plans/management/commands/init_crops.py** 初期データの自動投入は行わない。作物・品種はDjango管理画面またはUIから手動で登録する運用とする。
```python
from django.core.management.base import BaseCommand
from apps.plans.models import Crop, Variety
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 #### apps/plans/views.py
```python ```python
@@ -921,23 +884,16 @@ export default function ReportsPage() {
## ⚠️ 重要な実装上の注意点 ## ⚠️ 重要な実装上の注意点
### 1. データベース設計 ### 1. データベース設計
- **面積単位**: DB内部は全て `m2` で保存、表示`反` に変換 - **面積単位**: DB内部は `area_m2`IntegerFieldで保存、表示`area_tan`DecimalFieldも保持。1反=1000m2
- **紐付けキー**: `raw_*` フィールドと外部キー `*_field` の両方を持つ - **紐付け**: Field ↔ OfficialKyosaiField、Field ↔ OfficialChusankanField は **M:N**ManyToManyField
- **ユニーク制約**: `(field, year)` で作付け計画は1つまで - **ユニーク制約**: `(field, year)` で作付け計画は1つまで`(k_num, s_num)` で共済区画は一意
- **品種マスタ**: `(crop, name)` で一意制約 - **品種マスタ**: `(crop, name)` で一意制約
### 2. 作物・品種の統一 ### 2. 作物・品種の統一
- **すべての作物で品種選択UIは統一**: 作物による操作の違いなし - **すべての作物で品種選択UIは統一**: 作物による操作の違いなし
- **「作付けしない」系も特別扱いしない**: 「その他」という作物に統一 - **「作付けしない」系も特別扱いしない**: 「その他」という作物に統一
- **品種の追加**: その場で追加可能、データベースに永続化 - **品種の追加**: その場で追加可能、データベースに永続化
- **初期データ**: - **初期データ**: なし管理画面またはUIから登録する運用
```
米: にこまる、たちはるか、たちはるか(特栽)
トウモロコシ: (ユーザーが追加)
エンドウ: 久留米豊
野菜: (ユーザーが追加)
その他: 完全休耕、緑肥(ヘアリーベッチ)、緑肥(レンゲ)、景観作物(コスモス)、景観作物(ヒマワリ)
```
### 3. 集計サイドバー ### 3. 集計サイドバー
- **リアルタイム更新**: 作付け計画を保存するたびに自動更新 - **リアルタイム更新**: 作付け計画を保存するたびに自動更新

View File

@@ -13,7 +13,7 @@
2. **実圃場と申請区画のずれを管理する** 2. **実圃場と申請区画のずれを管理する**
- 実際に作業する圃場39筆と、申請書上の区画共済31区画、中山間71区画が異なる - 実際に作業する圃場39筆と、申請書上の区画共済31区画、中山間71区画が異なる
- 複数の実圃場が1つの申請区画紐づ関係M:1)を明示的に管理 - 実圃場と申請区画紐づ関係M:N)を明示的に管理
- 紐付けは半自動化するが、手動修正も可能にする - 紐付けは半自動化するが、手動修正も可能にする
3. **将来の拡張を見据えた設計** 3. **将来の拡張を見据えた設計**
@@ -95,7 +95,7 @@
**パフォーマンス:** **パフォーマンス:**
- 圃場一覧の表示: 1秒以内 - 圃場一覧の表示: 1秒以内
- 申請書CSVの生成: 3秒以内 - 申請書PDFの生成: 3秒以内
- スマホでの圃場詳細表示: 2秒以内 - スマホでの圃場詳細表示: 2秒以内
--- ---
@@ -140,7 +140,7 @@
**Phase 1MVP: 2025年2月まで** **Phase 1MVP: 2025年2月まで**
- 作付け計画の登録・編集 - 作付け計画の登録・編集
- 申請書(水稲共済・中山間)のCSV出力 - 申請書(水稲共済・中山間)のPDF出力
- 圃場一覧の参照PC/スマホ) - 圃場一覧の参照PC/スマホ)
**Phase 2: 2025年3月** **Phase 2: 2025年3月**

View File

@@ -1,5 +1,8 @@
# データ仕様書 # データ仕様書
> **最終更新**: 2026-02-16
> **変更履歴**: M:N関係に更新、中山間モデル全17列対応、面積単位統一、帳票仕様追加
## 📊 データ構造の全体像 ## 📊 データ構造の全体像
このシステムで扱うデータは3種類 このシステムで扱うデータは3種類
@@ -9,53 +12,80 @@
3. **中山間マスタ**(中山間.ods- 申請書用の区画 3. **中山間マスタ**(中山間.ods- 申請書用の区画
**紐付けの関係:** **紐付けの関係:**
- 実圃場 共済区画: **M対1**複数の実圃場が1つの共済区画に対応 - 実圃場 共済区画: **M対N**複数の実圃場が1つの共済区画に対応、また1つの実圃場が複数の共済区画に対応するケースもある
- 実圃場 中山間区画: **M対1**複数の実圃場が1つの中山間区画に対応 - 実圃場 中山間区画: **M対N**同上
```mermaid ```mermaid
erDiagram erDiagram
実圃場 }o--|| 共済区画 : "紐づく(M:1)" 実圃場 }o--o{ 共済区画 : "紐づく(M:N)"
実圃場 }o--|| 中山間区画 : "紐づく(M:1)" 実圃場 }o--o{ 中山間区画 : "紐づく(M:N)"
実圃場 ||--o{ 作付け計画 : "持つ(1:N)" 実圃場 ||--o{ 作付け計画 : "持つ(1:N)"
作付け計画 }o--|| 作物 : "参照"
作付け計画 }o--o| 品種 : "参照(任意)"
作物 ||--o{ 品種 : "持つ"
実圃場 { 実圃場 {
int id PK int id PK
string 名称 string 名称
string 住所 string 住所
float 面積_反 decimal 面積_反
int 面積_m2
string 地主 string 地主
int 細目_耕地番号 "共済紐付けキー" string グループ名
int 細目_分筆番号 "共済紐付けキー" int 表示順
int 中山間_ID "中山間紐付けキー" string 細目_耕地番号 "共済紐付けキー(raw)"
string 細目_分筆番号 "共済紐付けキー(raw)"
string 中山間_ID "中山間紐付けキー(raw)"
} }
共済区画 { 共済区画 {
int id PK int id PK
string 地名_地番 string 地名_地番
int 耕地番号 int 耕地番号
int 分筆番号 int 分筆番号
float 本地面積_m2 decimal 本地面積_m2
string 漢字地名 string 漢字地名
} }
中山間区画 { 中山間区画 {
int id PK int id PK
int ID string 中山間ID
string 中山間フラグ
string 大字 string 大字
string 字 string 字
int 地番 string 地番
string 枝番
string 地目
int 農地面積_m2 int 農地面積_m2
int 植栽面積_m2
string 作付け品目_元
string 協定管理者
string 所有者
string 傾斜度
int 基本金額
decimal 超急傾斜加算額
decimal スマート農業加算額
int 交付金額 int 交付金額
} }
作付け計画 { 作付け計画 {
int id PK int id PK
int 実圃場_id FK int 実圃場_id FK
int 年度 int 年度
string 作物 int 作物_id FK
string 品種 int 品種_id FK_nullable
date 播種日 text 備考
date 収穫日 }
作物 {
int id PK
string 作物名
}
品種 {
int id PK
int 作物_id FK
string 品種名
} }
``` ```
@@ -79,6 +109,24 @@ erDiagram
| 細目_分筆番号 | int | ○ | 共済マスタとの紐付けキー2/2 | 1 | | 細目_分筆番号 | int | ○ | 共済マスタとの紐付けキー2/2 | 1 |
| 中山間_ID | int | △ | 中山間マスタとの紐付けキー | 50 | | 中山間_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 名称 住所 面積(反) 細目_耕地番号 細目_分筆番号 中山間_ID
@@ -90,7 +138,9 @@ erDiagram
### 特記事項 ### 特記事項
- **中山間_IDは一部NULL**: 39筆中2筆が中山間の対象外`NaN` - **中山間_IDは一部NULL**: 39筆中2筆が中山間の対象外`NaN`
- **同じ共済区画に複数の実圃場**: 例えば共済キー「2-2」には3つの実圃場が紐づく - **同じ共済区画に複数の実圃場**: 例えば共済キー「2-2」には3つの実圃場が紐づく
- **面積単位**: DB内部では「反」と「m2」の両方を保持する変換: 1反=1000m2 - **1つの実圃場が複数の申請区画に紐づくケースもある**: M:N関係で対応
- **面積単位**: DB内部では「反DecimalField」と「m2IntegerField」の両方を保持する変換: 1反=1000m2
- **グループ機能**: group_name でエリア分け、display_order で表示順を制御
--- ---
@@ -110,6 +160,18 @@ erDiagram
| 本地面積 (m2) | float | ○ | 申請上の面積(単位: m2 | 25.4 | | 本地面積 (m2) | float | ○ | 申請上の面積(単位: m2 | 25.4 |
| 漢字地名 | string | ○ | 漢字表記の地名 | "四万十町 笹ヶ谷 374-1" | | 漢字地名 | 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) 漢字地名 地名 地番 耕地番号 分筆番号 本地面積(m2) 漢字地名
@@ -129,97 +191,114 @@ erDiagram
### ファイル情報 ### ファイル情報
- **行数:** 71行71区画 - **行数:** 71行71区画
- **列数:** 17列うち使用するのは一部 - **列数:** 17列全列をDBに保存
### カラム定義(主要なもの ### カラム定義(全17列
| カラム名 | データ型 | 必須 | 説明 | 例 | | カラム名 | データ型 | 必須 | 説明 | 例 |
|---------|---------|-----|------|---| |---------|---------|-----|------|---|
| ID | int | ○ | 中山間区画の識別子 | 50 | | ID | int | ○ | 中山間区画の識別子 | 1 |
| 中山間 | string | ○ | 中山間フラグ | "" |
| 大字 | string | ○ | 大字名 | "口神ノ川" | | 大字 | string | ○ | 大字名 | "口神ノ川" |
| 字 | string | ○ | 字名 | "壱町切" | | 字 | string | ○ | 字名 | "壱町切" |
| 地番 | int | ○ | 地番 | 1694 | | 地番 | string | ○ | 地番(数値でないケースあり:イ、ロ等) | "1694" |
| 農地面積 | int | | 面積(単位: m2 | 2900 | | 枝番 | string | | 枝番(-, 1, イ, ロ等) | "-" |
| 作付け品目 | string | | (役場が記入、システムでは上書き) | "ニラ" | | 目 | string | | 地目 | "" |
| 交付金額 | int | | 交付金額 | 37700 | | 農地面積 | 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 大字 字 地番 農地面積 作付け品目 交付金額 ID 中山間 大字 字 地番 枝番 地目 農地面積 植栽面積 作付け品目 協定管理者 所有者 傾斜度 基本金額 交付金額
50 口神ノ川 笹ヶ谷 374 2698 米 xxxxxx 1 口神ノ川 壱町切 1694 - 田 2900 2748 ニラ 神山倫子 1/29 23200 37700
2 口神ノ川 大窪 490 1 田 652 490 野菜 谷脇誠一 谷脇史男 1/20 15204 18824
``` ```
### 特記事項 ### 特記事項
- **使用する列は限定的**: システムでは主に「ID」「大字」「字」「地番」「農地面積」を使用 - **全17列をDBに保存**: 将来どの列が必要になるかわからないため全保存
- **作付け品目は上書き**: 役場が記入した「作付け品目」は参考情報で、システムで上書きす - **地番・枝番は文字列型**: 「イ」「ロ」などの非数値データが入
- **作付け品目は参考情報**: 役場が記入した値。システムの作付け計画Planとは別
- **面積の不整合は許容**: 共済マスタと同様、実圃場との差異は受け入れる - **面積の不整合は許容**: 共済マスタと同様、実圃場との差異は受け入れる
--- ---
## 4. 作付け計画データ(システム内部) ## 4. 作付け計画データ(システム内部)
### テーブル定義 ### DBモデルPlan
| カラム名 | データ型 | 必須 | 説明 | | フィールド名 | データ型 | 必須 | 説明 |
|---------|---------|-----|------| |-------------|---------|-----|------|
| id | int | ○ | 主キー(自動採番) | | id | int (自動) | ○ | 主キー |
| field_id | int | ○ | 実圃場ID(外部キー) | | field | FK → Field | ○ | 実圃場(外部キー) |
| year | int | ○ | 年度2025など | | year | IntegerField | ○ | 年度2025など |
| crop | string | | 作物(「米」「トウモロコシ」など | | crop | FK → Crop, nullable | | 作物(外部キー |
| variety | string | △ | 品種(「にこまる」など | | variety | FK → Variety, nullable | △ | 品種外部キー、NULLあり |
| planting_date | date | △ | 播種日/定植日Phase 2 | | notes | TextField, nullable | △ | 備考 |
| harvest_date | date | △ | 収穫日Phase 2 |
| notes | text | △ | 備考 |
### 制約 ### 制約
- **ユニーク制約**: (field_id, year) - 1つの圃場に対して1年度につき1つの作付け計画のみ - **ユニーク制約**: (field, year) - 1つの圃場に対して1年度につき1つの作付け計画のみ
- Phase 2で二毛作対応する場合は、この制約を見直す - Phase 2で二毛作対応する場合は、この制約を見直す
### 備考
- planting_date播種日、harvest_date収穫日は Phase 2 で追加予定
- crop, variety は外部キー(文字列ではなくリレーション)
--- ---
## 5. 作物マスタ ## 5. 作物マスタ
### 作物リスト ### DBモデルCrop
-
- トウモロコシ
- エンドウ
- 野菜
- その他
### 品種の登録方法 | フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| id | int (自動) | 主キー |
| name | CharField(50), unique | 作物名 |
**すべての作物で統一されたUI:** ### DBモデルVariety
- プリセット品種から選択
- その場で新しい品種を追加可能
- 作物による操作の違いなし
### プリセット品種の例 | フィールド名 | データ型 | 説明 |
|-------------|---------|------|
| id | int (自動) | 主キー |
| crop | FK → Crop | 所属する作物 |
| name | CharField(100) | 品種名 |
#### 米 **制約:** (crop, name) のペアで一意
- にこまる
- たちはるか
- たちはるか(特栽)
#### トウモロコシ ### 作物・品種の管理方針
- (ユーザーが追加 - 初期データは投入しない管理画面またはUIから登録
- すべての作物で品種選択UIは統一
#### エンドウ - 「作付けしない」系も特別扱いしない(「その他」作物の品種として扱う)
- 久留米豊 - 品種の追加・削除は作付け計画画面から可能
#### 野菜
- (ユーザーが追加)
#### その他
- 完全休耕
- 緑肥(ヘアリーベッチ)
- 緑肥(レンゲ)
- 景観作物(コスモス)
- 景観作物(ヒマワリ)
### 実装上の注意
- すべての作物で `Variety` テーブルに品種を登録
- 「作付けしない」系を特別扱いしない
- UIは完全に統一
--- ---
@@ -233,31 +312,31 @@ ID 大字 字 地番 農地面積 作付け品目 交付金額
2. **中山間マスタのインポート** 2. **中山間マスタのインポート**
- `中山間.ods` を読み込み - `中山間.ods` を読み込み
- `OfficialChusankanField` テーブルに保存 - `OfficialChusankanField` テーブルに全17列を保存
3. **実圃場データのインポート** 3. **実圃場データのインポート**
- `吉田農地台帳.ods` を読み込み - `吉田農地台帳.ods` を読み込み
- `Field` テーブルに保存 - `Field` テーブルに保存
- 同時に共済・中山間マスタとの紐付けを確立: - 同時に共済・中山間マスタとの紐付けを確立ManyToMany:
- `細目_耕地番号` + `細目_分筆番号``OfficialKyosaiField.id`外部キーとして保存 - `細目_耕地番号` + `細目_分筆番号``OfficialKyosaiField`検索して M:N 関連に追加
- `中山間_ID``OfficialChusankanField.id`外部キーとして保存 - `中山間_ID``OfficialChusankanField`検索して M:N 関連に追加
### 紐付けロジック ### 紐付けロジック
```python ```python
# 共済マスタとの紐付け # 共済マスタとの紐付けM:N
kyosai_record = OfficialKyosaiField.objects.get( kyosai_record = OfficialKyosaiField.objects.get(
k_num=row['細目_耕地番号'], k_num=row['細目_耕地番号'],
s_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']): if pd.notna(row['中山間_ID']):
chusankan_record = OfficialChusankanField.objects.get( 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サイズ、縦向き - A4サイズ、縦向き
- ヘッダー: 「水稲共済細目書(◯◯年度)」 - ヘッダー: 「水稲共済細目書(YYYY年度)」
- 表形式(罫線あり) - 表形式(罫線あり)、1行1区画31行
- フォントサイズ: 10pt - フォントサイズ: 10pt
- ページ番号(複数ページの場合) - ページ番号あり
**表の列:** **表の列:**
```
耕地番号 | 分筆番号 | 地名地番 | 漢字地名 | 本地面積(m2) | 作付品目 | 品種 | 備考 | 列名 | データ元 | 備考 |
1 | 1 | 四万十町... | 四万十町... | 2.2 | 米 |にこまる| |------|---------|------|
2 | 1 | 四万十町... | 四万十町... | 25.4 | 米 |にこまる| | 漢字地名 | OfficialKyosaiField.kanji_name | 例: 四万十町 笹ヶ谷 374-1 |
2 | 2 | 四万十町... | 四万十町... | 12.0 |米,野菜|にこまる,トマト|複数圃場 | 耕地-分筆 | k_num + "-" + s_num | 例: 2-1 |
``` | 本地面積 (m2) | OfficialKyosaiField.area | |
| 作付品目 | Plan.crop.name | システムの作付け計画から |
| 品種 | Plan.variety.name | 〃 |
| 圃場名称 | Field.name | 吉田農地台帳の名称 |
**集計ロジック:** **集計ロジック:**
```python 1. 共済マスタ31区画をループ
def generate_kyosai_pdf(year): 2. 各共済区画に紐づく実圃場を取得M:N関係
# 1. データ集約CSVと同じロジック 3. 紐づく実圃場の作付け情報を集約(作物名・品種名・圃場名をカンマ区切り)
output_rows = [] 4. HTMLテンプレートで表を生成 → WeasyPrint で PDF変換
for kyosai in OfficialKyosaiField.objects.all().order_by('k_num', 's_num'): 5. 複数の実圃場が紐づく場合 → 作物・品種・圃場名をカンマ区切りで列挙
fields = Field.objects.filter(kyosai_field_ref=kyosai.id) 6. 作付け未設定の場合 → 「未設定」と表示
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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
@page { size: A4; margin: 2cm; }
body { font-family: "MS Gothic", monospace; font-size: 10pt; }
h1 { text-align: center; font-size: 14pt; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid black; padding: 5px; text-align: center; }
th { background-color: #f0f0f0; }
</style>
</head>
<body>
<h1>水稲共済細目書({{ year }}年度)</h1>
<table>
<thead>
<tr>
<th>耕地番号</th>
<th>分筆番号</th>
<th>地名地番</th>
<th>漢字地名</th>
<th>本地面積(m2)</th>
<th>作付品目</th>
<th>品種</th>
<th>備考</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.耕地番号 }}</td>
<td>{{ row.分筆番号 }}</td>
<td>{{ row.地名地番 }}</td>
<td>{{ row.漢字地名 }}</td>
<td>{{ row.本地面積(m2) }}</td>
<td>{{ row.作付品目 }}</td>
<td>{{ row.品種 }}</td>
<td>{{ row.備考 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
```
### 中山間交付金申請 ### 中山間交付金申請
**出力形式:** **出力形式:**
- 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 - 水稲共済と同様、中山間マスタをループして実圃場を集約 → HTMLテンプレート → PDF
@@ -395,7 +409,7 @@ ID | 大字 | 字 | 地番 | 農地面積(m2) | 作付品目 | 品種 | 備考
- または、全削除→再インポートの2段階処理 - または、全削除→再インポートの2段階処理
### バックアップ ### バックアップ
- 全テーブルをCSV/Excelでエクスポート可能にする - 全テーブルをCSV/Excelでエクスポート可能にする(サーバー移行時にも利用)
- 最低5年分のデータを保持補助金監査対応 - 最低5年分のデータを保持補助金監査対応
--- ---
@@ -404,15 +418,17 @@ ID | 大字 | 字 | 地番 | 農地面積(m2) | 作付品目 | 品種 | 備考
システム内部では以下のように統一: システム内部では以下のように統一:
| 表示単位 | DB保存 | 変換式 | | 用途 | 単位 | DB | 変換式 |
|---------|--------|--------| |-----|------|------|--------|
| 反(たん) | m2 | 1反 = 1000m2 | | 実圃場の面積DB保存 | 反 + m2 | DecimalField + IntegerField | 1反 = 1000m2 |
| アールa | m2 | 1a = 100m2 | | 共済マスタの面積DB保存 | m2 | IntegerField | - |
| ヘクタールha | m2 | 1ha = 10000m2 | | 中山間マスタの面積DB保存 | m2 | IntegerField | - |
| 画面表示 | 反 | - | area_m2 / 1000 |
**実装方針:** **実装方針:**
- DB内部は全て `m2` で保存(整数型) - 実圃場: `area_tan`DecimalField`area_m2`IntegerFieldの両方を保持
- 表示時にユーザー設定に応じて変換(デフォルトは「反」) - 共済・中山間マスタ: `area` は m2IntegerFieldで保存
- 表示時は「反」に統一1反 = 10a = 1000m2
- 入力時は「反」で受け付け、内部で `m2` に変換 - 入力時は「反」で受け付け、内部で `m2` に変換
--- ---

View File

@@ -1,5 +1,8 @@
# 画面設計書 # 画面設計書
> **最終更新**: 2026-02-16
> **変更履歴**: 実装済み機能との差異を解消B-1〜B-5, C-6, E-1 反映)
## 🎨 デザイン原則(再掲) ## 🎨 デザイン原則(再掲)
1. **シンプル・イズ・ベスト**: 1画面1機能 1. **シンプル・イズ・ベスト**: 1画面1機能
@@ -10,28 +13,57 @@
--- ---
## 🧭 共通ナビゲーションNavbar
### PC レイアウト
上部に水平ナビゲーションバーを常時表示。ブランド名「KeinaSystem」と主要画面へのリンクを配置。
```
┌──────────────────────────────────────────────────────────────┐
│ 🌾 KeinaSystem [作付け計画] [圃場管理] [帳票出力] [データ取込] [ログアウト] │
└──────────────────────────────────────────────────────────────┘
```
### ナビゲーション項目
| アイコン | ラベル | パス | 説明 |
|---------|--------|------|------|
| 🌾 (Wheat) | 作付け計画 | `/allocation` | 作付け計画編集画面(メイン) |
| 📍 (MapPin) | 圃場管理 | `/fields` | 圃場一覧・編集 |
| 📄 (FileText) | 帳票出力 | `/reports` | 申請書PDFダウンロード |
| ⬆️ (Upload) | データ取込 | `/import` | マスタインポート |
### 仕様
- アクティブなページのリンクは緑背景でハイライト
- ログアウトボタンは右端に配置
- スマホではレスポンシブにタブバーまたはハンバーガーメニューに切り替え
---
## 📱 画面一覧 ## 📱 画面一覧
### Phase 1MVP ### Phase 1MVP
1. **ログイン画面** 1. **ログイン画面** (`/login`)
2. **ダッシュボード**将来拡張用、Phase 1では簡易版 2. **ダッシュボード** (`/`) — 将来拡張用、Phase 1では簡易版
3. **作付け計画一覧**(メイン画面) 3. **作付け計画一覧・編集** (`/allocation`) — メイン画面、インライン編集方式
4. **作付け計画編集**(モーダル/サイドパネル) 4. **圃場管理一覧** (`/fields`) — 圃場の一覧表示・グループ管理・表示順管理
5. **圃場詳細**(スマホ参照用) 5. **圃場詳細・編集** (`/fields/[id]`) — 個別圃場の情報編集
6. **申請書ダウンロード** 6. **圃場新規作成** (`/fields/new`) — 手動での圃場登録
7. **データ管理**(インポート・エクスポート) 7. **申請書ダウンロード** (`/reports`) — PDFダウンロード
8. **データ取込** (`/import`) — インポート
### Phase 2以降 ### Phase 2以降
8. 栽培履歴入力 9. 栽培履歴入力
9. 作業カレンダー 10. 作業カレンダー
10. 資材計画 11. 資材計画
--- ---
## 画面1: ログイン画面 ## 画面1: ログイン画面
### 目的 ### 目的
シンプルな認証(メール+パスワード) シンプルな認証(ユーザー名+パスワード)
### レイアウトPC/スマホ共通) ### レイアウトPC/スマホ共通)
@@ -42,7 +74,7 @@
│ 作付け計画管理システム │ │ 作付け計画管理システム │
│ │ │ │
│ ┌───────────────────────┐ │ │ ┌───────────────────────┐ │
│ │ メールアドレス │ │ │ │ ユーザー名 │ │
│ │ [___________________] │ │ │ │ [___________________] │ │
│ └───────────────────────┘ │ │ └───────────────────────┘ │
│ │ │ │
@@ -57,9 +89,9 @@
``` ```
### 機能要件 ### 機能要件
- [ ] メールアドレスとパスワードで認証 - [x] ユーザー名とパスワードで認証JWT
- [ ] ログイン成功 → ダッシュボードへ遷移 - [x] ログイン成功 → 作付け計画画面へ遷移
- [ ] ログイン失敗 → エラーメッセージ表示 - [x] ログイン失敗 → エラーメッセージ表示
- [ ] 「パスワードを忘れた」リンクPhase 2 - [ ] 「パスワードを忘れた」リンクPhase 2
--- ---
@@ -69,11 +101,15 @@
### 目的 ### 目的
システムの入り口Phase 1では簡易版、将来拡張 システムの入り口Phase 1では簡易版、将来拡張
### レイアウトPC ### 現在の実装
- `/` アクセス時、トークンの有無で `/allocation`(ログイン済み)か `/login`(未ログイン)にリダイレクト
- ダッシュボード画面自体は未実装
### レイアウト将来実装予定、PC
``` ```
┌────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────┐
│ 🌾 Keina System 2025年度 ▼ 👤ログアウト │ 🌾 KeinaSystem [作付け計画] [圃場管理] ...
├────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────┤
│ │ │ │
│ 📊 概要 │ │ 📊 概要 │
@@ -94,54 +130,55 @@
└────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────┘
``` ```
### 機能要件(Phase 1 ### 機能要件(将来実装予定
- [ ] 年度選択(ドロップダウン) - [ ] 年度選択(ドロップダウン)
- [ ] 作付け状況のサマリー表示 - [ ] 作付け状況のサマリー表示
- [ ] 「作付け計画を編集」→ 画面3へ - [ ] 「作付け計画を編集」→ 画面3へ
- [ ] 「申請書ダウンロード」→ 画面6 - [ ] 「申請書ダウンロード」→ 画面7
- [ ] 将来の機能追加時にボタンを追加していく想定
--- ---
## 画面3: 作付け計画一覧(メイン画面) ## 画面3: 作付け計画一覧・編集(メイン画面)
### 目的 ### 目的
全圃場の作付け状況を一覧で確認編集 全圃場の作付け状況を一覧で確認し、**インライン**で直接編集
### 編集方式
**インライン編集**を採用モーダルではない。テーブル行内のドロップダウンで作物・品種を選択し、変更は即座にAPIに保存される。
### レイアウトPC ### レイアウトPC
``` ```
┌──────────────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────────────────┐
│ 🌾 Keina System > 作付け計画一覧 2025年度 ▼ 👤ログアウト │ 🌾 KeinaSystem [作付け計画] [圃場管理] [帳票出力] [データ取込]
├──────┬───────────────────────────────────────────────────────────┤ ├──────┬───────────────────────────────────────────────────────────┤
│ │ │ │ │ │
│ 📊 │ 🔍 [検索: 圃場名・住所_____________] 🔽絞込: [全て▼] │ 📊 │ 年度: [2025 ▼] 並び順: [カスタム順 ▼]
│ 集計 │ │ │ 集計 │ │
│ │ ☐ 未割当のみ表示 [📋 前年度をコピー] [📊 申請書作成] │ │ ────────────────────────────────────────────────────────
│ ──────────────────────────────────────────────────────────────── │ ──── │ グループ 圃場名 面積 作物 品種 備考 順序
米 │ No. ☐ 名称 住所 面積 作付 品種 操作 合計 │ ────────────────────────────────────────────────────────
15.3反│ ──────────────────────────────────────────────────────── 20.0反│ [口神_▼] おまけ 0.2反 [米 ▼] [にこまる▼] [___] ↑↓
┣にこ │ 1 おまけ 口神ノ川... 0.2反 米 にこまる [編集] │ [口神_▼] 口神1反 1.2反 [米 ▼] [にこまる▼] [___] ↑↓
││10.2反2 ☐ 口神1反 口神ノ川... 1.2反 米 にこまる [編集] │ [口神_▼] 口神北東 0.4反 [野菜 ▼] [トマト▼] [___] ↑↓
┗たち │ 3 ☐ 口神北東 口神ノ川... 0.4反 野菜 トマト [編集] 15.3反│ [南__▼] 口神北中 0.4反 [-- ▼] [---------] [___] ↑↓
│5.1反│ 4 ☐ 口神北中 口神ノ川... 0.4❗未設定 [割当] ┣にこ │ [南__▼] 口神北西 0.5[その他 ▼] [完全休耕▼] [___] ↑↓
│ 5 口神北西 口神ノ川... 0.5反 その他 完全休耕 [編集] │10.2反│
野菜 │ ┗たち │ ... (39行)
3.2反 │ ... (39行) │5.1反│
│ │ │
│その他│ ────────────────────────────────────────────────────────│
│1.5反 │ ページ: 1 / 2 表示件数: [25件▼] │
│ │ │ │ │ │
│未設定│ │ │未設定│ │
│2.0反❗ │ │2.0反❗ │
└──────┴───────────────────────────────────────────────────────────┘ └──────┴───────────────────────────────────────────────────────────┘
``` ```
**サイドバー(開閉可能):** **サイドバー(集計パネル、開閉可能):**
``` ```
┌──────────────┐ ┌──────────────┐
[≡] 集計 │← トグルボタンで開閉 │ 集計 [×] │← 閉じるボタン
├──────────────┤ ├──────────────┤
│ 合計 40.0反 │ │ 合計 20.0反 │
│ │ │ │
│ 米 │ │ 米 │
│ 15.3反 │ │ 15.3反 │
@@ -152,87 +189,55 @@
│ │ │ │
│ 野菜 │ │ 野菜 │
│ 3.2反 │ │ 3.2反 │
│ ├トマト │
│ │ 1.8反 │
│ └キュウリ │
│ 1.4反 │
│ │
│ トウモロコシ │
│ 2.5反 │
│ │
│ エンドウ │
│ 1.8反 │
│ │ │ │
│ その他 │ │ その他 │
│ 1.5反 │ │ 1.5反 │
│ ├完全休耕 │
│ │ 0.8反 │
│ └緑肥 │
│ 0.7反 │
│ │ │ │
│ ❗未設定 │ │ ❗未設定 │
│ 2.0反 │ │ 2.0反 │
└──────────────┘ └──────────────┘
``` ```
**サイドバー閉じた状態:**
```
┌───┐
│[☰]│← クリックで開く
└───┘
```
### レイアウト(スマホ) ### レイアウト(スマホ)
``` ```
┌────────────────────────────────┐ ┌────────────────────────────────────
│ 🌾 作付け計画 2025年度 ▼ ☰ │ 🌾 作付け計画 [2025▼] [集計]
├────────────────────────────────┤ ├────────────────────────────────────
🔍 [検索_______________] [🔽] 並び順: [カスタム順 ▼]
│ │ ├────────────────────────────────────┤
[📊 集計を表示] [前年度コピー]│← 集計はモーダル ┌────────────────────────────────┐│
├────────────────────────────────┤ │ │ おまけ 0.2反 ││
┌────────────────────────────┐ │ グループ: [口神___▼] │
│ │ おまけ ││ │ │ 作物: [米 ▼] 品種: [にこまる▼]││
│ │ 口神ノ川足川 351 ││ │ │ 備考: [___________________] ││
│ 0.2反 | 米(にこまる) │ └────────────────────────────────┘
[編集]
──────────────────────────── ┌────────────────────────────────
│ 口神 北中 0.4反 │
┌────────────────────────────┐ │ グループ: [南___▼] │
│ │ 口神 北中 ││ │ │ 作物: [-- ▼] 品種: [------] ││
│ │ 口神ノ川198... ││ │ │ 備考: [___________________] ││
│ 0.4反 | ❗未設定 │ └────────────────────────────────┘
[割当]
└────────────────────────────┘ ... (39圃場)
│ │ └────────────────────────────────────┘
│ ... (39圃場) │
└────────────────────────────────┘
``` ```
**スマホ: 集計モーダル** **スマホ: 集計モーダル**[集計]ボタンで表示)
``` ```
┌────────────────────────────────┐ ┌────────────────────────────────┐
│ 集計 [×] │ │ 集計 [×] │
├────────────────────────────────┤ ├────────────────────────────────┤
合計面積: 20.0反
│ 合計面積: 40.0反 │
│ │ │ │
│ 米: 15.3反 │ │ 米: 15.3反 │
│ ├ にこまる: 10.2反 │ │ ├ にこまる: 10.2反 │
│ └ たちはるか: 5.1反 │ │ └ たちはるか: 5.1反 │
│ │ │ │
│ 野菜: 3.2反 │ │ 野菜: 3.2反 │
│ ├ トマト: 1.8反 │
│ └ キュウリ: 1.4反 │
│ │
│ トウモロコシ: 2.5反 │
│ │
│ エンドウ: 1.8反 │
│ │ │ │
│ その他: 1.5反 │ │ その他: 1.5反 │
│ ├ 完全休耕: 0.8反 │
│ └ 緑肥: 0.7反 │
│ │ │ │
│ ❗未設定: 2.0反 │ │ ❗未設定: 2.0反 │
│ │ │ │
@@ -241,221 +246,184 @@
``` ```
### 機能要件 ### 機能要件
- [ ] 全圃場を一覧表示39行 - [x] 全圃場を一覧表示39行
- [ ] 各行に以下を表示: - [x] 各行に以下を表示:
- チェックボックス(一括操作用 - グループ名インライン編集可能、datalist補完付き
- - 圃場
- 住所
- 面積(反) - 面積(反)
-付け作物(未設定の場合は警告色 -物(ドロップダウン、インライン選択
- 品種 - 品種(ドロップダウン、作物選択後に有効化)
- [編集]ボタン - 備考(テキスト入力)
- [ ] 検索機能: - 表示順変更ボタン(↑↓、カスタム順モード時のみ)
- 圃場名・住所で部分一致検索 - [x] 年度切り替え(ドロップダウン)
- リアルタイム絞り込み - [x] 並び替え機能:
- [ ] フィルタ機能: - カスタム順display_order
- 作物で絞り込み(米、野菜、休耕など - グループ順group_name
- 「未割当のみ」トグル - 作付け順crop別
- [ ] 一括操作: - [x] **インライン即時保存**: 作物・品種・備考を変更すると即座にAPIに保存画面遷移なし、スクロール位置維持
- 複数行を選択 → 「一括割当」ボタン表示 - [x] **集計サイドバーPC**:
- 同じ作物を一括で割り当て - 閉じるボタンで非表示可能
- [ ] [前年度をコピー]ボタン:
- 確認ダイアログ表示
- 前年度の作付けを全圃場にコピー
- [ ] [申請書作成]ボタン:
- 画面6へ遷移
- [ ] **集計サイドバーPC**:
- トグルボタンで開閉
- 作物別の合計面積 - 作物別の合計面積
- 品種別の内訳(ツリー表示) - 品種別の内訳(ツリー表示、展開可能
- 未設定の面積を警告表示 - 未設定の面積を警告表示
- [ ] **集計モーダル(スマホ)**: - 作付け変更時にリアルタイム更新
- [📊 集計を表示]ボタンでモーダル表示 - [x] **集計モーダル(スマホ)**:
- PC版と同じ内容を縦スクロール表示 - [集計]ボタンでサイドパネル表示
- 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/スマホ共通)
``` ```
┌────────────────────────────────────┐ ┌────────────────────────────────────┐
作付け計画を編集 [×] ← 一覧に戻る
├────────────────────────────────────┤ ├────────────────────────────────────┤
│ │ │ │
│ 圃場: 口神 北中 圃場
住所: 口神笹ヶ谷374-1) [口神 北中________________]
│ 面積: 0.4反 (400m2) │
│ │ │ │
───────────────────────────────── 住所
│ [口神笹ヶ谷374-1)__] │
│ │ │ │
作物 * 面積(反)
┌────────────────────────────────┐ [0.4___]
│ │ [米 ▼] ││
│ └────────────────────────────────┘│
│ │ │ │
品種 * 面積m2
┌────────────────────────────────┐ [400___]
│ │ [にこまる ▼] ││
│ │ - にこまる ││
│ │ - たちはるか ││
│ │ - たちはるか(特栽) ││
│ └────────────────────────────────┘│
│ [+ 新しい品種を追加] │
│ │ │ │
備考 所有者
┌────────────────────────────────┐ [吉田___]
│ │ [_____________________________]││
│ └────────────────────────────────┘│
│ │ │ │
[キャンセル] [保存] グループ名
│ [口神___] │
│ │ │ │
└────────────────────────────────────┘ │ 📋 共済情報Phase 1 予定) │
``` │ 紐づき共済区画: 2件 │
│ • 耕地2-1: 四万十町 笹ヶ谷 374-1 │
### 作物選択のドロップダウン │ • 耕地2-2: 四万十町 笹ヶ谷 374-2 │
│ │
``` │ 📋 中山間情報Phase 1 予定) │
┌────────────────────────────────────┐ │ 紐づき中山間区画: 1件 │
│ • ID50: 口神ノ川 壱町切 1694
• トウモロコシ
• エンドウ [保存]
│ • 野菜 │
│ • その他 │
└────────────────────────────────────┘
```
### 品種選択(すべての作物で統一)
**作物=「米」の場合:**
```
┌────────────────────────────────────┐
│ • にこまる │
│ • たちはるか │
│ • たちはるか(特栽) │
│ ──────────────────────────────── │
│ [+ 新しい品種を追加] │
└────────────────────────────────────┘
クリックすると:
┌────────────────────────────────────┐
│ 新しい品種名を入力: │
│ [___________________________] │
│ │ │ │
│ [キャンセル] [追加] │
└────────────────────────────────────┘
```
**作物=「トウモロコシ」の場合:**
```
┌────────────────────────────────────┐
│ (まだ品種が登録されていません) │
│ ──────────────────────────────── │
│ [+ 新しい品種を追加] │
└────────────────────────────────────┘
```
**作物=「その他」の場合:**
```
┌────────────────────────────────────┐
│ • 完全休耕 │
│ • 緑肥(ヘアリーベッチ) │
│ • 緑肥(レンゲ) │
│ • 景観作物(コスモス) │
│ • 景観作物(ヒマワリ) │
│ ──────────────────────────────── │
│ [+ 新しい品種を追加] │
└────────────────────────────────────┘ └────────────────────────────────────┘
``` ```
### 機能要件 ### 機能要件
- [ ] 作物をドロップダウンで選択 - [x] 圃場の基本情報を編集フォームで表示
- [ ] **すべての作物で品種選択UIは統一** - [x] 編集可能フィールド: 圃場名、住所、面積(反)、面積(m2)、所有者、グループ名
- プリセット品種のドロップダウン - [x] [保存]ボタン → PATCH API で更新
- [+ 新しい品種を追加]ボタンは常に表示 - [x] [← 一覧に戻る] → `/fields` へ遷移
- 作物による操作の違いなし - [x] エラーメッセージ表示
- [ ] 新しい品種の追加: - [ ] **共済/中山間情報の表示****未実装A-8: 最優先で実装予定)**
- [+ 新しい品種を追加]をクリック - 紐づいている共済区画の一覧(耕地番号-分筆、漢字地名)
- インライン入力フィールド表示 - 紐づいている中山間区画の一覧ID、所在地
- 入力後、その場でプリセットに追加
- データベースに永続化(次回から選択可能)
- [ ] 備考欄(任意)
- [ ] [保存]ボタン → 作付け計画を保存して一覧に戻る
- [ ] [キャンセル]ボタン → 変更を破棄して一覧に戻る
- [ ] **集計のリアルタイム更新**:
- 保存すると、サイドバーの集計が即座に更新される
### 一括割当の場合
- モーダルのタイトルを「一括割当」に変更
- 「圃場: 5件選択中」と表示
- 保存時、選択中の全圃場に同じ作付けを適用
### デザインノート
- **UIの統一性**: どの作物を選んでも操作フローが同じ
- **品種の追加**: その場で追加できる(別画面に遷移しない)
- **プリセットの管理**: 一度追加した品種は、全ユーザーで共有(マスタ化)
---
## 画面5: 圃場詳細(スマホ参照用)
### 目的
田んぼにいるときに、その圃場の情報を確認
### レイアウト(スマホ)
```
┌────────────────────────────────┐
│ ← 一覧に戻る 2025年度 │
├────────────────────────────────┤
│ │
│ 口神 北中 │
│ │
│ 📍 住所 │
│ 口神笹ヶ谷374-1) │
│ │
│ 📏 面積 │
│ 0.4反 (400m2) │
│ │
│ 🌾 今年の作付け │
│ 米(にこまる) │
│ │
│ 📋 共済情報 │
│ 耕地番号: 2 / 分筆: 2 │
│ │
│ 📋 中山間情報 │
│ ID: 50 │
│ │
│ ───────────────────────────── │
│ │
│ 📅 過去の作付け履歴Phase 2
│ • 2024年: 米(にこまる) │
│ • 2023年: 米(にこまる) │
│ • 2022年: 休耕 │
│ │
└────────────────────────────────┘
```
### 機能要件
- [ ] 圃場の基本情報を見やすく表示
- [ ] 文字サイズ: 18px以上スマホで見やすく
- [ ] 余白: 十分に確保(誤タップ防止)
- [ ] 将来的に栽培履歴も表示Phase 2 - [ ] 将来的に栽培履歴も表示Phase 2
--- ---
## 画面6: 申請書ダウンロード ## 画面6: 圃場新規作成
### 目的
手動で圃場を1件ずつ新規登録インポート以外の方法
### レイアウト
```
┌────────────────────────────────────┐
│ ← 一覧に戻る │
├────────────────────────────────────┤
│ │
│ 圃場名 │
│ [____________________________] │
│ │
│ 住所 │
│ [____________________________] │
│ │
│ 面積(反) │
│ [________] │
│ │
│ 面積m2
│ [________] │
│ │
│ 所有者 │
│ [____________________________] │
│ │
│ [作成] │
│ │
└────────────────────────────────────┘
```
### 機能要件
- [x] 各フィールドを入力して圃場を新規作成
- [x] [作成]ボタン → POST API で作成
- [x] 作成成功 → 圃場一覧へ遷移
- [x] バリデーションエラー → エラーメッセージ表示
### 補足
- インポートODS/Excelとの使い分け: 大量登録はインポート、1件追加は手動作成
- グループ名は新規作成時には設定不可(作成後に圃場一覧から設定)
---
## 画面7: 申請書ダウンロード
### 目的 ### 目的
水稲共済細目書・中山間交付金のPDFをダウンロード 水稲共済細目書・中山間交付金のPDFをダウンロード
@@ -464,7 +432,7 @@
``` ```
┌────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────┐
│ 🌾 Keina System > 申請書ダウンロード 👤ログアウト │ 🌾 KeinaSystem [作付け計画] [圃場管理] ...
├────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────┤
│ │ │ │
│ 年度: [2025年度 ▼] │ │ 年度: [2025年度 ▼] │
@@ -472,7 +440,6 @@
│ ┌────────────────────────────────────────────────┐│ │ ┌────────────────────────────────────────────────┐│
│ │ 📄 水稲共済細目書 ││ │ │ 📄 水稲共済細目書 ││
│ │ ││ │ │ ││
│ │ 提出時期: 2月・5月年2回 ││
│ │ 区画数: 31区画 ││ │ │ 区画数: 31区画 ││
│ │ ││ │ │ ││
│ │ ⚠️ 未割当の圃場: 4筆 ││ │ │ ⚠️ 未割当の圃場: 4筆 ││
@@ -484,7 +451,6 @@
│ ┌────────────────────────────────────────────────┐│ │ ┌────────────────────────────────────────────────┐│
│ │ 📄 中山間地域等直接支払交付金 ││ │ │ 📄 中山間地域等直接支払交付金 ││
│ │ ││ │ │ ││
│ │ 提出時期: 5月年1回 ││
│ │ 区画数: 71区画 ││ │ │ 区画数: 71区画 ││
│ │ ││ │ │ ││
│ │ ✅ 全て割当済み ││ │ │ ✅ 全て割当済み ││
@@ -496,95 +462,128 @@
``` ```
### 機能要件 ### 機能要件
- [ ] 年度を選択 - [x] 年度を選択
- [ ] 各申請書について: - [x] 各申請書について:
- 区画数を表示 - [x] [PDFダウンロード]ボタン → ファイルダウンロード
- 未割当の警告(ある場合) - [ ] 区画数の表示 — **未実装**
- [プレビュー]ボタン → 新しいタブでPDFプレビュー - [ ] 未割当の警告表示 — **未実装**
- [PDFダウンロード]ボタン → ファイルダウンロード - [ ] [プレビュー]ボタン → 新しいタブでPDF表示 — **未実装A-5**
- [ ] ダウンロードされるPDFのファイル名: - [ ] ダウンロードされるPDFのファイル名:
- 水稲共済: `水稲共済細目書_2025年度.pdf` - 水稲共済: `水稲共済細目書_2025年度.pdf`
- 中山間: `中山間交付金_2025年度.pdf` - 中山間: `中山間交付金_2025年度.pdf`
- [ ] PDFはA4サイズ、印刷してそのまま提出可能 - [ ] PDFはA4サイズ、印刷してそのまま提出可能
### プレビュー機能 ---
[プレビュー]ボタンをクリックすると、新しいタブでPDFを表示 ## 画面7-A: PDF帳票フォーマット仕様
``` ### 7-A-1: 水稲共済細目書 PDF
┌────────────────────────────────────────────────────┐
│ ← 戻る 水稲共済細目書_2025年度.pdf [印刷] [⬇] │
├────────────────────────────────────────────────────┤
│ │
│ 水稲共済細目書2025年度
│ │
│ ┌────────────────────────────────────────────────┐│
│ │ 耕地 分筆 地名地番 面積 作付 品種 ││
│ │ ──────────────────────────────────────────── ││
│ │ 1 1 四万十町 ... 2.2 米 にこまる ││
│ │ 2 1 四万十町 ... 25.4 米 にこまる ││
│ │ 2 2 四万十町 ... 12.0 米,野菜 ... ││
│ │ ││
│ │ ... (31行) ││
│ └────────────────────────────────────────────────┘│
│ │
│ 1 / 2 │
└────────────────────────────────────────────────────┘
```
- [ ] ブラウザの標準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 ### レイアウトPC
``` ```
┌────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────┐
│ 🌾 Keina System > データ管理 👤ログアウト │ 🌾 KeinaSystem [作付け計画] [圃場管理] ...
├────────────────────────────────────────────────────┤ ├────────────────────────────────────────────────────┤
│ │ │ │
│ 📥 データインポート │ │ 📥 データインポート │
│ │ │ │
│ タブ: [吉田農地台帳] [共済マスタ] [中山間マスタ] │
│ │
│ ┌────────────────────────────────────────────────┐│ │ ┌────────────────────────────────────────────────┐│
│ │ 吉田農地台帳 (実圃場データ) ││ │ │ 吉田農地台帳(圃場マスタ) ││
│ │ ││
│ │ 最終更新: 2025/02/01 ││
│ │ 登録圃場数: 39筆 ││
│ │ ││ │ │ ││
│ │ ファイルを選択: [ファイルを選択] 📎 ││ │ │ ファイルを選択: [ファイルを選択] 📎 ││
│ │ ││ │ │ ││
│ │ ⚠️ 既存データは上書きされます ││ │ │ ⚠️ 既存データは上書きされます ││
│ │ ││ │ │ ││
│ │ [プレビュー] [インポート実行] ││ │ │ [インポート実行] ││
│ └────────────────────────────────────────────────┘│
│ │
│ ┌────────────────────────────────────────────────┐│
│ │ 共済マスタ ││
│ │ ││
│ │ ファイルを選択: [ファイルを選択] 📎 ││
│ │ [インポート実行] ││
│ └────────────────────────────────────────────────┘│
│ │
│ ┌────────────────────────────────────────────────┐│
│ │ 中山間マスタ ││
│ │ ││
│ │ ファイルを選択: [ファイルを選択] 📎 ││
│ │ [インポート実行] ││
│ └────────────────────────────────────────────────┘│ │ └────────────────────────────────────────────────┘│
│ │ │ │
│ 📤 データエクスポート │ │ 📤 データエクスポート │
│ │
│ • [全圃場データ (CSV)] ※バックアップ用 │ │ • [全圃場データ (CSV)] ※バックアップ用 │
│ • [作付け計画 (CSV)] ※バックアップ用 │ │ • [作付け計画 (CSV)] ※バックアップ用 │
│ • [バックアップ (全データ ZIP)] │
│ │
│ 📄 申請書PDF生成 │
│ → 「申請書ダウンロード」画面へ │
│ │ │ │
└────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────┘
``` ```
### 機能要件 ### 機能要件
- [ ] 3種類のマスタをタブで切り替え - [x] 3種類のマスタを縦並びで表示(タブではなく各セクション形式)
- [ ] ファイルアップロードODS/Excel対応 - [x] ファイルアップロードODS/Excel対応
- [ ] プレビュー機能(インポート前に確認 - [x] インポート実行(結果メッセージ表示
- [ ] インポート実行(確認ダイアログ付き) - [ ] プレビュー機能(インポート前に確認)— **未実装**
- [ ] エクスポート機能CSV/ZIP - [ ] エクスポート機能CSV**未実装A-6**
--- ---
@@ -595,7 +594,7 @@
``` ```
プライマリカラー(緑系): プライマリカラー(緑系):
#2E7D32 濃い緑(ヘッダー、ボタン) #2E7D32 濃い緑(ヘッダー、ボタン)
#4CAF50 緑(アクセント) #4CAF50 緑(アクセント、アクティブなナビ項目
#81C784 淡い緑(ホバー) #81C784 淡い緑(ホバー)
セカンダリカラー(土系): セカンダリカラー(土系):
@@ -620,8 +619,8 @@
``` ```
フォント: フォント:
- システムフォント優先 - システムフォント優先
- 日本語: "Hiragino Sans", "Yu Gothic", sans-serif - 日本語: "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif
- 英数字: "Roboto", "Helvetica", sans-serif - 英数字: Inter, "Roboto", "Helvetica", sans-serif
サイズ: サイズ:
- 見出し(h1): 28px / 太字 - 見出し(h1): 28px / 太字
@@ -663,10 +662,11 @@ PC: 1024px〜
- **ホバー**: 10%明るく、カーソルpointer - **ホバー**: 10%明るく、カーソルpointer
- **押下**: 5%暗く、影を小さく - **押下**: 5%暗く、影を小さく
### モーダル ### インライン編集(作付け計画)
- **背景**: 半透明黒opacity: 0.5 - **ドロップダウン**: 選択変更と同時にバックグラウンド保存
- **アニメーション**: フェードイン0.2秒) - **テキスト入力**: blurフォーカスアウト時に保存
- **閉じる**: 背景クリック or [×]ボタン or Escキー - **保存中**: ローディングスピナーは表示しない(スクロールリセット防止のため)
- **エラー時**: トースト通知でエラー表示
### トースト通知 ### トースト通知
- **位置**: 画面右上 - **位置**: 画面右上
@@ -690,5 +690,5 @@ PC: 1024px〜
- **オートコンプリート**: 有効化 - **オートコンプリート**: 有効化
### ナビゲーション ### ナビゲーション
- **ハンバーガーメニュー**: 右上に配置 - **Navbar**: PC版と同じ項目をレスポンシブに配置
- **戻るボタン**: 画面左上に配置 - **戻るボタン**: 画面左上に配置(詳細画面など)

View File

@@ -8,15 +8,15 @@
- [ ] ログイン・認証機能 - [ ] ログイン・認証機能
- [ ] 作付け計画の一覧表示PC/スマホ) - [ ] 作付け計画の一覧表示PC/スマホ)
- [ ] 作付け計画の編集(個別・一括) - [ ] 作付け計画の編集(個別・一括)
- [ ] 水稲共済細目書のCSV出力 - [ ] 水稲共済細目書のPDF出力
- [ ] 中山間交付金のCSV出力 - [ ] 中山間交付金のPDF出力
- [ ] 前年度作付けのコピー機能 - [ ] 前年度作付けのコピー機能
- [ ] 3種類のマスタデータインポート - [ ] 3種類のマスタデータインポート
### 品質基準 ### 品質基準
- [ ] PCで快適に操作できるレスポンス1秒以内 - [ ] PCで快適に操作できるレスポンス1秒以内
- [ ] スマホで見やすい文字16px以上 - [ ] スマホで見やすい文字16px以上
- [ ] 出力されるCSVが正確手動検証でOK - [ ] 出力されるPDFが正確手動検証でOK
### ユーザビリティ基準 ### ユーザビリティ基準
- [ ] 作付け計画の登録が10分以内で完了 - [ ] 作付け計画の登録が10分以内で完了
@@ -84,10 +84,7 @@
### Day 5-6: 作付け計画機能(コア機能) ### Day 5-6: 作付け計画機能(コア機能)
**Day 5: 作付け計画API** **Day 5: 作付け計画API**
- [ ] Django: 作物・品種マスタの初期データ投入 - [ ] Django: 作付け計画API作物・品種はUIまたは管理画面から登録
- 作物: 米、トウモロコシ、エンドウ、野菜、その他
- 品種: 米(にこまる等)、その他(完全休耕等)
- [ ] Django: 作付け計画API
- 一覧取得 (`GET /api/plans/?year=2025`) - 一覧取得 (`GET /api/plans/?year=2025`)
- 作成・更新 (`POST /api/plans/`, `PATCH /api/plans/{id}/`) - 作成・更新 (`POST /api/plans/`, `PATCH /api/plans/{id}/`)
- 一括更新 (`POST /api/plans/bulk/`) - 一括更新 (`POST /api/plans/bulk/`)
@@ -105,13 +102,11 @@
- 作物別・品種別の合計面積 - 作物別・品種別の合計面積
- リアルタイム更新 - リアルタイム更新
- **スマホ: 集計モーダル表示** - **スマホ: 集計モーダル表示**
- [ ] Next.js: 作付け計画編集モーダル - [ ] Next.js: 作付け計画インライン編集
- 作物選択(ドロップダウン) - 作物選択(テーブル内ドロップダウン)
- **品種選択(統一UI** - 品種選択(テーブル内ドロップダウン、作物選択後に有効化)
- プリセット品種のドロップダウン - 備考入力(テーブル内テキスト)
- [+ 新しい品種を追加]ボタン - 変更即時保存(バックグラウンド、スクロール維持)
- すべての作物で同じ操作
- 一括割当対応
- [ ] Next.js: 前年度コピーボタン - [ ] Next.js: 前年度コピーボタン
- [ ] 動作確認: 作付け計画を実際に入力 - [ ] 動作確認: 作付け計画を実際に入力
@@ -170,7 +165,7 @@
| 項目 | 採用技術 | 理由 | | 項目 | 採用技術 | 理由 |
|------|---------|------| |------|---------|------|
| フレームワーク | Django 5.0 | 安定性、豊富なエコシステム | | フレームワーク | Django 5.2 | 安定性、豊富なエコシステム |
| REST API | Django REST Framework | 標準的なAPI構築ツール | | REST API | Django REST Framework | 標準的なAPI構築ツール |
| 認証 | djoser + SimpleJWT | JWT認証の簡単な実装 | | 認証 | djoser + SimpleJWT | JWT認証の簡単な実装 |
| GIS | GeoDjango (PostGIS) | 地理情報の扱いに最適 | | GIS | GeoDjango (PostGIS) | 地理情報の扱いに最適 |
@@ -207,8 +202,8 @@
### しっかり作り込むもの ### しっかり作り込むもの
- 作付け計画一覧: 検索・フィルタ・ソート機能 - 作付け計画一覧: 検索・フィルタ・ソート機能
- 編集モーダル: 入力バリデーション、エラー表示 - インライン編集: 即時保存、スクロール維持
- 申請書CSV: 正確なデータ集計ロジック - 申請書PDF: 正確なデータ集計ロジック、A4印刷対応
### Phase 2以降に回すもの ### Phase 2以降に回すもの
- 栽培履歴(播種日、作業記録) - 栽培履歴(播種日、作業記録)
@@ -305,7 +300,7 @@
### コミットメッセージ ### コミットメッセージ
``` ```
feat: 作付け計画一覧APIを実装 feat: 作付け計画一覧APIを実装
fix: 共済CSVの面積計算バグを修正 fix: 共済PDFの面積計算バグを修正
docs: READMEにセットアップ手順を追加 docs: READMEにセットアップ手順を追加
style: Tailwindクラスを整理 style: Tailwindクラスを整理
``` ```
@@ -321,6 +316,6 @@ style: Tailwindクラスを整理
完成したら、以下を実施: 完成したら、以下を実施:
1. **使用感チェック**: 実際に作付け計画を入力してみる 1. **使用感チェック**: 実際に作付け計画を入力してみる
2. **申請書検証**: 出力されたCSVを役場の書式と照合 2. **申請書検証**: 出力されたPDFを役場の書式と照合
3. **改善点の洗い出し**: 「ここがもっとこうだったら...」を記録 3. **改善点の洗い出し**: 「ここがもっとこうだったら...」を記録
4. **Phase 2の要件整理**: 栽培履歴機能の詳細を詰める 4. **Phase 2の要件整理**: 栽培履歴機能の詳細を詰める

View File

@@ -353,10 +353,84 @@ IsAuthenticated に変更
セキュリティ必須 セキュリティ必須
--- ---
## E.追加で修正の要望 ## E. 追加で修正の要望
### E-1.PDF出力される帳票のフォーマットが気に入らないです。
ここ未定義なので、まずは仕様を決めましょう
### 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(交付金額)
---
## 対応の進め方 ## 対応の進め方