ExcelJs使用tRPC路由器下载xlsx文件



我想点击底部下载excel文件,但我不明白为什么它不起作用
主要问题出现在tRPC路由器端。

我使用的工具:

  1. T3
  2. ExcelJs

tRPC路由器:

.mutation("xlsx", {
input: z.object({
id: z.string(),
}),
resolve: async ({ ctx }) => {
const FILE_PATH = "./src/utils/01.xlsx";
const wb = new ExcelJs.Workbook();
await wb.xlsx.readFile(FILE_PATH).then(() => {
var ws = wb.getWorksheet(1);
ws.getCell("H4").value = "fkfk";
});
return wb.xlsx.write(ctx.res);
},
});

前端:

function Print() {
const xlsxMutation = trpc.useMutation(['guest.xlsx'])
const onDownload = React.useCallback(()=>{
xlsxMutation.mutate({
id:"test"
})
},[xlsxMutation])

return (
<>
<button onClick={()=>handleClickOpen()}>download</button>

</>

);
}

CodeSandBox

codesandbox还没有安装ExcelJS,因为我不确定为什么会出现错误
不管怎样,它模拟了我的代码结构

是否有人使用NextJS tRPC和ExcelJS共享代码。

##编辑
由于xlsx文件已经存在(file_PATH(,我应该使用类似ctx.res.pipe()的内容,对吗?但是怎么做呢??

不确定这种方法是否正确,请阅读关于Blob的文档,然后了解服务器和客户端Transformers的数据(如图像或pdf文件等(,所以我选择了这种方式。

tRPC:

.mutation("xlsx", {
input: z.object({
id: z.string(),
}),
resolve: async ({ ctx }) => {
const wb = await new ExcelJs.Workbook();
await wb.xlsx.readFile(PUBLIC_FILE_PATH).then(() => {
var ws = wb.getWorksheet(1);
ws.getCell("H4").value = "OKM";
});

await wb.xlsx.writeFile(PUBLIC_FILE_PATH);
const stream = fs.readFileSync(PUBLIC_FILE_PATH);
return {xxx:stream.toString("base64")}

},
});

前端:

function Print() {
const xlsxMutation = trpc.useMutation(["guest.xlsx"]);
const onDownload = React.useCallback(() => {
xlsxMutation.mutate({
id: "test",
});
}, [xlsxMutation]);
const [open, setOpen] = React.useState(true);
const handleClickOpen = () => {
onDownload();
if (!xlsxMutation.data) return;
const mediaType =
"data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,";
window.location.href = `${mediaType}${xlsxMutation.data.xxx}`;
};
const handleClose = () => {
setOpen(false);
};
return (
<>
<button onClick={() => handleClickOpen()}>Download</button>
</>
);
}

基本上,路由器端将转换成base64的excel文件发送回,fontend得到base64的数据,将其转换回xlsx文件。

请参阅:

  1. 在此处输入链接描述
  2. 下载Excel.xlsx可在文件中保存base64字符串

类似于@Balius的方法,我的方法利用了enabled+saveAs npm库的useQuery属性:

import { saveAs } from "file-saver";
const Questionnaires: NextPage = () => {
const [exportToDocxClicked, setExportToDocxClicked] = useState('');
const docxBlobQuery = trpc.form.report.useQuery(
{ id: exportToDocxClicked },
{ enabled: !!exportToDocxClicked }
);

useEffect(() => {
if (docxBlobQuery.isSuccess) {
const blob = new Blob(
[docxBlobQuery.data?.buffer],
{type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'}
);
saveAs(blob, 'test.docx');
setExportToDocxClicked('');
}
}, [docxBlobQuery]);


const exportToDocx = (id: string) => {
setExportToDocxClicked(id);
}
...
<Button onClick={() => exportToDocx(id)} />
...

然后在tRPC路由器中创建文件并返回缓冲区,在这种情况下,我使用docx模板包在docx缓冲区(仅字符串(中创建报告

import createReport from 'docx-templates';
report: protectedProcedure
.input(
z
.object({
id: z.string().optional(),
})
)
.query(async ({ ctx, input }) => {
try {
const template = await fs.readFile(templatesDirectory + '/test_template.docx');

const buffer = await createReport({
template
});

return {
buffer
};
} catch (error) {
console.error(error);
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'An unexpected error occurred, please try again later.',
// optional: pass the original error to retain stack trace
cause: error,
});
}
}),

我推荐";XLSX";npm包导出文件,它有更多的选项,它工作。尽管exceljs对我不起作用,即使我按照t.的指南

最新更新