generated from eternallycyf/ims-monorepo-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5a621b0
commit de61b2c
Showing
11 changed files
with
637 additions
and
1 deletion.
There are no files selected for viewing
217 changes: 217 additions & 0 deletions
217
packages/ims-view-pc/src/components/FileViewer/FileView.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
import { Image, Skeleton } from 'antd'; | ||
import cx from 'classnames'; | ||
import { renderAsync } from 'docx-preview'; | ||
import type { CSSProperties } from 'react'; | ||
import { PureComponent } from 'react'; | ||
import { OutTable } from 'react-excel-renderer'; | ||
import './index.less'; | ||
import MarkDown from './MarkDown'; | ||
|
||
interface IProps { | ||
styles?: CSSProperties; | ||
src?: string; | ||
base64?: string; | ||
[onherProps: string]: any; | ||
} | ||
|
||
const txtFileTypes = [ | ||
'txt', | ||
'json', | ||
'js', | ||
'css', | ||
'java', | ||
'py', | ||
'html', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'xml', | ||
'md', | ||
'log', | ||
]; | ||
|
||
class FileView extends PureComponent<IProps, any> { | ||
constructor(props: IProps | Readonly<IProps>) { | ||
super(props); | ||
this.state = { | ||
pdfSrc: '', | ||
loading: false, | ||
text: '', | ||
}; | ||
} | ||
componentDidMount() { | ||
const { src, base64 } = this.props; | ||
if (src) { | ||
this.showPDFBySrc(src); | ||
} else if (base64) { | ||
this.showPDFByBase64(base64); | ||
} | ||
} | ||
componentwillUnmount() { | ||
URL.revokeObjectURL(this.state.pdfSrc); | ||
} | ||
//通过src展示 | ||
showPDFBySrc = async (src: string) => { | ||
const { fileType } = this.props; | ||
if (fileType == 'pdf') { | ||
try { | ||
this.setState({ | ||
loading: true, | ||
}); | ||
this.setState({ | ||
pdfSrc: src, | ||
loading: false, | ||
}); | ||
} catch (err) {} | ||
} | ||
|
||
if (fileType == 'word') { | ||
// const url = `xxxxx/${src}`; | ||
// const blob = await axios.get(url, { | ||
// responseType: 'blob' | ||
// }) | ||
// renderAsync( | ||
// blob, | ||
// document.getElementById("file-preview-modal") as HTMLDivElement, | ||
// null as unknown as HTMLDivElement, | ||
// { | ||
// className: "docx", // 默认和文档样式类的类名/前缀 | ||
// inWrapper: true, // 启用围绕文档内容渲染包装器 | ||
// ignoreWidth: false, // 禁止页面渲染宽度 | ||
// ignoreHeight: false, // 禁止页面渲染高度 | ||
// ignoreFonts: false, // 禁止字体渲染 | ||
// breakPages: true, // 在分页符上启用分页 | ||
// ignoreLastRenderedPageBreak: true, //禁用lastRenderedPageBreak元素的分页 | ||
// experimental: false, //启用实验性功能(制表符停止计算) | ||
// trimXmlDeclaration: true, //如果为真,xml声明将在解析之前从xml文档中删除 | ||
// debug: false, // 启用额外的日志记录 | ||
// }, | ||
// ); | ||
} | ||
}; | ||
|
||
//base64转blob | ||
dataURItoBlob = (dataURI: string) => { | ||
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // mime类型 | ||
const byteString = atob(dataURI.split(',')[1]); //base64 解码 | ||
const arrayBuffer = new ArrayBuffer(byteString.length); //创建缓冲数组 | ||
const intArray = new Uint8Array(arrayBuffer); //创建视图 | ||
for (let i = 0; i < byteString.length; i++) { | ||
intArray[i] = byteString.charCodeAt(i); | ||
} | ||
return new Blob([intArray], { type: mimeString }); | ||
}; | ||
|
||
// 转baffer | ||
readBuffer = async (file: any): Promise<Buffer> => { | ||
return new Promise((resolve, reject) => { | ||
const reader = new FileReader(); | ||
reader.onload = (loadEvent: any) => resolve(loadEvent.target.result); | ||
reader.onerror = (e) => reject(e); | ||
reader.readAsArrayBuffer(file); | ||
}); | ||
}; | ||
|
||
// 转文本string | ||
readText = async (buffer: Buffer): Promise<string> => { | ||
return new Promise((resolve, reject) => { | ||
const reader = new FileReader(); | ||
reader.onload = (loadEvent: any) => resolve(loadEvent.target.result); | ||
reader.onerror = (e) => reject(e); | ||
reader.readAsText(new Blob([buffer]), 'utf-8'); | ||
}); | ||
}; | ||
|
||
//通过base64展示 | ||
showPDFByBase64 = async (content: string) => { | ||
const { fileType } = this.props; | ||
const blob = this.dataURItoBlob(content); | ||
const fileUrl = URL.createObjectURL(blob); | ||
this.setState({ | ||
pdfSrc: fileUrl, | ||
loading: false, | ||
}); | ||
|
||
if (txtFileTypes.includes(fileType)) { | ||
const Buffer = await this.readBuffer(blob); | ||
const text = await this.readText(Buffer); | ||
this.setState({ | ||
text, | ||
}); | ||
} | ||
|
||
// 当使用旧版浏览器时 需要兼容 globalThis | ||
if (fileType === 'docx') { | ||
setTimeout(() => { | ||
renderAsync( | ||
blob, | ||
document.getElementById('file-preview-modal') as HTMLDivElement, | ||
null as unknown as HTMLDivElement, | ||
{ | ||
className: 'docx', // 默认和文档样式类的类名/前缀 | ||
inWrapper: true, // 启用围绕文档内容渲染包装器 | ||
ignoreWidth: false, // 禁止页面渲染宽度 | ||
ignoreHeight: false, // 禁止页面渲染高度 | ||
ignoreFonts: false, // 禁止字体渲染 | ||
breakPages: true, // 在分页符上启用分页 | ||
ignoreLastRenderedPageBreak: true, //禁用lastRenderedPageBreak元素的分页 | ||
experimental: false, //启用实验性功能(制表符停止计算) | ||
trimXmlDeclaration: true, //如果为真,xml声明将在解析之前从xml文档中删除 | ||
debug: false, // 启用额外的日志记录 | ||
}, | ||
); | ||
}, 0); | ||
} | ||
}; | ||
|
||
render() { | ||
const { styles, className, fileType, txtFileTypes, excelData } = this.props; | ||
const { loading, pdfSrc, text } = this.state; | ||
const src = `${pdfSrc}`; | ||
|
||
if (loading) { | ||
return <Skeleton loading paragraph={{ rows: 10 }} active />; | ||
} | ||
|
||
if (fileType == 'docx') { | ||
return <div id="file-preview-modal" />; | ||
} | ||
|
||
if (fileType == 'xlsx') { | ||
return ( | ||
<OutTable | ||
data={excelData.rows} | ||
columns={excelData.cols} | ||
tableClassName="ExcelTable2007" | ||
tableHeaderRowClass="heading" | ||
/> | ||
); | ||
} | ||
|
||
if (fileType == 'png' || fileType == 'jpg') { | ||
return ( | ||
<div className="image"> | ||
<Image src={src} /> | ||
</div> | ||
); | ||
} | ||
|
||
if (txtFileTypes?.includes(fileType)) { | ||
const newText = ` | ||
~~~${fileType} | ||
${text} | ||
~~~ | ||
`; | ||
return <MarkDown markdown={newText} />; | ||
} | ||
|
||
if (fileType == 'pdf') { | ||
return ( | ||
<iframe className={cx('iframeStyle', className)} style={styles} src={src} title="pdf预览" /> | ||
); | ||
} | ||
|
||
return <span>不支持</span>; | ||
} | ||
} | ||
export default FileView; |
99 changes: 99 additions & 0 deletions
99
packages/ims-view-pc/src/components/FileViewer/FileViewer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { message, Modal } from 'antd'; | ||
import React, { PureComponent } from 'react'; | ||
import { ExcelRenderer } from 'react-excel-renderer'; | ||
import FileView from './FileView'; | ||
const txtFileTypes = [ | ||
'txt', | ||
'json', | ||
'js', | ||
'css', | ||
'java', | ||
'py', | ||
'html', | ||
'jsx', | ||
'ts', | ||
'tsx', | ||
'xml', | ||
'md', | ||
'log', | ||
]; | ||
|
||
const fileAllTypes = ['docx', 'xlsx', 'png', 'jpg', 'pdf', ...txtFileTypes]; | ||
class FilePreView extends PureComponent<any, any> { | ||
protected pdfViewRef: React.RefObject<any> = React.createRef(); | ||
protected previewWrapperRef: React.RefObject<HTMLDivElement> = React.createRef(); | ||
constructor(props: any) { | ||
super(props); | ||
this.state = { | ||
modalVisible: false, | ||
fileType: '', | ||
excelData: { | ||
cols: [], | ||
rows: [], | ||
}, | ||
}; | ||
} | ||
//显隐状态的改变 | ||
controlIsShow = (params: { src?: string; base64?: string; originFileObj?: any }) => { | ||
const { modalVisible } = this.state; | ||
const { src, base64, originFileObj } = params; | ||
const { name } = originFileObj; | ||
const fileType = name.slice(name.lastIndexOf('.') + 1).toLowerCase(); | ||
|
||
if (!fileAllTypes.includes(fileType)) { | ||
return message.error('该文件不支持预览'); | ||
} | ||
if (fileType == 'xlsx') { | ||
ExcelRenderer(originFileObj, (err: Error, resp: any) => { | ||
this.setState({ | ||
excelData: { | ||
cols: resp.cols, | ||
rows: resp.rows, | ||
}, | ||
}); | ||
}); | ||
} | ||
this.setState({ | ||
modalVisible: !modalVisible, | ||
src, | ||
base64, | ||
fileType, | ||
}); | ||
}; | ||
|
||
render() { | ||
const { modalVisible, src, base64, fileType, excelData } = this.state; | ||
return ( | ||
<Modal | ||
open={modalVisible} | ||
title={fileType + ' 预览'} | ||
onCancel={() => { | ||
this.setState({ | ||
modalVisible: false, | ||
}); | ||
}} | ||
width={1200} | ||
styles={{ | ||
body: { | ||
overflow: 'scroll', | ||
height: '70vh', | ||
}, | ||
}} | ||
footer={null} | ||
destroyOnClose={true} | ||
> | ||
<FileView | ||
id="file-preview-modal" | ||
ref={this.pdfViewRef} | ||
src={src} | ||
base64={base64} | ||
fileType={fileType} | ||
excelData={excelData} | ||
txtFileTypes={txtFileTypes} | ||
styles={{ height: '600px' }} | ||
/> | ||
</Modal> | ||
); | ||
} | ||
} | ||
export default FilePreView; |
34 changes: 34 additions & 0 deletions
34
packages/ims-view-pc/src/components/FileViewer/MarkDown.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import ReactMarkdown from 'react-markdown'; | ||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; | ||
import { dracula } from 'react-syntax-highlighter/dist/esm/styles/prism'; | ||
import remarkGfm from 'remark-gfm'; | ||
|
||
export default (props: any) => { | ||
return ( | ||
<ReactMarkdown | ||
// eslint-disable-next-line react/no-children-prop | ||
children={props.markdown} | ||
remarkPlugins={[remarkGfm]} | ||
components={{ | ||
code({ className, children }) { | ||
const match = /language-(\w+)/.exec(className || ''); | ||
return match ? ( | ||
<SyntaxHighlighter | ||
// eslint-disable-next-line react/no-children-prop | ||
children={String(children).replace(/\n$/, '')} | ||
style={dracula} | ||
language={match[1]} | ||
showLineNumbers | ||
PreTag="div" | ||
{...props} | ||
/> | ||
) : ( | ||
<code className={className} {...props}> | ||
{children} | ||
</code> | ||
); | ||
}, | ||
}} | ||
/> | ||
); | ||
}; |
Oops, something went wrong.