A-6 完了。 本セッションの進捗まとめ:
タスク 内容 状態 A-3 前年度コピーボタン ✅ 完了 A-4 品種のインライン追加・削除 ✅ 完了 A-5 PDFプレビュー機能 ✅ 完了 A-6 エクスポート機能 ✅ 完了 残りタスク: A-2: チェックボックス・一括操作 A-1: ダッシュボード画面 A-7: 検索・フィルタ 確認ポイント: 作付け計画 (/allocation): 年度セレクタの横に「前年度コピー」「品種管理」ボタン、品種セレクトに「+ 新しい品種を追加...」 帳票出力 (/reports): 各帳票にプレビュー/ダウンロードの2ボタン データ取込 (/import): ページ下部に「データエクスポート」(ZIPダウンロード)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import { useState } from 'react';
|
||||
import { api } from '@/lib/api';
|
||||
import Navbar from '@/components/Navbar';
|
||||
import { FileDown, Loader2 } from 'lucide-react';
|
||||
import { FileDown, Eye, Loader2 } from 'lucide-react';
|
||||
|
||||
const downloadPdf = async (url: string, filename: string) => {
|
||||
const response = await api.get(url, { responseType: 'blob' });
|
||||
@@ -18,31 +18,35 @@ const downloadPdf = async (url: string, filename: string) => {
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
};
|
||||
|
||||
const previewPdf = async (url: string) => {
|
||||
const response = await api.get(url, { responseType: 'blob' });
|
||||
const blob = new Blob([response.data], { type: 'application/pdf' });
|
||||
const previewUrl = window.URL.createObjectURL(blob);
|
||||
window.open(previewUrl, '_blank');
|
||||
};
|
||||
|
||||
export default function ReportsPage() {
|
||||
const [year, setYear] = useState<number>(2025);
|
||||
const [downloading, setDownloading] = useState<string | null>(null);
|
||||
const [busy, setBusy] = useState<string | null>(null);
|
||||
|
||||
const handleDownloadKyosai = async () => {
|
||||
setDownloading('kyosai');
|
||||
const handleAction = async (action: 'download' | 'preview', type: 'kyosai' | 'chusankan') => {
|
||||
const key = `${action}-${type}`;
|
||||
setBusy(key);
|
||||
try {
|
||||
await downloadPdf(`/reports/kyosai/${year}/`, `水稲共済細目書_${year}.pdf`);
|
||||
const url = `/reports/${type}/${year}/`;
|
||||
if (action === 'download') {
|
||||
const filename = type === 'kyosai'
|
||||
? `水稲共済細目書_${year}.pdf`
|
||||
: `中山間交付金申請書_${year}.pdf`;
|
||||
await downloadPdf(url, filename);
|
||||
} else {
|
||||
await previewPdf(url);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Download failed:', error);
|
||||
alert('ダウンロードに失敗しました');
|
||||
console.error(`${action} failed:`, error);
|
||||
alert(`${action === 'download' ? 'ダウンロード' : 'プレビュー'}に失敗しました`);
|
||||
} finally {
|
||||
setDownloading(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDownloadChusankan = async () => {
|
||||
setDownloading('chusankan');
|
||||
try {
|
||||
await downloadPdf(`/reports/chusankan/${year}/`, `中山間交付金申请书_${year}.pdf`);
|
||||
} catch (error) {
|
||||
console.error('Download failed:', error);
|
||||
alert('ダウンロードに失敗しました');
|
||||
} finally {
|
||||
setDownloading(null);
|
||||
setBusy(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,41 +74,63 @@ export default function ReportsPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<button
|
||||
onClick={handleDownloadKyosai}
|
||||
disabled={downloading !== null}
|
||||
className="w-full flex items-center justify-center px-4 py-3 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{downloading === 'kyosai' ? (
|
||||
<>
|
||||
<Loader2 className="h-5 w-5 mr-2 animate-spin" />
|
||||
ダウンロード中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<FileDown className="h-5 w-5 mr-2" />
|
||||
水稲共済細目書をダウンロード
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{/* 水稲共済細目書 */}
|
||||
<div className="border rounded-lg p-4">
|
||||
<h3 className="font-medium text-gray-900 mb-3">水稲共済細目書</h3>
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
onClick={() => handleAction('preview', 'kyosai')}
|
||||
disabled={busy !== null}
|
||||
className="flex-1 flex items-center justify-center px-4 py-2.5 border border-green-600 text-green-700 rounded-md hover:bg-green-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{busy === 'preview-kyosai' ? (
|
||||
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />生成中...</>
|
||||
) : (
|
||||
<><Eye className="h-4 w-4 mr-2" />プレビュー</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleAction('download', 'kyosai')}
|
||||
disabled={busy !== null}
|
||||
className="flex-1 flex items-center justify-center px-4 py-2.5 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{busy === 'download-kyosai' ? (
|
||||
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />ダウンロード中...</>
|
||||
) : (
|
||||
<><FileDown className="h-4 w-4 mr-2" />ダウンロード</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleDownloadChusankan}
|
||||
disabled={downloading !== null}
|
||||
className="w-full flex items-center justify-center px-4 py-3 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{downloading === 'chusankan' ? (
|
||||
<>
|
||||
<Loader2 className="h-5 w-5 mr-2 animate-spin" />
|
||||
ダウンロード中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<FileDown className="h-5 w-5 mr-2" />
|
||||
中山間交付金申請書をダウンロード
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
{/* 中山間交付金申請書 */}
|
||||
<div className="border rounded-lg p-4">
|
||||
<h3 className="font-medium text-gray-900 mb-3">中山間交付金申請書</h3>
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
onClick={() => handleAction('preview', 'chusankan')}
|
||||
disabled={busy !== null}
|
||||
className="flex-1 flex items-center justify-center px-4 py-2.5 border border-blue-600 text-blue-700 rounded-md hover:bg-blue-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{busy === 'preview-chusankan' ? (
|
||||
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />生成中...</>
|
||||
) : (
|
||||
<><Eye className="h-4 w-4 mr-2" />プレビュー</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleAction('download', 'chusankan')}
|
||||
disabled={busy !== null}
|
||||
className="flex-1 flex items-center justify-center px-4 py-2.5 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{busy === 'download-chusankan' ? (
|
||||
<><Loader2 className="h-4 w-4 mr-2 animate-spin" />ダウンロード中...</>
|
||||
) : (
|
||||
<><FileDown className="h-4 w-4 mr-2" />ダウンロード</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user