zy-react-library/src/components/Word/index.js

130 lines
3.0 KiB
JavaScript
Raw Normal View History

import { Button, message, Modal, Spin } from "antd";
import { renderAsync } from "docx-preview";
import { useEffect, useRef, useState } from "react";
import useDownloadFile from "../../hooks/useDownloadFile";
import { getFileUrl } from "../../utils";
/**
* Word 查看组件
*/
function Word(props) {
const {
visible = false,
onCancel,
file,
name,
inline = false,
title = "Word预览",
style = {},
extraButtons,
} = props;
const contentRef = useRef(null);
const fullscreenRef = useRef(null);
const unmountedRef = useRef(false);
const fileUrl = getFileUrl();
const [loading, setLoading] = useState(false);
const { downloadFile } = useDownloadFile();
const renderWord = async () => {
setLoading(true);
contentRef.current.innerHTML = "";
try {
const response = await fetch(!file.includes(fileUrl) ? fileUrl + file : file);
if (!response.ok)
throw new Error("加载 Word 文件失败");
const data = await response.arrayBuffer();
if (unmountedRef.current)
return;
await renderAsync(data, contentRef.current, null, {
className: "docx-preview",
inWrapper: true,
ignoreWidth: false,
ignoreHeight: false,
breakPages: true,
});
}
catch {
message.error("加载 Word 文件失败");
if (!inline && onCancel)
onCancel();
}
finally {
if (!unmountedRef.current)
setLoading(false);
}
};
useEffect(() => {
if ((!visible && !inline) || !file)
return;
unmountedRef.current = false;
const initTimer = setTimeout(() => {
renderWord();
}, 100);
return () => {
unmountedRef.current = true;
if (contentRef.current)
contentRef.current.innerHTML = "";
if (initTimer)
clearTimeout(initTimer);
};
}, [visible, inline, file]);
const renderWordContent = () => (
<Spin spinning={loading}>
<div
style={{ height: "72vh", overflowY: "auto", padding: "24px", background: "#f5f5f5", ...style }}
>
<div ref={contentRef} />
</div>
</Spin>
);
if (inline)
return renderWordContent();
const onDownloadFile = () => {
downloadFile({
url: file,
name,
});
};
return (
<div ref={fullscreenRef}>
<Modal
style={{ top: 100, maxWidth: "calc(100vw - 32px)", paddingBottom: 24 }}
open={visible}
mask={{ closable: false }}
width={900}
title={title}
onCancel={() => {
onCancel();
}}
getContainer={false}
footer={[
<Button
key="cancel"
onClick={() => {
onCancel();
}}
>
关闭
</Button>,
<Button key="download" type="primary" onClick={onDownloadFile}>下载</Button>,
...(extraButtons || []),
]}
>
{renderWordContent()}
</Modal>
</div>
);
}
Word.displayName = "Word";
export default Word;