作付け計画画面 (/allocation):
年度をlocalStorageに保存・復元(ブラウザを閉じても維持、明示的に変えるまで固定)
過去年度を表示中は琥珀色のバナー「{year}年度のデータを参照中(過去年度)」+ 「今年度に戻る」ボタン
テーブル枠も過去年度では薄いセピア調に変化
デフォルトは今年度(2026)
帳票出力画面 (/reports):
デフォルトを 2025 固定 → new Date().getFullYear() に変更
セレクタも動的5年分に変更
ダッシュボード (/dashboard):
既に今年度デフォルト(変更不要)
記憶:
CLAUDE.md「重要な設計判断」に年度管理方針を追記済み
MEMORY.md に Phase 2 のグローバル作業年度導入方針を記録済み
This commit is contained in:
@@ -146,6 +146,13 @@ Variety (品種マスタ)
|
||||
- `display_order` (リスト表示時の順序)
|
||||
- マイグレーション0004で追加
|
||||
|
||||
5. **年度管理の設計方針**(⚠️ Phase 2 で必ず参照):
|
||||
- **作付け計画**: 年度セレクタで独立して来年度も選べる。選んだ年度はlocalStorageに保存して維持
|
||||
- **過去年度**: 「参照モード」として視覚的に区別(背景色・バナー)
|
||||
- **Phase 2 の栽培管理・販売管理**: グローバル作業年度を導入し、基本は今年度に従う
|
||||
- **栽培記録・作業日誌**: 日付中心設計、年度は日付から自動算出
|
||||
- 参考: ソリマチ農業簿記の年度管理方式(明示的に年度を選択、変更するまで固定)
|
||||
|
||||
---
|
||||
|
||||
## 🔑 重要な制約・ルール
|
||||
|
||||
@@ -23,7 +23,13 @@ export default function AllocationPage() {
|
||||
const [fields, setFields] = useState<Field[]>([]);
|
||||
const [crops, setCrops] = useState<Crop[]>([]);
|
||||
const [plans, setPlans] = useState<Plan[]>([]);
|
||||
const [year, setYear] = useState<number>(2025);
|
||||
const [year, setYear] = useState<number>(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = localStorage.getItem('allocationYear');
|
||||
if (saved) return parseInt(saved);
|
||||
}
|
||||
return new Date().getFullYear();
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState<number | null>(null);
|
||||
const [showSidebar, setShowSidebar] = useState(true);
|
||||
@@ -44,9 +50,13 @@ export default function AllocationPage() {
|
||||
const [filterUnassigned, setFilterUnassigned] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('allocationYear', String(year));
|
||||
fetchData();
|
||||
}, [year]);
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
const isPastYear = year < currentYear;
|
||||
|
||||
const fetchData = async (background = false) => {
|
||||
if (!background) setLoading(true);
|
||||
try {
|
||||
@@ -540,7 +550,9 @@ export default function AllocationPage() {
|
||||
<div className="flex-1 min-w-0 p-4 lg:p-0">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="mb-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<h1 className="text-2xl font-bold text-gray-900">作付け計画</h1>
|
||||
<h1 className="text-2xl font-bold text-gray-900">
|
||||
作付け計画 <span className="text-green-700">{year}年度</span>
|
||||
</h1>
|
||||
|
||||
{/* スマホ用集計ボタン */}
|
||||
<button
|
||||
@@ -569,11 +581,11 @@ export default function AllocationPage() {
|
||||
id="year"
|
||||
value={year}
|
||||
onChange={(e) => setYear(parseInt(e.target.value))}
|
||||
className="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
className="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 font-semibold"
|
||||
>
|
||||
<option value={2025}>2025年</option>
|
||||
<option value={2026}>2026年</option>
|
||||
<option value={2027}>2027年</option>
|
||||
{Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - 2 + i).map((y) => (
|
||||
<option key={y} value={y}>{y}年</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<button
|
||||
@@ -649,6 +661,20 @@ export default function AllocationPage() {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{isPastYear && (
|
||||
<div className="mb-4 p-3 bg-amber-50 border border-amber-300 rounded-md flex items-center justify-between">
|
||||
<p className="text-sm text-amber-800 font-medium">
|
||||
{year}年度のデータを参照中(過去年度)
|
||||
</p>
|
||||
<button
|
||||
onClick={() => setYear(currentYear)}
|
||||
className="text-sm text-amber-700 underline hover:text-amber-900"
|
||||
>
|
||||
{currentYear}年度に戻る
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-4 p-3 bg-blue-50 border border-blue-200 rounded-md">
|
||||
<p className="text-sm text-blue-800">
|
||||
💡 グループ名を入力して「グループ順」で並び替え、「↑」「↓」ボタンで順序を変更できます
|
||||
@@ -699,7 +725,7 @@ export default function AllocationPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-lg shadow overflow-hidden">
|
||||
<div className={`rounded-lg shadow overflow-hidden ${isPastYear ? 'bg-amber-50/50 ring-1 ring-amber-200' : 'bg-white'}`}>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
|
||||
@@ -26,7 +26,7 @@ const previewPdf = async (url: string) => {
|
||||
};
|
||||
|
||||
export default function ReportsPage() {
|
||||
const [year, setYear] = useState<number>(2025);
|
||||
const [year, setYear] = useState<number>(new Date().getFullYear());
|
||||
const [busy, setBusy] = useState<string | null>(null);
|
||||
|
||||
const handleAction = async (action: 'download' | 'preview', type: 'kyosai' | 'chusankan') => {
|
||||
@@ -67,9 +67,9 @@ export default function ReportsPage() {
|
||||
onChange={(e) => setYear(parseInt(e.target.value))}
|
||||
className="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 w-full max-w-xs"
|
||||
>
|
||||
<option value={2025}>2025年</option>
|
||||
<option value={2026}>2026年</option>
|
||||
<option value={2027}>2027年</option>
|
||||
{Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - 2 + i).map((y) => (
|
||||
<option key={y} value={y}>{y}年</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user