Revert "feat: 支持PDF预览" (#9694)

This commit is contained in:
liaoxuezhi 2024-02-29 21:01:03 +08:00 committed by GitHub
parent b1252fe0c1
commit eccd5c7ea5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 5 additions and 486 deletions

View File

@ -1,54 +0,0 @@
---
title: PDF Viewer
description:
type: 0
group: ⚙ 组件
menuName: PDFViewer 渲染
icon:
order: 24
---
## 基本用法
```schema: scope="body"
{
"type": "pdf-viewer",
"id": "pdf-viewer",
"src": "/examples/static/simple.pdf"
}
```
## 配合文件上传实现预览功能
配置和 `input-file` 相同的 `name` 即可
```schema: scope="body"
{
"type": "form",
"title": "",
"wrapWithPanel": false,
"body": [
{
"type": "input-file",
"name": "file",
"label": "File",
"asBlob": true,
"accept": ".pdf"
},
{
"type": "pdf-viewer",
"id": "pdf-viewer",
"name": "file"
}
]
}
```
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| ---------- | ------ | ------ | ---------- |
| src | Api | | 文档地址 |
| width | number | 500 | 宽度 |
| height | number | - | 高度 |
| background | string | #fff | PDF 背景色 |

View File

@ -987,13 +987,6 @@ export const components = [
import('../../docs/zh-CN/components/office-viewer.md').then(wrapDoc)
)
},
{
label: 'PDFViewer 渲染',
path: '/zh-CN/components/pdf-viewer',
component: React.lazy(() =>
import('../../docs/zh-CN/components/pdf-viewer.md').then(wrapDoc)
)
},
{
label: 'Progress 进度条',
path: '/zh-CN/components/progress',

View File

@ -130,7 +130,6 @@ import Tab3Schema from './Tabs/Tab3';
import Loading from './Loading';
import CodeSchema from './Code';
import OfficeViewer from './OfficeViewer';
import PdfViewer from './PdfViewer';
import InputTableEvent from './EventAction/cmpt-event-action/InputTableEvent';
import WizardPage from './WizardPage';
@ -913,13 +912,6 @@ export const examples = [
component: makeSchemaRenderer(OfficeViewer)
},
{
label: 'Pdf 预览',
icon: 'fa fa-file-pdf',
path: '/examples/pdf-viewer',
component: makeSchemaRenderer(PdfViewer)
},
{
label: '多 loading',
icon: 'fa fa-spinner',

View File

@ -1,23 +0,0 @@
export default {
type: 'page',
body: {
type: 'form',
id: 'form',
debug: true,
wrapWithPanel: false,
body: [
{
type: 'input-file',
name: 'file',
label: '选择 PDF 文件预览效果(不会上传到服务器)',
asBlob: true,
accept: '.pdf'
},
{
type: 'pdf-viewer',
id: 'pdf-viewer',
name: 'file'
}
]
}
};

Binary file not shown.

View File

@ -241,7 +241,7 @@ fis.match('/examples/mod.js', {
isMod: false
});
fis.match('{markdown-it,moment-timezone,pdfjs-dist}/**', {
fis.match('{markdown-it,moment-timezone}/**', {
preprocessor: fis.plugin('js-require-file')
});
@ -503,7 +503,6 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!amis-ui/lib/components/RichText.js',
'!amis-ui/lib/components/Tinymce.js',
'!amis-ui/lib/components/ColorPicker.js',
'!amis-ui/lib/components/PdfViewer.js',
'!react-color/**',
'!material-colors/**',
'!reactcss/**',
@ -563,11 +562,6 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'tinycolor2/**'
],
'pdf-viewer.js': [
'amis-ui/lib/components/PdfViewer.js',
'pdfjs-dist/build/pdf.worker.min.js'
],
'cropperjs.js': ['cropperjs/**', 'react-cropper/**'],
'barcode.js': ['src/components/BarCode.tsx', 'jsbarcode/**'],
@ -590,7 +584,6 @@ if (fis.project.currentMedia() === 'publish-sdk') {
'!mpegts.js/**',
'!hls.js/**',
'!froala-editor/**',
'!pdfjs-dist/**',
'!amis-ui/lib/components/RichText.js',
'!zrender/**',

View File

@ -65,7 +65,6 @@
"react-intersection-observer": "9.5.2",
"react-json-view": "1.21.3",
"react-overlays": "5.1.1",
"react-pdf": "^7.7.1",
"react-textarea-autosize": "8.3.3",
"react-transition-group": "4.4.2",
"react-visibility-sensor": "5.1.1",
@ -144,4 +143,4 @@
]
},
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
}
}

View File

