128 lines
2.9 KiB
JavaScript
128 lines
2.9 KiB
JavaScript
|
|
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 = {},
|
||
|
|
} = 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>,
|
||
|
|
]}
|
||
|
|
>
|
||
|
|
{renderWordContent()}
|
||
|
|
</Modal>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Word.displayName = "Word";
|
||
|
|
|
||
|
|
export default Word;
|