|
| 1 | +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' |
| 2 | +import { saveAs } from 'file-saver' |
| 3 | +import type { FC } from 'react' |
| 4 | +import * as XLSX from 'xlsx' |
| 5 | + |
| 6 | +type DropdownProps = { |
| 7 | + renderRecords: any |
| 8 | + paraphrases: any |
| 9 | +} |
| 10 | + |
| 11 | +const DropdownExport: FC<DropdownProps> = ({ renderRecords, paraphrases }) => { |
| 12 | + const formatTimestamp = (date: any) => { |
| 13 | + const year = date.getFullYear() |
| 14 | + const month = String(date.getMonth() + 1).padStart(2, '0') // 月份从0开始 |
| 15 | + const day = String(date.getDate()).padStart(2, '0') |
| 16 | + const hours = String(date.getHours()).padStart(2, '0') |
| 17 | + const minutes = String(date.getMinutes()).padStart(2, '0') |
| 18 | + const seconds = String(date.getSeconds()).padStart(2, '0') |
| 19 | + |
| 20 | + return `${year}-${month}-${day} ${hours}-${minutes}-${seconds}` |
| 21 | + } |
| 22 | + |
| 23 | + const handleExport = (bookType: string) => { |
| 24 | + const ExportData: Array<{ 单词: string; 释义: string; 错误次数: number; 词典: string }> = [] |
| 25 | + |
| 26 | + renderRecords.forEach((item: any) => { |
| 27 | + const word = paraphrases.find((w: any) => w.name === item.word) |
| 28 | + ExportData.push({ |
| 29 | + 单词: item.word, |
| 30 | + 释义: word ? word.trans.join(';') : '', |
| 31 | + 错误次数: item.wrongCount, |
| 32 | + 词典: item.dict, |
| 33 | + }) |
| 34 | + }) |
| 35 | + |
| 36 | + let blob: Blob |
| 37 | + |
| 38 | + if (bookType === 'txt') { |
| 39 | + const content = ExportData.map((item: any) => `${item.单词}: ${item.释义}`).join('\n') |
| 40 | + blob = new Blob([content], { type: 'text/plain' }) |
| 41 | + } else { |
| 42 | + const worksheet = XLSX.utils.json_to_sheet(ExportData) |
| 43 | + const workbook = XLSX.utils.book_new() |
| 44 | + XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') |
| 45 | + const excelBuffer = XLSX.write(workbook, { bookType: bookType as XLSX.BookType, type: 'array' }) |
| 46 | + blob = new Blob([excelBuffer], { type: 'application/octet-stream' }) |
| 47 | + } |
| 48 | + |
| 49 | + const timestamp = formatTimestamp(new Date()) |
| 50 | + const fileName = `ErrorBook_${timestamp}.${bookType}` |
| 51 | + |
| 52 | + if (blob && fileName) { |
| 53 | + saveAs(blob, fileName) |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + return ( |
| 58 | + <div className="z-10"> |
| 59 | + <DropdownMenu.Root> |
| 60 | + <DropdownMenu.Trigger asChild> |
| 61 | + <button className="my-btn-primary h-8 shadow transition hover:bg-indigo-600">导出</button> |
| 62 | + </DropdownMenu.Trigger> |
| 63 | + <DropdownMenu.Content className="mt-1 rounded bg-indigo-500 text-white shadow-lg"> |
| 64 | + <DropdownMenu.Item |
| 65 | + className="cursor-pointer rounded px-4 py-2 hover:bg-indigo-400 focus:bg-indigo-600 focus:outline-none" |
| 66 | + onClick={() => handleExport('xlsx')} |
| 67 | + > |
| 68 | + .xlsx |
| 69 | + </DropdownMenu.Item> |
| 70 | + <DropdownMenu.Item |
| 71 | + className="cursor-pointer rounded px-4 py-2 hover:bg-indigo-600 focus:bg-indigo-600 focus:outline-none" |
| 72 | + onClick={() => handleExport('csv')} |
| 73 | + > |
| 74 | + .csv |
| 75 | + </DropdownMenu.Item> |
| 76 | + </DropdownMenu.Content> |
| 77 | + </DropdownMenu.Root> |
| 78 | + </div> |
| 79 | + ) |
| 80 | +} |
| 81 | + |
| 82 | +export default DropdownExport |
0 commit comments