@ -49,8 +49,7 @@ const input = [
'./src/components/Markdown.tsx',
'./src/components/Tinymce.tsx',
'./src/components/RichText.tsx',
'./src/components/CityDB.ts',
'./src/components/PdfViewer.tsx'
'./src/components/CityDB.ts'
];
/** 获取子包编译后的入口路径,需要使用相对路径 */

View File

@ -1,45 +0,0 @@
.#{$ns}PdfViewer {
position: relative;
height: 100%;
min-height: 500px;
display: flex;
justify-content: center;
padding: 50px 0;
&-Content {
width: max-content;
max-width: 100%;
&.is-loaded {
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px 0px;
}
}
&-Loading {
text-align: center;
}
&-Tool {
position: absolute;
z-index: 10;
padding: 5px 15px;
bottom: 60px;
background-color: #444444;
border-radius: 10px;
color: #fff;
text-align: center;
user-select: none;
.gap {
margin: 0 4px;
}
.icon {
cursor: pointer;
width: 20px;
margin: 0 10px;
&:hover {
color: var(--colors-brand-5);
}
}
.page-input {
width: 40px;
}
}
}

View File

@ -142,6 +142,5 @@
@import '../components/debug';
@import '../components/menu';
@import '../components/overflow-tpl';
@import '../components/pdf_viewer';
@import '../components/print';

View File

@ -1,143 +0,0 @@
/**
* @file PdfViewer.tsx PDF
*
* @created: 2024/02/26
*/
import React from 'react';
import {themeable, ThemeProps} from 'amis-core';
import {Document, Page, pdfjs} from 'react-pdf';
import {Icon} from './icons';
import Input from './Input';
import Spinner from './Spinner';
// @ts-ignore
import pdfJSWorkerURL from 'pdfjs-dist/build/pdf.worker.min';
pdfjs.GlobalWorkerOptions.workerSrc = pdfJSWorkerURL;
export interface PdfViewerProps extends ThemeProps {
file?: ArrayBuffer;
width?: number;
height?: number;
background?: string;
}
const PdfViewer: React.FC<PdfViewerProps> = props => {
const {classnames: cx, className, width = 500} = props;
const [file, setFile] = React.useState(props.file);
const [loaded, setLoaded] = React.useState(false);
const [page, setPage] = React.useState(1);
const [scale, setScale] = React.useState(1);
const [total, setTotal] = React.useState(1);
const inputRef = React.useRef<HTMLInputElement>();
React.useEffect(() => {
if (props.file instanceof ArrayBuffer && props.file.byteLength > 0) {
setFile(props.file);
} else {
setFile(undefined);
}
}, [props.file]);
function handleLoadSuccess({numPages}: {numPages: number}) {
setLoaded(true);
setTotal(numPages);
}
function handleChangePage(idx: number) {
const newPage = page + idx;
if (newPage <= 0 || newPage > total) {
return;
}
setPage(newPage);
}
function handlePageBlur(event: React.ChangeEvent<HTMLInputElement>) {
const newPage = +event.target.value;
if (isNaN(newPage) || newPage <= 0 || newPage > total) {
if (inputRef.current) {
inputRef.current.value = page + '';
}
return;
}
setPage(newPage);
}
function handleChangeScale(t: number) {
setScale(scale * t);
}
if (!file) {
return null;
}
function renderLoading() {
return (
<div className={cx('PdfViewer-Loading')} style={{width: `${width}px`}}>
<Spinner />
</div>
);
}
function renderTool() {
return (
<div className={cx('PdfViewer-Tool')}>
<Icon
className="icon"
icon="prev"
onClick={() => handleChangePage(-1)}
/>
<Input
className="page-input"
value={page}
onBlur={handlePageBlur}
ref={inputRef}
/>
<span className="gap">/</span>
<span>{total}</span>
<Icon
className="icon"
icon="next"
onClick={() => handleChangePage(1)}
/>
<Icon
className="icon"
icon="zoom-in"
onClick={() => handleChangeScale(1.2)}
/>
<Icon
className="icon"
icon="zoom-out"
onClick={() => handleChangeScale(0.8)}
/>
</div>
);
}
return (
<div className={cx(className, 'PdfViewer')}>
<div className={cx('PdfViewer-Content', {'is-loaded': loaded})}>
<Document
file={file}
onLoadSuccess={handleLoadSuccess}
loading={renderLoading()}
>
<Page
className={cx('PdfViewer-Content-Page')}
pageNumber={page}
width={width}
height={props.height}
loading={renderLoading()}
noData={<div>No PDF data</div>}
scale={scale}
renderTextLayer={false}
renderAnnotationLayer={false}
/>
</Document>
</div>
{loaded ? renderTool() : null}
</div>
);
};
export default themeable(PdfViewer);

