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, useRef } from 'react';
|
||||
import { api } from '@/lib/api';
|
||||
import Navbar from '@/components/Navbar';
|
||||
import { Upload, Loader2, CheckCircle, XCircle } from 'lucide-react';
|
||||
import { Upload, Download, Loader2, CheckCircle, XCircle } from 'lucide-react';
|
||||
|
||||
interface ImportResult {
|
||||
success: boolean;
|
||||
@@ -20,10 +20,32 @@ export default function ImportPage() {
|
||||
const [kyosaiResult, setKyosaiResult] = useState<ImportResult | null>(null);
|
||||
const [yoshidaResult, setYoshidaResult] = useState<ImportResult | null>(null);
|
||||
const [chusankanResult, setChusankanResult] = useState<ImportResult | null>(null);
|
||||
const [exporting, setExporting] = useState(false);
|
||||
const kyosaiInputRef = useRef<HTMLInputElement>(null);
|
||||
const yoshidaInputRef = useRef<HTMLInputElement>(null);
|
||||
const chusankanInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleExportZip = async () => {
|
||||
setExporting(true);
|
||||
try {
|
||||
const response = await api.get('/fields/export/zip/', { responseType: 'blob' });
|
||||
const blob = new Blob([response.data], { type: 'application/zip' });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = 'keinasystem_backup.zip';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Export failed:', error);
|
||||
alert('エクスポートに失敗しました');
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKyosaiUpload = async () => {
|
||||
if (!kyosaiFile) {
|
||||
alert('ファイルを選択してください');
|
||||
@@ -399,6 +421,33 @@ export default function ImportPage() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* エクスポート */}
|
||||
<div className="bg-white rounded-lg shadow p-6 border-t-4 border-gray-300">
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-2">
|
||||
データエクスポート
|
||||
</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">
|
||||
全データ(圃場・共済・中山間・作付け計画・品種・紐づけ情報)をCSV形式のZIPファイルとしてダウンロードします。サーバー移行時のバックアップとして使用できます。
|
||||
</p>
|
||||
<button
|
||||
onClick={handleExportZip}
|
||||
disabled={exporting}
|
||||
className="w-full flex items-center justify-center px-4 py-2 bg-gray-700 text-white rounded-md hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
{exporting ? (
|
||||
<>
|
||||
<Loader2 className="h-5 w-5 mr-2 animate-spin" />
|
||||
エクスポート中...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="h-5 w-5 mr-2" />
|
||||
全データをZIPでダウンロード
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user