init the project
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
// 用例导出面板:格式切换 + 导出下载
|
||||
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import type { ExportFormat } from '@/lib/types';
|
||||
import { exportTestCases } from '@/lib/api';
|
||||
|
||||
interface ExportPanelProps {
|
||||
tcSetId: string;
|
||||
}
|
||||
|
||||
const EXPORT_FORMATS: { key: ExportFormat; label: string; description: string }[] = [
|
||||
{ key: 'yaml', label: 'YAML', description: '自动化测试可解析的结构化用例' },
|
||||
{ key: 'csv', label: 'CSV 表格', description: '适合 Excel 查看与评审归档' },
|
||||
{ key: 'xmind', label: 'XMind', description: '思维导图,便于评审展示' },
|
||||
];
|
||||
|
||||
export default function ExportPanel({ tcSetId }: ExportPanelProps) {
|
||||
const [activeFormat, setActiveFormat] = useState<ExportFormat>('yaml');
|
||||
const [exporting, setExporting] = useState(false);
|
||||
|
||||
const handleExport = async () => {
|
||||
setExporting(true);
|
||||
try {
|
||||
const blob = await exportTestCases(tcSetId, activeFormat);
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `testcases.${activeFormat === 'csv' ? 'csv' : activeFormat === 'yaml' ? 'yaml' : 'xmind'}`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (err) {
|
||||
console.error('Export failed:', err);
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-200 bg-white p-6">
|
||||
<h3 className="mb-4 text-lg font-semibold text-gray-900">导出测试用例</h3>
|
||||
|
||||
{/* 格式切换标签 */}
|
||||
<div className="mb-6 flex gap-2">
|
||||
{EXPORT_FORMATS.map((fmt) => (
|
||||
<button
|
||||
key={fmt.key}
|
||||
onClick={() => setActiveFormat(fmt.key)}
|
||||
className={`rounded-lg border px-4 py-3 text-sm transition
|
||||
${activeFormat === fmt.key
|
||||
? 'border-blue-500 bg-blue-50 text-blue-700'
|
||||
: 'border-gray-200 text-gray-600 hover:border-gray-300 hover:bg-gray-50'}`}
|
||||
>
|
||||
<div className="font-medium">{fmt.label}</div>
|
||||
<div className="mt-0.5 text-xs text-gray-400">{fmt.description}</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 导出按钮 */}
|
||||
<button
|
||||
onClick={handleExport}
|
||||
disabled={exporting}
|
||||
className="flex items-center gap-2 rounded bg-green-600 px-6 py-2.5 text-sm font-medium text-white hover:bg-green-700 disabled:opacity-50"
|
||||
>
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
{exporting ? '导出中...' : `下载 ${activeFormat.toUpperCase()}`}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user