View File

@ -3,7 +3,7 @@ import {localeable, LocaleProps} from 'amis-core';
import {themeable, ThemeProps} from 'amis-core';
import {Icon} from './icons';
import type {IconCheckedSchema} from '../index';
import type {IconCheckedSchema} from 'amis-ui';
export interface TimelineItemProps {
/**

View File

@ -244,4 +244,4 @@
"react-dom": ">=16.8.6"
},
"gitHead": "37d23b4a8eb1c663bc38e8dd9040889ea1526ec4"
}
}

View File

@ -253,7 +253,6 @@ export type SchemaType =
| 'input-formula'
| 'diff-editor'
| 'office-viewer'
| 'pdf-viewer'
// editor 系列
| 'editor'

View File

@ -153,7 +153,6 @@ import './renderers/Password';
import './renderers/DateRange';
import './renderers/MultilineText';
import './renderers/OfficeViewer';
import './renderers/PdfViewer';
import './renderers/AMIS';
import './compat';

View File

@ -1,189 +0,0 @@
/**
* @file PdfViewer.tsx PDF
*
* @created: 2024/02/26
*/
import React from 'react';
import {
autobind,
getVariable,
isApiOutdated,
IScopedContext,
Renderer,
RendererProps,
resolveVariableAndFilter,
ScopedContext
} from 'amis-core';
import {BaseSchema} from '../Schema';
export const PdfView = React.lazy(
() => import('amis-ui/lib/components/PdfViewer')
);
export interface PdfViewerSchema extends BaseSchema {
type: 'pdf-viewer';
/**
*
*/
src?: string;
/**
* 使
*/
name?: string;
width?: number;
height?: number;
background?: string;
}
export interface PdfViewerProps extends RendererProps {}
interface PdfViewerState {
loading: boolean;
}
export default class PdfViewer extends React.Component<
PdfViewerProps,
PdfViewerState
> {
file?: ArrayBuffer;
reader?: FileReader;
fetchCancel?: Function;
constructor(props: PdfViewerProps) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
this.renderPdf();
}
componentDidUpdate(prevProps: PdfViewerProps) {
const props = this.props;
if (isApiOutdated(prevProps.src, props.src, prevProps.data, props.data)) {
this.abortLoad();
this.fetchPdf();
}
if (getVariable(props.data, props.name)) {
if (
getVariable(prevProps.data, prevProps.name) !==
getVariable(props.data, props.name)
) {
this.abortLoad();
this.renderPdf();
}
}
}
@autobind
abortLoad() {
if (this.fetchCancel) {
this.fetchCancel('load canceled');
this.fetchCancel = undefined;
}
if (this.reader) {
this.reader.abort();
this.reader = undefined;
}
}
@autobind
async renderPdf() {
const {src, name, data} = this.props;
// src 优先级高于 name
if (src) {
if (!this.file) {
await this.fetchPdf();
}
} else if (getVariable(data, name)) {
await this.renderFormFile();
}
}
@autobind
async fetchPdf() {
const {env, src, data, translate: __} = this.props;
const finalSrc = src
? resolveVariableAndFilter(src, data, '| raw')
: undefined;
if (!finalSrc) {
console.warn('file src is empty');
return;
}
this.setState({
loading: true
});
try {
const res = await env.fetcher(finalSrc, data, {
responseType: 'arraybuffer',
cancelExecutor: (executor: Function) => (this.fetchCancel = executor)
});
this.file = res.data;
this.forceUpdate();
} catch (error) {
console.error(error);
} finally {
this.setState({
loading: false
});
}
}
@autobind
async renderFormFile() {
const {name, data} = this.props;
const file = getVariable(data, name);
if (file instanceof File) {
const reader = new FileReader();
reader.onload = _e => {
const data = reader.result as ArrayBuffer;
this.file = data;
this.forceUpdate();
};
reader.readAsArrayBuffer(file);
this.reader = reader;
}
}
render() {
const {className, classnames: cx, width, height, background} = this.props;
return (
<PdfView
file={this.file}
className={className}
classnames={cx}
width={width}
height={height}
background={background}
/>
);
}
}
@Renderer({
type: 'pdf-viewer'
})
export class PdfViewerRenderer extends PdfViewer {
static contextType = ScopedContext;
constructor(props: PdfViewerProps, context: IScopedContext) {
super(props);
const scoped = context;
scoped.registerComponent(this);
}
componentWillUnmount() {
super.componentWillUnmount?.();
const scoped = this.context as IScopedContext;
scoped.unRegisterComponent(this);
}
}