@lingxiteam/ebe-utils 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/es/index.d.ts +11 -6
- package/es/index.js +63 -52
- package/es/node/babel/getAllImportFiles.d.ts +1 -1
- package/es/node/babel/getAllImportFiles.js +4 -4
- package/es/node/move.d.ts +1 -0
- package/es/node/move.js +21 -13
- package/lib/h5public/src/components/factory/package.json +4 -0
- package/lib/h5public/src/components/factory/src/BlockSelect/index.tsx +9 -1
- package/lib/h5public/src/components/factory/src/DynamicDataContainer/index.tsx +24 -5
- package/lib/h5public/src/components/factory/src/DynamicList/MySwipe/index.tsx +1 -1
- package/lib/h5public/src/hooks/usePageForm.ts +108 -4
- package/lib/h5public/src/utils/LcdpSpin/index.tsx +15 -3
- package/lib/h5public/src/utils/formUtils.ts +336 -0
- package/lib/node/babel/getAllImportFiles.d.ts +1 -1
- package/lib/node/babel/getAllImportFiles.js +3 -3
- package/lib/node/move.d.ts +1 -0
- package/lib/node/move.js +19 -8
- package/lib/pcpublic/src/components/common/PreviewFile/index.less +200 -0
- package/lib/pcpublic/src/components/common/PreviewFile/index.tsx +787 -0
- package/lib/pcpublic/src/components/common/PreviewFile/utils.ts +90 -0
- package/lib/pcpublic/src/components/pcfactory/package.json +4 -0
- package/lib/pcpublic/src/components/pcfactory/src/Audio/index.tsx +6 -6
- package/lib/pcpublic/src/components/pcfactory/src/Cascader/index.tsx +15 -0
- package/lib/pcpublic/src/components/pcfactory/src/Checkbox/index.tsx +2 -2
- package/lib/pcpublic/src/components/pcfactory/src/DynamicDataContainer/index.tsx +301 -0
- package/lib/pcpublic/src/components/pcfactory/src/DynamicDataContainer/useDynamicDataContainer.ts +27 -0
- package/lib/pcpublic/src/components/pcfactory/src/Form/Form.tsx +1 -0
- package/lib/pcpublic/src/components/pcfactory/src/GridView/GridView.tsx +1 -1
- package/lib/pcpublic/src/components/pcfactory/src/Img/assets/placeholder.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/Input/index.tsx +1 -1
- package/lib/pcpublic/src/components/pcfactory/src/LoopList/index.tsx +1 -1
- package/lib/pcpublic/src/components/pcfactory/src/ModalSelect/index.tsx +1 -1
- package/lib/pcpublic/src/components/pcfactory/src/PictureVerifyCode/assets/placeholder.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/PictureVerifyCode/index.tsx +6 -6
- package/lib/pcpublic/src/components/pcfactory/src/QuillEditor/index.tsx +11 -0
- package/lib/pcpublic/src/components/pcfactory/src/RemoteComponent/components/ReactRender.tsx +5 -1
- package/lib/pcpublic/src/components/pcfactory/src/RemoteComponent/constant.ts +36 -0
- package/lib/pcpublic/src/components/pcfactory/src/RemoteComponent/index.tsx +28 -16
- package/lib/pcpublic/src/components/pcfactory/src/RichTextEditor/RichTextEditor.tsx +12 -5
- package/lib/pcpublic/src/components/pcfactory/src/Select/index.tsx +65 -39
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/default.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/js.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/pdf.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/ppt.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/txt.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/word.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/xls.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/assets/zip.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/StdUpload/index.tsx +11 -1
- package/lib/pcpublic/src/components/pcfactory/src/SuperSelect/ComSelect.tsx +1 -2
- package/lib/pcpublic/src/components/pcfactory/src/Table/TableSummaryRow/index.tsx +8 -1
- package/lib/pcpublic/src/components/pcfactory/src/Table/hooks/useCMDActions.ts +4 -4
- package/lib/pcpublic/src/components/pcfactory/src/Table/hooks/useColumns.tsx +91 -34
- package/lib/pcpublic/src/components/pcfactory/src/Table/hooks/useSelection.ts +22 -11
- package/lib/pcpublic/src/components/pcfactory/src/Table/hooks/useSummaryCol.ts +51 -8
- package/lib/pcpublic/src/components/pcfactory/src/Table/index.tsx +28 -6
- package/lib/pcpublic/src/components/pcfactory/src/Table/types/bodyCell.d.ts +22 -0
- package/lib/pcpublic/src/components/pcfactory/src/Table/types/contentStyle.d.ts +41 -0
- package/lib/pcpublic/src/components/pcfactory/src/Table/types/event.d.ts +129 -0
- package/lib/pcpublic/src/components/pcfactory/src/Table/types/headerCell.d.ts +37 -0
- package/lib/pcpublic/src/components/pcfactory/src/Table/types/prop.d.ts +301 -0
- package/lib/pcpublic/src/components/pcfactory/src/Table/utils/index.ts +83 -31
- package/lib/pcpublic/src/components/pcfactory/src/Table/utils/indexedDBHelper.ts +119 -0
- package/lib/pcpublic/src/components/pcfactory/src/Transfer/index.tsx +8 -3
- package/lib/pcpublic/src/components/pcfactory/src/Tree/index.tsx +4 -1
- package/lib/pcpublic/src/components/pcfactory/src/TreeSelect/index.tsx +12 -1
- package/lib/pcpublic/src/components/pcfactory/src/TreeTable/index.tsx +28 -3
- package/lib/pcpublic/src/components/pcfactory/src/VerificationCode/assets/placeholder.png +0 -0
- package/lib/pcpublic/src/components/pcfactory/src/VerificationCode/index.tsx +6 -6
- package/lib/pcpublic/src/components/pcfactory/src/VideoPlayer/index.tsx +12 -12
- package/lib/pcpublic/src/components/pcfactory/src/View/index.tsx +18 -4
- package/lib/pcpublic/src/components/pcfactory/src/index.component.ts +3 -0
- package/lib/pcpublic/src/components/pcfactory/src/styles/common.less +6 -1
- package/lib/pcpublic/src/components/pcfactory/src/styles/components/Form.less +4 -0
- package/lib/pcpublic/src/components/pcfactory/src/styles/components/Input.less +3 -0
- package/lib/pcpublic/src/components/pcfactory/src/styles/components/InputNumber.less +1 -1
- package/lib/pcpublic/src/components/pcfactory/src/styles/components/ModalSelect.less +3 -0
- package/lib/pcpublic/src/components/pcfactory/src/styles/components/Table.less +5 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/DummyFormContext.ts +2 -2
- package/lib/pcpublic/src/components/pcfactory/src/utils/Empty/empty.tsx +29 -28
- package/lib/pcpublic/src/components/pcfactory/src/utils/Empty/index.tsx +36 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/Spin/index.tsx +29 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/common.ts +18 -2
- package/lib/pcpublic/src/components/pcfactory/src/utils/formUtils/FormContext.tsx +10 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/formUtils/FormFields.tsx +10 -5
- package/lib/pcpublic/src/components/pcfactory/src/utils/formUtils/common.ts +46 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/hooks/useCompState.tsx +44 -0
- package/lib/pcpublic/src/components/pcfactory/src/utils/hooks/useLocale.ts +1 -0
- package/lib/pcpublic/src/utils/formUtils.ts +458 -0
- package/lib/public/src/components/WaterMark/index.tsx +1 -1
- package/lib/public/src/services/api/index.ts +7 -0
- package/package.json +2 -2
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
import api from '@/services/api/file';
|
|
2
|
+
import {
|
|
3
|
+
DownOutlined,
|
|
4
|
+
RotateLeftOutlined,
|
|
5
|
+
RotateRightOutlined,
|
|
6
|
+
} from '@ant-design/icons';
|
|
7
|
+
import { Cascader, message, Spin } from 'antd';
|
|
8
|
+
import classnames from 'classnames';
|
|
9
|
+
import React, {
|
|
10
|
+
useCallback,
|
|
11
|
+
useEffect,
|
|
12
|
+
useMemo,
|
|
13
|
+
useRef,
|
|
14
|
+
useState,
|
|
15
|
+
} from 'react';
|
|
16
|
+
import pageIcon from '../../../assets/pageicon';
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
import { Document, Page, pdfjs } from 'react-pdf';
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
import pdfworker from 'react-pdf/dist/pdf.worker.entry';
|
|
21
|
+
import './index.less';
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
import { addFileUrlSign, useCreation } from '@/utils/engine-utils';
|
|
24
|
+
|
|
25
|
+
import security from '@/utils/Security';
|
|
26
|
+
|
|
27
|
+
import { LocaleFunction } from '@lingxiteam/types';
|
|
28
|
+
import {
|
|
29
|
+
CAN_SCALE,
|
|
30
|
+
isUrlFormat,
|
|
31
|
+
LOCAL_PREVIEW,
|
|
32
|
+
parseFileInfo,
|
|
33
|
+
PREVIEW_MODE,
|
|
34
|
+
} from './utils';
|
|
35
|
+
|
|
36
|
+
interface PreviewFileProps {
|
|
37
|
+
// appId: string;
|
|
38
|
+
fileIdOrUrl: string;
|
|
39
|
+
// pageId: string;
|
|
40
|
+
file?: any;
|
|
41
|
+
showDownLoad?: boolean;
|
|
42
|
+
downloadClick?: (file: any) => void;
|
|
43
|
+
showDelete?: boolean;
|
|
44
|
+
deleteClick?: (url: string) => void;
|
|
45
|
+
windowWidth?: number;
|
|
46
|
+
getLocale: LocaleFunction;
|
|
47
|
+
language: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type fileItem = {
|
|
51
|
+
fileId?: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
filePath?: string;
|
|
54
|
+
fullFilePath?: string[];
|
|
55
|
+
[key: string]: any;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
pdfjs.GlobalWorkerOptions.workerSrc = pdfworker;
|
|
59
|
+
const prefix = 'lcdp-previewFile';
|
|
60
|
+
const PreviewFile: React.FC<PreviewFileProps> = (props) => {
|
|
61
|
+
const {
|
|
62
|
+
fileIdOrUrl,
|
|
63
|
+
// pageId,
|
|
64
|
+
file,
|
|
65
|
+
downloadClick,
|
|
66
|
+
showDownLoad,
|
|
67
|
+
showDelete,
|
|
68
|
+
deleteClick,
|
|
69
|
+
getLocale,
|
|
70
|
+
language,
|
|
71
|
+
} = props;
|
|
72
|
+
// const { appId } = props;
|
|
73
|
+
// const api = getApis({ appId, language, pageId });
|
|
74
|
+
const [fileDataMap, setFileDataMap] = useState<any>({});
|
|
75
|
+
const [loading, setLoading] = useState(false);
|
|
76
|
+
// 预览失败信息
|
|
77
|
+
const [resultInfo, setResultInfo] = useState<any>();
|
|
78
|
+
const [windowWidth, setWindowWidth] = useState<number>(
|
|
79
|
+
props?.windowWidth || window.innerWidth,
|
|
80
|
+
);
|
|
81
|
+
const tip = getLocale('notSupportPreview', '该文件不支持当前窗口预览');
|
|
82
|
+
const timeId = useRef<any>(null);
|
|
83
|
+
const [curPreviewFile, setCurPreviewFile] = useState<fileItem>();
|
|
84
|
+
// 当前预览文件信息
|
|
85
|
+
const { currentFileData, fileData } = useMemo(() => {
|
|
86
|
+
// 当前预览文件ID,ZIP预览时会切换当前预览的文件
|
|
87
|
+
const { fileId } = curPreviewFile || {};
|
|
88
|
+
let curData = fileId ? fileDataMap[fileId] : undefined;
|
|
89
|
+
if (curData?.previewMode === PREVIEW_MODE.ZIP && curData.zipChildFileId) {
|
|
90
|
+
curData = fileDataMap[curData.zipChildFileId] || curData;
|
|
91
|
+
}
|
|
92
|
+
// 当前打开文件的Id
|
|
93
|
+
const curFileId = fileIdOrUrl || file?.fileId;
|
|
94
|
+
return {
|
|
95
|
+
currentFileData: curData,
|
|
96
|
+
fileData: fileDataMap[curFileId],
|
|
97
|
+
};
|
|
98
|
+
}, [file, fileIdOrUrl, fileDataMap, curPreviewFile]);
|
|
99
|
+
|
|
100
|
+
// 是否支持放大缩小、旋转、切换页面
|
|
101
|
+
const pageSwitch = useMemo(
|
|
102
|
+
() => CAN_SCALE.includes(currentFileData?.previewMode),
|
|
103
|
+
[currentFileData?.previewMode],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const fileCacheMap = useCreation(() => fileDataMap, [fileDataMap]);
|
|
107
|
+
|
|
108
|
+
const {
|
|
109
|
+
pageNum,
|
|
110
|
+
setPageNum,
|
|
111
|
+
scale,
|
|
112
|
+
setScale,
|
|
113
|
+
rotation,
|
|
114
|
+
setRotation,
|
|
115
|
+
updateCurrentFileData,
|
|
116
|
+
} = useCreation(() => {
|
|
117
|
+
const updateData = (key: string, newVal: any | ((preVal: any) => any)) => {
|
|
118
|
+
const id = currentFileData?.fileId;
|
|
119
|
+
setFileDataMap((pre: any) => ({
|
|
120
|
+
...pre,
|
|
121
|
+
[id]: {
|
|
122
|
+
...(pre[id] || {}),
|
|
123
|
+
[key]: typeof newVal === 'function' ? newVal(pre[id]?.[key]) : newVal,
|
|
124
|
+
},
|
|
125
|
+
}));
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
// pdf/ppt/doc等文件会转成多张图片,切换文件页码
|
|
129
|
+
pageNum: currentFileData?.pageNum || 1,
|
|
130
|
+
setPageNum: (newVal: any) => updateData('pageNum', newVal || 1),
|
|
131
|
+
// 放大缩小比例
|
|
132
|
+
scale: currentFileData?.scale || 0.7,
|
|
133
|
+
setScale: (newVal: any) => updateData('scale', newVal || 0.7),
|
|
134
|
+
rotation: currentFileData?.rotation,
|
|
135
|
+
setRotation: (angle?: number) =>
|
|
136
|
+
updateData(
|
|
137
|
+
'rotation',
|
|
138
|
+
(rotation: any) => ((rotation || 0) + angle) % 360,
|
|
139
|
+
),
|
|
140
|
+
updateCurrentFileData: updateData,
|
|
141
|
+
};
|
|
142
|
+
}, [currentFileData]);
|
|
143
|
+
|
|
144
|
+
const throttle = (fn: any) => (v?: any) => {
|
|
145
|
+
if (!timeId?.current) {
|
|
146
|
+
timeId.current = setTimeout(() => {
|
|
147
|
+
fn(v);
|
|
148
|
+
clearTimeout(timeId.current);
|
|
149
|
+
timeId.current = null;
|
|
150
|
+
}, 500);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleOnResize = () => {
|
|
155
|
+
setWindowWidth(window.innerWidth);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const onResizeThrottle = useCallback(() => {
|
|
159
|
+
return throttle(handleOnResize)();
|
|
160
|
+
}, []);
|
|
161
|
+
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
const resize = () => {
|
|
164
|
+
onResizeThrottle();
|
|
165
|
+
};
|
|
166
|
+
window.addEventListener('resize', resize);
|
|
167
|
+
return () => {
|
|
168
|
+
window.removeEventListener('resize', resize);
|
|
169
|
+
if (timeId.current) {
|
|
170
|
+
clearTimeout(timeId.current);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}, []);
|
|
174
|
+
|
|
175
|
+
const getFilePreviewUrl = (id: string) =>
|
|
176
|
+
/^\d+$/.test(id) ? api.previewFileById(id) : id;
|
|
177
|
+
|
|
178
|
+
// 签名每次会增加一个时间戳,需要缓存url
|
|
179
|
+
const filePreviewUrl = useMemo(() => {
|
|
180
|
+
let url =
|
|
181
|
+
currentFileData?.serverFileUrl ||
|
|
182
|
+
currentFileData?.data?.dataUrl ||
|
|
183
|
+
currentFileData?.data?.url;
|
|
184
|
+
|
|
185
|
+
if (url) return url;
|
|
186
|
+
if (currentFileData?.serverFileId) {
|
|
187
|
+
url = getFilePreviewUrl(currentFileData?.serverFileId);
|
|
188
|
+
currentFileData.serverFileUrl = url;
|
|
189
|
+
} else {
|
|
190
|
+
url = getFilePreviewUrl(currentFileData?.fileId);
|
|
191
|
+
}
|
|
192
|
+
return url;
|
|
193
|
+
}, [currentFileData?.fileId]);
|
|
194
|
+
|
|
195
|
+
// 下载当前文件
|
|
196
|
+
const mydownloadClick = () => {
|
|
197
|
+
if (file) {
|
|
198
|
+
downloadClick && downloadClick(file);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const renderIMG = (src: string) => {
|
|
203
|
+
return <img width={windowWidth * 0.5 * scale} src={src} alt="" />;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// 根据下载接口获取文件,判断文件类型是否可以预览
|
|
207
|
+
const getFileData = (fileId: string): Promise<any> => {
|
|
208
|
+
const url = isUrlFormat(fileId) ? fileId : getFilePreviewUrl(fileId);
|
|
209
|
+
if (url) {
|
|
210
|
+
const xhr = new XMLHttpRequest(); // ActiveXObject只存在于IE7及以下,无需兼容
|
|
211
|
+
xhr.open('GET', url);
|
|
212
|
+
xhr.responseType = 'blob'; // 设置接受类型
|
|
213
|
+
|
|
214
|
+
const headers: any = {
|
|
215
|
+
// 'X-B-TARGET-ID': pageId,
|
|
216
|
+
'X-B-AUTH': '1',
|
|
217
|
+
// 'APP-ID': props?.appId,
|
|
218
|
+
};
|
|
219
|
+
Object.keys(headers).forEach((header) => {
|
|
220
|
+
xhr.setRequestHeader(header, headers[header]); // 设置请求头参数
|
|
221
|
+
});
|
|
222
|
+
xhr.setRequestHeader(
|
|
223
|
+
'X-SIGN',
|
|
224
|
+
security.httpEncryption.createHttpSignStr(url, {
|
|
225
|
+
method: 'GET',
|
|
226
|
+
headers,
|
|
227
|
+
body: '',
|
|
228
|
+
search: '',
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
xhr.withCredentials = true;
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
xhr.onload = () => {
|
|
234
|
+
const data = xhr.response; // 获取响应体数据
|
|
235
|
+
if (xhr.status === 200) {
|
|
236
|
+
const position = xhr.getResponseHeader('Content-Disposition');
|
|
237
|
+
const filename = position?.match(/filename\*?=[^;]*/)?.[0];
|
|
238
|
+
if (filename) {
|
|
239
|
+
data.name = filename;
|
|
240
|
+
}
|
|
241
|
+
data.url = url;
|
|
242
|
+
try {
|
|
243
|
+
const reader = new FileReader();
|
|
244
|
+
reader.addEventListener('load', () => {
|
|
245
|
+
data.dataUrl = reader.result;
|
|
246
|
+
resolve(data);
|
|
247
|
+
});
|
|
248
|
+
reader.readAsDataURL(data);
|
|
249
|
+
} catch (e) {
|
|
250
|
+
resolve(data);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
xhr.onerror = () => {
|
|
255
|
+
const previewUrl = new URL(url);
|
|
256
|
+
if (previewUrl.origin !== window.location.origin) {
|
|
257
|
+
// 非同源的根据url后缀判断
|
|
258
|
+
resolve({
|
|
259
|
+
name: url,
|
|
260
|
+
cors: true,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
setResultInfo(tip);
|
|
264
|
+
reject();
|
|
265
|
+
};
|
|
266
|
+
xhr.onloadend = () => {
|
|
267
|
+
if (xhr.status === 404) {
|
|
268
|
+
setResultInfo(getLocale('fileNotExist', '文件资源不存在'));
|
|
269
|
+
reject();
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
xhr.send();
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return Promise.resolve(null);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// 获取zip压缩文件目录
|
|
279
|
+
const getZipFileDir = async (fileItem: fileItem) => {
|
|
280
|
+
try {
|
|
281
|
+
const id = fileItem?.fileId;
|
|
282
|
+
if (!id) return undefined;
|
|
283
|
+
setLoading(true);
|
|
284
|
+
const zipDir = await api.getZipFileNode({ sourceFileId: id });
|
|
285
|
+
return {
|
|
286
|
+
...fileItem,
|
|
287
|
+
zipDir,
|
|
288
|
+
};
|
|
289
|
+
} catch (e) {
|
|
290
|
+
return undefined;
|
|
291
|
+
} finally {
|
|
292
|
+
setLoading(false);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// 校验是否为指定格式
|
|
297
|
+
// 部分格式后端不支持预览转换,由前端处理
|
|
298
|
+
const checkPreview = async (fileItem: fileItem) => {
|
|
299
|
+
let fileInfo: fileItem = fileItem;
|
|
300
|
+
// 切换文件时优先从缓存取,若无则重新加载
|
|
301
|
+
const fileData = fileCacheMap[fileInfo?.fileId!];
|
|
302
|
+
let fileBlob: File & {
|
|
303
|
+
cors: boolean;
|
|
304
|
+
name: string;
|
|
305
|
+
} = fileData?.data;
|
|
306
|
+
if (fileInfo?.fileId && !fileData) {
|
|
307
|
+
try {
|
|
308
|
+
fileBlob = await getFileData(fileInfo?.fileId);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error('预览文件时候错误error', error);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
let target = LOCAL_PREVIEW.find((val) => {
|
|
314
|
+
if (
|
|
315
|
+
val.suffix?.test(
|
|
316
|
+
fileInfo?.name || fileBlob?.name || fileInfo?.fileId || '',
|
|
317
|
+
) ||
|
|
318
|
+
val.mimeTypeReg?.test(fileBlob?.type || '')
|
|
319
|
+
) {
|
|
320
|
+
fileInfo.previewMode = val.previewMode;
|
|
321
|
+
if (fileBlob?.cors && !val.cors) {
|
|
322
|
+
// 预览跨域文件地址且无法通过平台定制方式预览的,通过iframe展示
|
|
323
|
+
fileInfo.previewMode = PREVIEW_MODE.IFRAME;
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
});
|
|
329
|
+
if (target?.previewMode === PREVIEW_MODE.TXT && fileBlob instanceof Blob) {
|
|
330
|
+
if (fileBlob?.text) {
|
|
331
|
+
// 兼容ie11
|
|
332
|
+
fileInfo.content = await fileBlob.text();
|
|
333
|
+
} else {
|
|
334
|
+
target = undefined;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (target?.previewMode === PREVIEW_MODE.ZIP && !fileData) {
|
|
338
|
+
// ZIP 预览需要特殊处理,先获取zip文件的目录结构,在分层进行预览
|
|
339
|
+
const zipInfo = await getZipFileDir(fileInfo);
|
|
340
|
+
if (!zipInfo) return undefined;
|
|
341
|
+
fileInfo = zipInfo;
|
|
342
|
+
}
|
|
343
|
+
if (target && fileInfo) {
|
|
344
|
+
fileInfo.data = fileBlob;
|
|
345
|
+
setFileDataMap((pre: any) => ({
|
|
346
|
+
...pre,
|
|
347
|
+
[fileInfo?.fileId!]: {
|
|
348
|
+
...(pre[fileInfo?.fileId!] || {}),
|
|
349
|
+
...fileInfo,
|
|
350
|
+
},
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
return target;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const getFileInfo = async (fileItem: fileItem) => {
|
|
357
|
+
setLoading(true);
|
|
358
|
+
try {
|
|
359
|
+
const target = await checkPreview({
|
|
360
|
+
fileId: fileItem.fileId,
|
|
361
|
+
name: fileItem?.name,
|
|
362
|
+
});
|
|
363
|
+
if (target) {
|
|
364
|
+
setLoading(false);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
await getFile(fileItem);
|
|
368
|
+
} finally {
|
|
369
|
+
setLoading(false);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const viewFile = async (fileItem: fileItem, viewSource?: string) => {
|
|
374
|
+
if (!fileItem) return undefined;
|
|
375
|
+
switch (viewSource) {
|
|
376
|
+
// 来源压缩包子文件预览处理
|
|
377
|
+
case PREVIEW_MODE.ZIP: {
|
|
378
|
+
const { zipSourceFileId, filePath } = fileItem || {};
|
|
379
|
+
// 预览zip 子文件
|
|
380
|
+
const fileInfo = await api.viewZipFile({
|
|
381
|
+
filePath,
|
|
382
|
+
sourceFileId: zipSourceFileId,
|
|
383
|
+
});
|
|
384
|
+
return fileInfo;
|
|
385
|
+
}
|
|
386
|
+
default: {
|
|
387
|
+
// 常规文件预览处理
|
|
388
|
+
const id = fileItem.fileId;
|
|
389
|
+
if (!id) return undefined;
|
|
390
|
+
let fileInfo = fileCacheMap[id];
|
|
391
|
+
const isUrl = isUrlFormat(id);
|
|
392
|
+
// 当传入的fileIdOrUrl是合法的网络地址时,则视为外部地址,所有不支持浏览器直接预览
|
|
393
|
+
if (!fileInfo && !isUrl) {
|
|
394
|
+
fileInfo = await api.viewFile({
|
|
395
|
+
fileId: id,
|
|
396
|
+
// appId,
|
|
397
|
+
// pageId
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
return fileInfo;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// 根据平台预览接口获取转换后的文件格式
|
|
406
|
+
const getFile = async (fileItem: fileItem, viewSource?: string) => {
|
|
407
|
+
setLoading(true);
|
|
408
|
+
let fileInfo: any = null;
|
|
409
|
+
try {
|
|
410
|
+
fileInfo = await viewFile(fileItem, viewSource);
|
|
411
|
+
if (fileInfo && fileInfo?.resultCode !== '-2') {
|
|
412
|
+
const id = fileItem?.fileId;
|
|
413
|
+
if (id) {
|
|
414
|
+
// 根据预览接口返回参数补充文件参数
|
|
415
|
+
fileInfo = parseFileInfo(fileItem, fileInfo);
|
|
416
|
+
setFileDataMap((pre: any) => ({
|
|
417
|
+
...pre,
|
|
418
|
+
[id]: {
|
|
419
|
+
// 切换文件的时候使用上一次的旋转
|
|
420
|
+
rotation: pre?.[fileInfo?.fileId]?.rotation,
|
|
421
|
+
...fileInfo,
|
|
422
|
+
},
|
|
423
|
+
}));
|
|
424
|
+
}
|
|
425
|
+
} else if (!fileInfo?.previewMode) {
|
|
426
|
+
setResultInfo(tip);
|
|
427
|
+
}
|
|
428
|
+
} catch (e: any) {
|
|
429
|
+
const { resultCode } = e;
|
|
430
|
+
if (resultCode === '-2') {
|
|
431
|
+
if (!fileInfo?.previewMode) {
|
|
432
|
+
setResultInfo(tip);
|
|
433
|
+
}
|
|
434
|
+
} else {
|
|
435
|
+
setResultInfo(e.resultMsg);
|
|
436
|
+
}
|
|
437
|
+
} finally {
|
|
438
|
+
setLoading(false);
|
|
439
|
+
}
|
|
440
|
+
return fileInfo;
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
const initFile = async (curFile: fileItem) => {
|
|
444
|
+
setCurPreviewFile(curFile);
|
|
445
|
+
if (curFile?.fileId) {
|
|
446
|
+
await getFileInfo(curFile);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
const curFile: fileItem = {
|
|
452
|
+
...(file || {}),
|
|
453
|
+
fileId: file?.fileId || fileIdOrUrl,
|
|
454
|
+
};
|
|
455
|
+
initFile(curFile);
|
|
456
|
+
}, [file, fileIdOrUrl]);
|
|
457
|
+
|
|
458
|
+
const renderPPT = () => {
|
|
459
|
+
return (
|
|
460
|
+
<div className="preview_content ppt">
|
|
461
|
+
{renderIMG(getFilePreviewUrl(currentFileData?.fileIdList[pageNum - 1]))}
|
|
462
|
+
</div>
|
|
463
|
+
);
|
|
464
|
+
};
|
|
465
|
+
const renderContent = () => (
|
|
466
|
+
<div className="preview_content txt">
|
|
467
|
+
<div className="code">{currentFileData?.content}</div>
|
|
468
|
+
</div>
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
const renderPDF = (fileUrl: string) => {
|
|
472
|
+
return (
|
|
473
|
+
<div className="pdf-container">
|
|
474
|
+
<Document
|
|
475
|
+
file={fileUrl}
|
|
476
|
+
loading={
|
|
477
|
+
<div className="pdf-loading">
|
|
478
|
+
<Spin size="large" />
|
|
479
|
+
</div>
|
|
480
|
+
}
|
|
481
|
+
options={{
|
|
482
|
+
cMapUrl: 'cmaps/',
|
|
483
|
+
cMapPacked: true,
|
|
484
|
+
}}
|
|
485
|
+
onLoadSuccess={onDocumentLoadSuccess}
|
|
486
|
+
>
|
|
487
|
+
<Page
|
|
488
|
+
pageNumber={pageNum}
|
|
489
|
+
width={windowWidth * 0.5}
|
|
490
|
+
scale={scale}
|
|
491
|
+
loading={
|
|
492
|
+
<div className="pdf-loading">
|
|
493
|
+
<Spin size="large" />
|
|
494
|
+
</div>
|
|
495
|
+
}
|
|
496
|
+
/>
|
|
497
|
+
</Document>
|
|
498
|
+
</div>
|
|
499
|
+
);
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
const render = () => {
|
|
503
|
+
switch (currentFileData?.previewMode) {
|
|
504
|
+
case PREVIEW_MODE.IMG:
|
|
505
|
+
return renderIMG(filePreviewUrl);
|
|
506
|
+
case PREVIEW_MODE.PDF:
|
|
507
|
+
return renderPDF(filePreviewUrl);
|
|
508
|
+
case PREVIEW_MODE.HTML:
|
|
509
|
+
// eslint-disable-next-line react/no-danger
|
|
510
|
+
return (
|
|
511
|
+
<div className="preview_content">
|
|
512
|
+
<iframe
|
|
513
|
+
ref={(r) => {
|
|
514
|
+
if (r?.contentDocument?.write) {
|
|
515
|
+
// r.contentDocument?.write(addFileUrlSign(currentFileData?.content));
|
|
516
|
+
// r.contentDocument?.close?.();
|
|
517
|
+
// contentDocument.write 会直接往内存里面写,如果数据量较大会导致浏览器内存溢出,用其他方法修改下
|
|
518
|
+
const content = addFileUrlSign(currentFileData?.content);
|
|
519
|
+
const blob = new Blob([content], { type: 'text/html' });
|
|
520
|
+
const url = URL.createObjectURL(blob);
|
|
521
|
+
r.src = url;
|
|
522
|
+
}
|
|
523
|
+
}}
|
|
524
|
+
title={getLocale('preview', '预览')}
|
|
525
|
+
style={{
|
|
526
|
+
backgroundColor: '#fff',
|
|
527
|
+
overflow: 'auto',
|
|
528
|
+
height: '80vh',
|
|
529
|
+
width: '50vw',
|
|
530
|
+
}}
|
|
531
|
+
/>
|
|
532
|
+
</div>
|
|
533
|
+
);
|
|
534
|
+
case PREVIEW_MODE.VIDEO:
|
|
535
|
+
return (
|
|
536
|
+
<div className="preview_content">
|
|
537
|
+
<video
|
|
538
|
+
src={getFilePreviewUrl(currentFileData?.fileId)}
|
|
539
|
+
loop
|
|
540
|
+
height="100%"
|
|
541
|
+
width={windowWidth * 0.8}
|
|
542
|
+
autoPlay={!loading}
|
|
543
|
+
muted
|
|
544
|
+
/>
|
|
545
|
+
</div>
|
|
546
|
+
);
|
|
547
|
+
case PREVIEW_MODE.PPT:
|
|
548
|
+
return renderPPT();
|
|
549
|
+
case PREVIEW_MODE.TXT:
|
|
550
|
+
return renderContent();
|
|
551
|
+
case PREVIEW_MODE.IFRAME:
|
|
552
|
+
return (
|
|
553
|
+
<div className="preview_content">
|
|
554
|
+
<iframe
|
|
555
|
+
src={getFilePreviewUrl(currentFileData?.fileId)}
|
|
556
|
+
key={currentFileData?.fileId}
|
|
557
|
+
title={currentFileData?.name}
|
|
558
|
+
className="iframe"
|
|
559
|
+
/>
|
|
560
|
+
</div>
|
|
561
|
+
);
|
|
562
|
+
default: {
|
|
563
|
+
let info = resultInfo;
|
|
564
|
+
let tips = '';
|
|
565
|
+
if (PREVIEW_MODE.ZIP === currentFileData?.previewMode) {
|
|
566
|
+
info = getLocale(
|
|
567
|
+
'zipPreviewTitle',
|
|
568
|
+
'当前预览内容为压缩包,不支持直接预览',
|
|
569
|
+
);
|
|
570
|
+
tips = getLocale(
|
|
571
|
+
'zipPreviewTips',
|
|
572
|
+
'请在下方选择压缩包内文件进行预览',
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
if (info) {
|
|
576
|
+
return (
|
|
577
|
+
<div className="error">
|
|
578
|
+
<div className="error-title">{info}</div>
|
|
579
|
+
{tips && <div className={`${prefix}-error-tips`}>{tips}</div>}
|
|
580
|
+
</div>
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
const onDocumentLoadSuccess = (params: any) => {
|
|
589
|
+
const { numPages } = params || {};
|
|
590
|
+
updateCurrentFileData('totalPage', numPages);
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// 预览zip包里面的文件
|
|
594
|
+
const handlePreviewZipFile = async (val: any[], selectOptions: any[]) => {
|
|
595
|
+
if (val) {
|
|
596
|
+
const filePath = [...val].pop();
|
|
597
|
+
// 防止多次点击同一个文件
|
|
598
|
+
if (filePath === currentFileData?.fullFilePath) return;
|
|
599
|
+
const zipSourceFileId = file?.id || fileIdOrUrl;
|
|
600
|
+
const fileItem: fileItem = {
|
|
601
|
+
filePath,
|
|
602
|
+
fullFilePath: val,
|
|
603
|
+
fullFilePathName: selectOptions.map((opt) => opt.fileName),
|
|
604
|
+
zipSourceFileId,
|
|
605
|
+
// zip包内的文件部分后端转换后,不一定能返回fileId,根据zip的fileId和filePath临时生成一个用来渲染
|
|
606
|
+
fileId: `${zipSourceFileId}_${filePath}`,
|
|
607
|
+
};
|
|
608
|
+
let fileInfo = fileItem;
|
|
609
|
+
try {
|
|
610
|
+
// 预览当前文件
|
|
611
|
+
fileInfo = await getFile(fileItem, PREVIEW_MODE.ZIP);
|
|
612
|
+
} catch (e) {
|
|
613
|
+
//
|
|
614
|
+
}
|
|
615
|
+
setFileDataMap((pre: any) => ({
|
|
616
|
+
...pre,
|
|
617
|
+
[zipSourceFileId]: {
|
|
618
|
+
...(pre[zipSourceFileId] || {}),
|
|
619
|
+
zipChildFileId: fileInfo?.fileId,
|
|
620
|
+
},
|
|
621
|
+
}));
|
|
622
|
+
setCurPreviewFile(fileInfo);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const renderDisBtn = () => {
|
|
627
|
+
return (
|
|
628
|
+
<div className="pdf-disbtn" onClick={(e) => e.stopPropagation()}>
|
|
629
|
+
{fileData?.previewMode === PREVIEW_MODE.ZIP && (
|
|
630
|
+
<Cascader
|
|
631
|
+
placement="topLeft"
|
|
632
|
+
onChange={handlePreviewZipFile}
|
|
633
|
+
fieldNames={{
|
|
634
|
+
label: 'fileName',
|
|
635
|
+
value: 'filePath',
|
|
636
|
+
children: 'children',
|
|
637
|
+
}}
|
|
638
|
+
value={currentFileData?.fullFilePath}
|
|
639
|
+
dropdownClassName={`${prefix}-dropdown`}
|
|
640
|
+
options={fileData?.zipDir ? [fileData.zipDir] : []}
|
|
641
|
+
>
|
|
642
|
+
<div
|
|
643
|
+
className={classnames(`${prefix}-zip-select`, `${prefix}-group`)}
|
|
644
|
+
>
|
|
645
|
+
<span className={`${prefix}-zip-select-label`}>
|
|
646
|
+
{currentFileData?.fileId !== fileData?.fileId &&
|
|
647
|
+
currentFileData?.fullFilePathName
|
|
648
|
+
? currentFileData?.fullFilePathName?.join('/')
|
|
649
|
+
: getLocale(
|
|
650
|
+
'zipPreviewPlaceholder',
|
|
651
|
+
'请选择包内文件进行预览',
|
|
652
|
+
)}
|
|
653
|
+
</span>
|
|
654
|
+
<DownOutlined rev="" />
|
|
655
|
+
</div>
|
|
656
|
+
</Cascader>
|
|
657
|
+
)}
|
|
658
|
+
{pageSwitch && (
|
|
659
|
+
<>
|
|
660
|
+
<div className={`${prefix}-group`}>
|
|
661
|
+
<div
|
|
662
|
+
className="pdf-bt"
|
|
663
|
+
onClick={() => {
|
|
664
|
+
if (pageNum > 1) setPageNum(pageNum - 1);
|
|
665
|
+
}}
|
|
666
|
+
>
|
|
667
|
+
<img src={pageIcon.leftIcon} alt="" />
|
|
668
|
+
</div>
|
|
669
|
+
<div className="pdf-bt-text">{`${pageNum}/${
|
|
670
|
+
currentFileData?.totalPage || 1
|
|
671
|
+
}`}</div>
|
|
672
|
+
<div
|
|
673
|
+
className="pdf-bt"
|
|
674
|
+
onClick={() => {
|
|
675
|
+
if (pageNum < (currentFileData?.totalPage || 1))
|
|
676
|
+
setPageNum(pageNum + 1);
|
|
677
|
+
}}
|
|
678
|
+
>
|
|
679
|
+
<img src={pageIcon.rightIcon} alt="" />
|
|
680
|
+
</div>
|
|
681
|
+
</div>
|
|
682
|
+
<div className={`${prefix}-group`}>
|
|
683
|
+
<div
|
|
684
|
+
className="pdf-bt"
|
|
685
|
+
onClick={() => {
|
|
686
|
+
if (scale <= 0.1) {
|
|
687
|
+
message.info(getLocale('scaleMin'));
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const newScale = (scale * 10 - 0.1 * 10) / 10;
|
|
691
|
+
setScale(newScale);
|
|
692
|
+
}}
|
|
693
|
+
>
|
|
694
|
+
<img src={pageIcon.zoomOutIcon} alt="" />
|
|
695
|
+
</div>
|
|
696
|
+
<div className="pdf-bt-text">{`${Math.round(scale * 100)}%`}</div>
|
|
697
|
+
<div
|
|
698
|
+
className="pdf-bt"
|
|
699
|
+
onClick={() => {
|
|
700
|
+
if (scale >= 2) {
|
|
701
|
+
message.info(getLocale('scaleMax'));
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
const newScale = (scale * 10 + 0.1 * 10) / 10;
|
|
705
|
+
setScale(newScale);
|
|
706
|
+
}}
|
|
707
|
+
>
|
|
708
|
+
<img src={pageIcon.zoomInIcon} alt="" />
|
|
709
|
+
</div>
|
|
710
|
+
</div>
|
|
711
|
+
<div className={`${prefix}-group`}>
|
|
712
|
+
<div
|
|
713
|
+
className="pdf-bt"
|
|
714
|
+
onClick={() => {
|
|
715
|
+
setRotation(-90);
|
|
716
|
+
}}
|
|
717
|
+
>
|
|
718
|
+
<RotateLeftOutlined rev="" />
|
|
719
|
+
</div>
|
|
720
|
+
<div
|
|
721
|
+
className="pdf-bt"
|
|
722
|
+
onClick={() => {
|
|
723
|
+
setRotation(90);
|
|
724
|
+
}}
|
|
725
|
+
>
|
|
726
|
+
<RotateRightOutlined rev="" />
|
|
727
|
+
</div>
|
|
728
|
+
</div>
|
|
729
|
+
</>
|
|
730
|
+
)}
|
|
731
|
+
{(showDownLoad || showDelete) && (
|
|
732
|
+
<div className={`${prefix}-group`}>
|
|
733
|
+
{showDownLoad && (
|
|
734
|
+
<div className="pdf-bt" onClick={mydownloadClick}>
|
|
735
|
+
<img src={pageIcon.downloadIcon} alt="" />
|
|
736
|
+
</div>
|
|
737
|
+
)}
|
|
738
|
+
{showDelete && (
|
|
739
|
+
<div
|
|
740
|
+
className="pdf-bt"
|
|
741
|
+
onClick={() => {
|
|
742
|
+
if (typeof deleteClick === 'function') {
|
|
743
|
+
deleteClick(file);
|
|
744
|
+
}
|
|
745
|
+
}}
|
|
746
|
+
>
|
|
747
|
+
<img src={pageIcon.deleteIcon} alt="" />
|
|
748
|
+
</div>
|
|
749
|
+
)}
|
|
750
|
+
</div>
|
|
751
|
+
)}
|
|
752
|
+
</div>
|
|
753
|
+
);
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
return (
|
|
757
|
+
<div
|
|
758
|
+
className={classnames(`${prefix}-wrap`, {
|
|
759
|
+
[`${prefix}-wrapPic`]:
|
|
760
|
+
currentFileData?.previewMode === PREVIEW_MODE.IMG || loading,
|
|
761
|
+
})}
|
|
762
|
+
>
|
|
763
|
+
<Spin size="large" spinning={loading} />
|
|
764
|
+
<div
|
|
765
|
+
className="content"
|
|
766
|
+
onClick={(e) => e.stopPropagation()}
|
|
767
|
+
style={
|
|
768
|
+
currentFileData?.previewMode
|
|
769
|
+
? {
|
|
770
|
+
transform: `rotate(${rotation || 0}deg)`,
|
|
771
|
+
}
|
|
772
|
+
: undefined
|
|
773
|
+
}
|
|
774
|
+
>
|
|
775
|
+
{!loading && render()}
|
|
776
|
+
</div>
|
|
777
|
+
{renderDisBtn()}
|
|
778
|
+
</div>
|
|
779
|
+
);
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
PreviewFile.defaultProps = {
|
|
783
|
+
// eslint-disable-next-line react/default-props-match-prop-types
|
|
784
|
+
getLocale: (_l, t) => t ?? '',
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
export default PreviewFile;
|