@gientech/modual 1.2.8 → 1.2.9-fix
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 +593 -79
- package/USAGE.md +56 -0
- package/dist/README.md +593 -79
- package/dist/assets/GientechStreamReader-C21-q_Qv.js +449 -0
- package/dist/assets/chevron-down-DjLtKwcs.js +280 -0
- package/dist/assets/databse.svg +6 -0
- package/dist/assets/graph.svg +4 -0
- package/dist/assets/homeBg.png +0 -0
- package/dist/assets/index-BMz4lcjQ.js +1 -0
- package/dist/assets/index-C3Viu8Oj.js +1 -0
- package/dist/assets/index-C9GlPyHu.js +13 -0
- package/dist/assets/index-CRbX3ZA1.js +1 -0
- package/dist/assets/index-CTwzi_v2.js +21 -0
- package/dist/assets/index-DQlLDleQ.js +11 -0
- package/dist/assets/index-DRU1P9R0.js +1150 -0
- package/dist/assets/index-Dqej68NT.js +585 -0
- package/dist/assets/index-ECprhahs.js +157 -0
- package/dist/assets/index-i7qcZOwY.js +1088 -0
- package/dist/assets/knowledge.svg +4 -0
- package/dist/assets/left.jpg +0 -0
- package/dist/assets/logoImg.png +0 -0
- package/dist/assets/{plus-omCUN0e3.js → plus-CvJRSbOe.js} +1 -1
- package/dist/assets/sensitive.svg +5 -0
- package/dist/assets/style.css +1 -1
- package/dist/assets/style3.css +1 -1
- package/dist/assets/worker-BbpylX7l.js +13 -0
- package/dist/assets/{x-vPcWt3fC.js → x-DKPeLdlu.js} +1 -1
- package/dist/assistantConfig.d.ts +31 -0
- package/dist/assistantConfig.js +1 -0
- package/dist/chat.d.ts +25 -1
- package/dist/chat.js +563 -369
- package/dist/database.js +2 -2
- package/dist/databaseId.js +1 -11
- package/dist/databaseTable.js +2 -2
- package/dist/index.d.ts +85 -0
- package/dist/index.js +1 -0
- package/dist/modelManage.js +1 -1
- package/dist/package.json +13 -1
- package/dist/sensitive.js +1 -1
- package/dist/streamFilesReader.d.ts +3 -0
- package/dist/streamFilesReader.js +1 -442
- package/doc_assets//346/226/271/346/241/210//344/274/230/345/214/226/346/226/271/346/241/210-/345/244/232/344/274/232/350/257/235SSE/350/277/236/346/216/245/347/256/241/347/220/206.md +504 -0
- package/package.json +125 -99
- package/package.json.demo-backup +109 -0
- package/scripts/README.md +133 -133
- package/scripts/build-demo.js +88 -88
- package/scripts/demo-selector.js +216 -216
- package/scripts/preview-demo.js +130 -130
- package/scripts/run-demo.bat +34 -34
- package/src/assets/img/close.png +0 -0
- package/src/assets/img/database.png +0 -0
- package/src/assets/img/downLoad.png +0 -0
- package/src/assets/img/graphIcon.png +0 -0
- package/src/assets/img/pdf.png +0 -0
- package/src/assets/img/singleQa.png +0 -0
- package/src/assets/img/webSearch.png +0 -0
- package/src/examples/ConversationAssistantPage/index.tsx +37 -0
- package/src/examples/Demo/index.tsx +12 -0
- package/src/examples/chat/components/DrawerGraphPreview.tsx +78 -0
- package/src/examples/chat/index.tsx +112 -99
- package/src/examples/chat/logo03.png +0 -0
- package/src/examples/gientechStreamFilesReader/index.tsx +4 -69
- package/src/lib_enter.ts +11 -6
- package/src/modules/assistantConfig/assets/databse.svg +6 -0
- package/src/modules/assistantConfig/assets/empty.png +0 -0
- package/src/modules/assistantConfig/assets/graph.svg +4 -0
- package/src/modules/assistantConfig/assets/knowledge.svg +4 -0
- package/src/modules/assistantConfig/assets/sensitive.svg +5 -0
- package/src/modules/assistantConfig/components/Database.tsx +144 -0
- package/src/modules/assistantConfig/components/Graph.tsx +156 -0
- package/src/modules/assistantConfig/components/Knowledge.tsx +266 -0
- package/src/modules/assistantConfig/components/NotFoundContent.tsx +21 -0
- package/src/modules/assistantConfig/components/Paragraph.tsx +51 -0
- package/src/modules/assistantConfig/components/ParamsItem.tsx +39 -0
- package/src/modules/assistantConfig/components/ResourceBinderItem.tsx +132 -0
- package/src/modules/assistantConfig/components/SearchableSelector.tsx +500 -0
- package/src/modules/assistantConfig/components/Sensitive.tsx +179 -0
- package/src/modules/assistantConfig/components/SliderInput.tsx +65 -0
- package/src/modules/assistantConfig/constants.tsx +74 -0
- package/src/modules/assistantConfig/index.tsx +700 -0
- package/src/modules/assistantConfig/server.ts +262 -0
- package/src/modules/chat/Conversations/List.tsx +76 -9
- package/src/modules/chat/Conversations/index.tsx +37 -19
- package/src/modules/chat/ReferenceBar.tsx +592 -0
- package/src/modules/chat/constants.tsx +29 -6
- package/src/modules/chat/data.txt +82 -0
- package/src/modules/chat/index.tsx +357 -113
- package/src/modules/chat/referenceCom/DeleteModal.tsx +75 -0
- package/src/modules/chat/referenceCom/DrawerContent.tsx +136 -0
- package/src/modules/chat/referenceCom/DrawerDatabase.tsx +110 -0
- package/src/modules/chat/referenceCom/DrawerGraphPreview.tsx +86 -0
- package/src/modules/chat/referenceCom/DrawerPreview.tsx +73 -0
- package/src/modules/chat/referenceCom/DrawerTitle.tsx +26 -0
- package/src/modules/chat/referenceCom/RenameModal.tsx +86 -0
- package/src/modules/chat/referenceCom/TagCom.tsx +30 -0
- package/src/modules/chat/style.less +3 -0
- package/src/modules/chat/utils/index.ts +326 -0
- package/src/modules/database/CreateModal.tsx +1 -1
- package/src/modules/headlessChat/index.tsx +1 -3
- package/src/modules/nodegraph/index.tsx +1 -0
- package/src/modules/search/components/ResultContent.tsx +2 -2
- package/src/modules/streamFilesReader/GientechStreamReader.tsx +436 -367
- package/src/modules/streamFilesReader/index.tsx +1 -1
- package/src/utils/gientechCommon/components/AppLoading.tsx +10 -10
- package/src/utils/gientechCommon/components/Messages/GientechNewChatWelcome.tsx +312 -27
- package/src/utils/gientechCommon/hooks/AichatUseController.tsx +84 -6
- package/src/utils/testconfigs/index.ts +7 -1
- package/stats.html +1 -1
- package/vite.config.ts +69 -20
- package/dist/assets/_commonjsHelpers-gnU0ypJ3.js +0 -1
- package/dist/assets/circle-alert-g2Y6zAjt.js +0 -6
- package/dist/assets/index-97TKgPKE.js +0 -1284
- package/dist/assets/index-CEK88UzR.js +0 -26
- package/dist/assets/index-DIm7RgkM.js +0 -1709
- package/dist/assets/styled-components.browser.esm-DPkS13KC.js +0 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import axios from 'axios';
|
|
4
|
-
import {Fviewer,parseFile} from '@mxmweb/fviewer';
|
|
4
|
+
import { Fviewer, parseFile, registerPDFWorker } from '@mxmweb/fviewer';
|
|
5
5
|
import type { ParseResult } from '@mxmweb/fviewer';
|
|
6
6
|
import Header from './components/Header';
|
|
7
|
-
|
|
8
|
-
import type { Annotation,
|
|
7
|
+
export { registerPDFWorker };
|
|
8
|
+
import type { Annotation, ToolsConfig } from '@mxmweb/fviewer';
|
|
9
9
|
|
|
10
10
|
import { Styles } from '@mxmweb/zui';
|
|
11
11
|
// Stream接口参数类型
|
|
@@ -104,8 +104,12 @@ const ReaderContainer = styled.div<{ $theme: Styles }>`
|
|
|
104
104
|
|
|
105
105
|
/* 添加动画样式 */
|
|
106
106
|
@keyframes spin {
|
|
107
|
-
0% {
|
|
108
|
-
|
|
107
|
+
0% {
|
|
108
|
+
transform: rotate(0deg);
|
|
109
|
+
}
|
|
110
|
+
100% {
|
|
111
|
+
transform: rotate(360deg);
|
|
112
|
+
}
|
|
109
113
|
}
|
|
110
114
|
`;
|
|
111
115
|
|
|
@@ -118,85 +122,101 @@ const DefaultLoadingComponent: React.FC<{
|
|
|
118
122
|
theme: Styles;
|
|
119
123
|
}> = ({ status, theme }) => {
|
|
120
124
|
return (
|
|
121
|
-
<div
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
<div
|
|
126
|
+
style={{
|
|
127
|
+
display: 'flex',
|
|
128
|
+
flexDirection: 'column',
|
|
129
|
+
alignItems: 'center',
|
|
130
|
+
justifyContent: 'center',
|
|
131
|
+
height: '100%',
|
|
132
|
+
padding: '40px',
|
|
133
|
+
background: theme.colors.background,
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
130
136
|
{/* 文件图标动画 */}
|
|
131
|
-
<div
|
|
132
|
-
|
|
133
|
-
width: '80px',
|
|
134
|
-
height: '80px',
|
|
135
|
-
marginBottom: '24px'
|
|
136
|
-
}}>
|
|
137
|
-
{/* 文件图标背景 */}
|
|
138
|
-
<div style={{
|
|
139
|
-
width: '60px',
|
|
140
|
-
height: '80px',
|
|
141
|
-
background: theme.colors.primary,
|
|
142
|
-
borderRadius: '8px 8px 0 0',
|
|
137
|
+
<div
|
|
138
|
+
style={{
|
|
143
139
|
position: 'relative',
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
width: '80px',
|
|
141
|
+
height: '80px',
|
|
142
|
+
marginBottom: '24px',
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
{/* 文件图标背景 */}
|
|
146
|
+
<div
|
|
147
|
+
style={{
|
|
148
|
+
width: '60px',
|
|
149
|
+
height: '80px',
|
|
150
|
+
background: theme.colors.primary,
|
|
151
|
+
borderRadius: '8px 8px 0 0',
|
|
152
|
+
position: 'relative',
|
|
153
|
+
margin: '0 auto',
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
146
156
|
{/* 文件折角 */}
|
|
147
|
-
<div
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
<div
|
|
158
|
+
style={{
|
|
159
|
+
position: 'absolute',
|
|
160
|
+
top: '0',
|
|
161
|
+
right: '0',
|
|
162
|
+
width: '0',
|
|
163
|
+
height: '0',
|
|
164
|
+
borderStyle: 'solid',
|
|
165
|
+
borderWidth: '0 20px 20px 0',
|
|
166
|
+
borderColor: `transparent ${theme.colors.background} transparent transparent`,
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
157
169
|
</div>
|
|
158
170
|
|
|
159
171
|
{/* 加载动画圆点 */}
|
|
160
|
-
<div
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
<div
|
|
173
|
+
style={{
|
|
174
|
+
position: 'absolute',
|
|
175
|
+
top: '50%',
|
|
176
|
+
left: '50%',
|
|
177
|
+
transform: 'translate(-50%, -50%)',
|
|
178
|
+
width: '20px',
|
|
179
|
+
height: '20px',
|
|
180
|
+
borderRadius: '50%',
|
|
181
|
+
background: theme.colors.background,
|
|
182
|
+
animation: 'pulse 1.5s ease-in-out infinite',
|
|
183
|
+
}}
|
|
184
|
+
/>
|
|
171
185
|
</div>
|
|
172
186
|
|
|
173
187
|
{/* 状态文本 */}
|
|
174
|
-
<div
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
<div
|
|
189
|
+
style={{
|
|
190
|
+
fontSize: '16px',
|
|
191
|
+
fontWeight: '500',
|
|
192
|
+
color: theme.colors.text,
|
|
193
|
+
marginBottom: '8px',
|
|
194
|
+
textAlign: 'center',
|
|
195
|
+
}}
|
|
196
|
+
>
|
|
181
197
|
{status}
|
|
182
198
|
</div>
|
|
183
199
|
|
|
184
200
|
{/* 进度指示器 */}
|
|
185
|
-
<div
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
overflow: 'hidden',
|
|
191
|
-
position: 'relative'
|
|
192
|
-
}}>
|
|
193
|
-
<div style={{
|
|
194
|
-
width: '30%',
|
|
195
|
-
height: '100%',
|
|
196
|
-
background: theme.colors.primary,
|
|
201
|
+
<div
|
|
202
|
+
style={{
|
|
203
|
+
width: '200px',
|
|
204
|
+
height: '4px',
|
|
205
|
+
background: theme.colors.border,
|
|
197
206
|
borderRadius: '2px',
|
|
198
|
-
|
|
199
|
-
|
|
207
|
+
overflow: 'hidden',
|
|
208
|
+
position: 'relative',
|
|
209
|
+
}}
|
|
210
|
+
>
|
|
211
|
+
<div
|
|
212
|
+
style={{
|
|
213
|
+
width: '30%',
|
|
214
|
+
height: '100%',
|
|
215
|
+
background: theme.colors.primary,
|
|
216
|
+
borderRadius: '2px',
|
|
217
|
+
animation: 'loading-progress 2s ease-in-out infinite',
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
200
220
|
</div>
|
|
201
221
|
|
|
202
222
|
{/* 动画样式 */}
|
|
@@ -245,8 +265,6 @@ const ErrorContainer = styled.div<{ $theme: Styles }>`
|
|
|
245
265
|
const DEFAULT_STREAM_API_URL = 'http://10.15.12.13:9005/proxy/index/knowledgeBase/file/stream';
|
|
246
266
|
const CACHE_EXPIRY_TIME = 5 * 60 * 1000; // 5分钟缓存过期
|
|
247
267
|
|
|
248
|
-
|
|
249
|
-
|
|
250
268
|
// 默认主题
|
|
251
269
|
const defaultTheme: Styles = {
|
|
252
270
|
colors: {
|
|
@@ -322,7 +340,7 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
322
340
|
|
|
323
341
|
// 通用文件缓存状态
|
|
324
342
|
const [genericContentCache, setGenericContentCache] = useState<{
|
|
325
|
-
[key: string]: { content: any; timestamp: number }
|
|
343
|
+
[key: string]: { content: any; timestamp: number };
|
|
326
344
|
}>({});
|
|
327
345
|
|
|
328
346
|
// 防抖状态 - 防止重复请求
|
|
@@ -380,31 +398,31 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
380
398
|
case 'pdf_slides':
|
|
381
399
|
defaultTools = {
|
|
382
400
|
...baseTools,
|
|
383
|
-
annotation: false,
|
|
384
|
-
download: false,
|
|
385
|
-
navigation: true,
|
|
386
|
-
rotate: false,
|
|
401
|
+
annotation: false, // PDF模式关闭标注功能
|
|
402
|
+
download: false, // PDF模式关闭下载功能
|
|
403
|
+
navigation: true, // PDF模式开启翻页导航
|
|
404
|
+
rotate: false, // PDF模式关闭旋转功能
|
|
387
405
|
};
|
|
388
406
|
break;
|
|
389
407
|
case 'image':
|
|
390
408
|
defaultTools = {
|
|
391
409
|
...baseTools,
|
|
392
|
-
annotation: false,
|
|
393
|
-
download: false,
|
|
394
|
-
navigation: false,
|
|
395
|
-
rotate: true,
|
|
396
|
-
zoom:true,
|
|
410
|
+
annotation: false, // 图片模式关闭标注功能
|
|
411
|
+
download: false, // 图片模式关闭下载功能
|
|
412
|
+
navigation: false, // 图片模式关闭翻页导航
|
|
413
|
+
rotate: true, // 图片模式开启旋转功能
|
|
414
|
+
zoom: true,
|
|
397
415
|
};
|
|
398
416
|
break;
|
|
399
417
|
case 'markdown':
|
|
400
418
|
case 'markdown_table':
|
|
401
419
|
defaultTools = {
|
|
402
420
|
...baseTools,
|
|
403
|
-
annotation: false,
|
|
404
|
-
download: false,
|
|
405
|
-
navigation: false,
|
|
406
|
-
rotate: false,
|
|
407
|
-
zoom: false,
|
|
421
|
+
annotation: false, // Markdown模式开启标注功能
|
|
422
|
+
download: false, // Markdown模式关闭下载功能
|
|
423
|
+
navigation: false, // Markdown模式关闭翻页导航
|
|
424
|
+
rotate: false, // Markdown模式关闭旋转功能
|
|
425
|
+
zoom: false, // Markdown模式关闭缩放功能
|
|
408
426
|
};
|
|
409
427
|
break;
|
|
410
428
|
case 'text':
|
|
@@ -412,11 +430,11 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
412
430
|
case 'unknown':
|
|
413
431
|
defaultTools = {
|
|
414
432
|
...baseTools,
|
|
415
|
-
annotation: false,
|
|
416
|
-
download: false,
|
|
417
|
-
navigation: false,
|
|
418
|
-
rotate: false,
|
|
419
|
-
zoom: false,
|
|
433
|
+
annotation: false, // 其他模式关闭标注功能
|
|
434
|
+
download: false, // 其他模式关闭下载功能
|
|
435
|
+
navigation: false, // 其他模式关闭翻页导航
|
|
436
|
+
rotate: false, // 其他模式关闭旋转功能
|
|
437
|
+
zoom: false, // 其他模式关闭缩放功能
|
|
420
438
|
};
|
|
421
439
|
break;
|
|
422
440
|
default:
|
|
@@ -448,257 +466,296 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
448
466
|
return `${chunkStart}-${chunkStart + pageSize - 1}`;
|
|
449
467
|
}, []);
|
|
450
468
|
|
|
451
|
-
|
|
469
|
+
/**
|
|
452
470
|
* 检查页面是否在缓存中,并返回解析后的PDF文档
|
|
453
471
|
* @param pageNo 页码
|
|
454
472
|
* @returns 缓存的PDF文档或null
|
|
455
473
|
*/
|
|
456
|
-
const getCachedPage = useCallback(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (!isPDF) {
|
|
461
|
-
console.log(`文件类型 ${fileType} 不是PDF,跳过缓存检查`);
|
|
462
|
-
return null;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
console.log(`检查页面 ${pageNo} 是否在缓存中`);
|
|
474
|
+
const getCachedPage = useCallback(
|
|
475
|
+
async (pageNo: number): Promise<any | null> => {
|
|
476
|
+
// 根据文件类型决定处理方式
|
|
477
|
+
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
466
478
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
console.log(`使用单个页面缓存: ${pageNo}`);
|
|
471
|
-
if (pageCached.pdfDocument) {
|
|
472
|
-
console.log(`直接返回缓存的PDF文档: ${pageNo}`);
|
|
473
|
-
return pageCached.pdfDocument;
|
|
479
|
+
if (!isPDF) {
|
|
480
|
+
console.log(`文件类型 ${fileType} 不是PDF,跳过缓存检查`);
|
|
481
|
+
return null;
|
|
474
482
|
}
|
|
475
|
-
// 如果没有缓存的PDF文档,需要重新解析
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
478
483
|
|
|
479
|
-
|
|
480
|
-
const chunkKey = getChunkKey(pageNo, pageSize);
|
|
481
|
-
const chunkCached = chunkCache.current[chunkKey];
|
|
482
|
-
console.log(`检查chunk缓存: ${chunkKey}, 存在: ${!!chunkCached}, 包含页面: ${chunkCached?.pages?.join(', ') || '无'}`);
|
|
484
|
+
console.log(`检查页面 ${pageNo} 是否在缓存中`);
|
|
483
485
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (
|
|
487
|
-
console.log(
|
|
488
|
-
if (
|
|
486
|
+
// 先检查单个页面缓存
|
|
487
|
+
const pageCached = pageCache.current[pageNo];
|
|
488
|
+
if (pageCached && Date.now() - pageCached.timestamp < CACHE_EXPIRY_TIME) {
|
|
489
|
+
console.log(`使用单个页面缓存: ${pageNo}`);
|
|
490
|
+
if (pageCached.pdfDocument) {
|
|
489
491
|
console.log(`直接返回缓存的PDF文档: ${pageNo}`);
|
|
490
|
-
return
|
|
492
|
+
return pageCached.pdfDocument;
|
|
491
493
|
}
|
|
492
494
|
// 如果没有缓存的PDF文档,需要重新解析
|
|
493
495
|
return null;
|
|
494
|
-
} else {
|
|
495
|
-
console.log(`页面 ${pageNo} 不在chunk ${chunkKey} 中,chunk包含: ${chunkCached.pages.join(', ')}`);
|
|
496
496
|
}
|
|
497
|
-
}
|
|
498
497
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
498
|
+
// 检查chunk缓存
|
|
499
|
+
const chunkKey = getChunkKey(pageNo, pageSize);
|
|
500
|
+
const chunkCached = chunkCache.current[chunkKey];
|
|
501
|
+
console.log(
|
|
502
|
+
`检查chunk缓存: ${chunkKey}, 存在: ${!!chunkCached}, 包含页面: ${chunkCached?.pages?.join(', ') || '无'}`
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
if (chunkCached && Date.now() - chunkCached.timestamp < CACHE_EXPIRY_TIME) {
|
|
506
|
+
// 验证页面是否真的在这个chunk中
|
|
507
|
+
if (chunkCached.pages.includes(pageNo)) {
|
|
508
|
+
console.log(`使用chunk缓存: ${pageNo} (chunk: ${chunkKey})`);
|
|
509
|
+
if (chunkCached.pdfDocument) {
|
|
510
|
+
console.log(`直接返回缓存的PDF文档: ${pageNo}`);
|
|
511
|
+
return chunkCached.pdfDocument;
|
|
512
|
+
}
|
|
513
|
+
// 如果没有缓存的PDF文档,需要重新解析
|
|
514
|
+
return null;
|
|
515
|
+
} else {
|
|
516
|
+
console.log(
|
|
517
|
+
`页面 ${pageNo} 不在chunk ${chunkKey} 中,chunk包含: ${chunkCached.pages.join(', ')}`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
console.log(`页面 ${pageNo} 不在任何缓存中,需要重新请求`);
|
|
523
|
+
return null;
|
|
524
|
+
},
|
|
525
|
+
[pageSize, getChunkKey, fileType]
|
|
526
|
+
);
|
|
502
527
|
|
|
503
528
|
/**
|
|
504
529
|
* 获取stream数据(仅用于PDF文件)
|
|
505
530
|
* @param pageNo 页码
|
|
506
531
|
* @returns Promise<ArrayBuffer>
|
|
507
532
|
*/
|
|
508
|
-
const fetchStreamData = useCallback(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
533
|
+
const fetchStreamData = useCallback(
|
|
534
|
+
async (pageNo: number): Promise<ArrayBuffer> => {
|
|
535
|
+
try {
|
|
536
|
+
// 根据文件类型决定是否传递分页参数
|
|
537
|
+
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
512
538
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
539
|
+
if (!isPDF) {
|
|
540
|
+
console.log(`文件类型 ${fileType} 不需要分页参数,获取完整内容`);
|
|
541
|
+
throw new Error(`文件类型 ${fileType} 不支持分页加载`);
|
|
542
|
+
}
|
|
517
543
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
544
|
+
// 计算需要请求的chunk
|
|
545
|
+
const chunkStart = Math.floor((pageNo - 1) / pageSize) * pageSize + 1;
|
|
546
|
+
const chunkKey = getChunkKey(pageNo, pageSize);
|
|
521
547
|
|
|
522
|
-
|
|
548
|
+
console.log(
|
|
549
|
+
`请求PDF chunk数据: ${chunkStart} (包含页面 ${chunkStart}-${chunkStart + pageSize - 1})`
|
|
550
|
+
);
|
|
523
551
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
552
|
+
const headers: Record<string, string> = {
|
|
553
|
+
'Content-Type': 'application/json',
|
|
554
|
+
};
|
|
527
555
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
556
|
+
if (authorization) {
|
|
557
|
+
headers['Authorization'] = authorization;
|
|
558
|
+
}
|
|
531
559
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
560
|
+
if (csrfToken) {
|
|
561
|
+
headers['X-CSRF-TOKEN-IN'] = csrfToken;
|
|
562
|
+
}
|
|
535
563
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
564
|
+
// PDF文件类型传递分页参数
|
|
565
|
+
const requestData = {
|
|
566
|
+
convertedFilePath,
|
|
567
|
+
pageNo: chunkStart, // 使用chunk的起始页
|
|
568
|
+
pageSize,
|
|
569
|
+
};
|
|
542
570
|
|
|
543
|
-
|
|
544
|
-
streamApiUrl,
|
|
545
|
-
requestData,
|
|
546
|
-
{
|
|
571
|
+
const response = await axios.post<ArrayBuffer>(streamApiUrl, requestData, {
|
|
547
572
|
headers,
|
|
548
573
|
responseType: 'arraybuffer',
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
// 获取响应头中的CSRF Token并触发事件
|
|
577
|
+
const responseCsrfToken =
|
|
578
|
+
response.headers['x-csrf-token-out'] || response.headers['X-CSRF-TOKEN-OUT'];
|
|
579
|
+
if (responseCsrfToken) {
|
|
580
|
+
console.log('获取到响应头中的CSRF Token:', responseCsrfToken);
|
|
581
|
+
eventsEmit('request_finish', responseCsrfToken);
|
|
549
582
|
}
|
|
550
|
-
);
|
|
551
583
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const chunkPages = Array.from({ length: pageSize }, (_, i) => chunkStart + i);
|
|
561
|
-
chunkCache.current[chunkKey] = {
|
|
562
|
-
data: response.data,
|
|
563
|
-
pages: chunkPages,
|
|
564
|
-
timestamp: Date.now(),
|
|
565
|
-
totalPages: userTotalPages, // 始终使用用户传入的总页数,不覆盖
|
|
566
|
-
};
|
|
584
|
+
// 缓存chunk数据
|
|
585
|
+
const chunkPages = Array.from({ length: pageSize }, (_, i) => chunkStart + i);
|
|
586
|
+
chunkCache.current[chunkKey] = {
|
|
587
|
+
data: response.data,
|
|
588
|
+
pages: chunkPages,
|
|
589
|
+
timestamp: Date.now(),
|
|
590
|
+
totalPages: userTotalPages, // 始终使用用户传入的总页数,不覆盖
|
|
591
|
+
};
|
|
567
592
|
|
|
568
|
-
|
|
569
|
-
|
|
593
|
+
console.log(
|
|
594
|
+
`缓存PDF chunk数据: ${chunkKey}, 包含页面: ${chunkPages.join(', ')}, 请求的页面: ${pageNo}`
|
|
595
|
+
);
|
|
596
|
+
console.log(`当前所有缓存:`, Object.keys(chunkCache.current));
|
|
570
597
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
598
|
+
return response.data;
|
|
599
|
+
} catch (error: any) {
|
|
600
|
+
console.error('获取PDF stream数据失败:', error);
|
|
601
|
+
throw new Error(`PDF请求失败: ${error.response?.status || '网络错误'}`);
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
[
|
|
605
|
+
streamApiUrl,
|
|
606
|
+
convertedFilePath,
|
|
607
|
+
pageSize,
|
|
608
|
+
authorization,
|
|
609
|
+
getChunkKey,
|
|
610
|
+
userTotalPages,
|
|
611
|
+
totalPages,
|
|
612
|
+
fileType,
|
|
613
|
+
eventsEmit,
|
|
614
|
+
]
|
|
615
|
+
);
|
|
577
616
|
|
|
578
617
|
/**
|
|
579
618
|
* 加载PDF文档(仅用于PDF文件类型)
|
|
580
619
|
* @param pageNo 页码
|
|
581
620
|
* @param isInitialLoad 是否为初始加载
|
|
582
621
|
*/
|
|
583
|
-
const loadPDFDocument = useCallback(
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
// 根据文件类型决定处理方式
|
|
587
|
-
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
622
|
+
const loadPDFDocument = useCallback(
|
|
623
|
+
async (pageNo: number, isInitialLoad: boolean = false) => {
|
|
624
|
+
if (!pageNo) return;
|
|
588
625
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
return null; // 直接返回,不进行任何操作
|
|
592
|
-
}
|
|
626
|
+
// 根据文件类型决定处理方式
|
|
627
|
+
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
593
628
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
setLoadingStatus('正在加载PDF文档...');
|
|
598
|
-
} else {
|
|
599
|
-
setIsLoading(true);
|
|
600
|
-
setLoadingStatus(`正在加载第 ${pageNo} 页...`);
|
|
629
|
+
if (!isPDF) {
|
|
630
|
+
console.log(`文件类型 ${fileType} 不是PDF,跳过PDF加载逻辑`);
|
|
631
|
+
return null; // 直接返回,不进行任何操作
|
|
601
632
|
}
|
|
602
|
-
setError(null);
|
|
603
633
|
|
|
604
|
-
|
|
634
|
+
try {
|
|
635
|
+
if (isInitialLoad) {
|
|
636
|
+
setIsLoading(true);
|
|
637
|
+
setLoadingStatus('正在加载PDF文档...');
|
|
638
|
+
} else {
|
|
639
|
+
setIsLoading(true);
|
|
640
|
+
setLoadingStatus(`正在加载第 ${pageNo} 页...`);
|
|
641
|
+
}
|
|
642
|
+
setError(null);
|
|
643
|
+
|
|
644
|
+
console.log(`开始加载PDF页面: ${pageNo}, 初始加载: ${isInitialLoad}`);
|
|
645
|
+
|
|
646
|
+
// 先检查缓存
|
|
647
|
+
const cachedPdf = await getCachedPage(pageNo);
|
|
648
|
+
if (cachedPdf) {
|
|
649
|
+
// 如果缓存中有PDF文档,直接使用,无需重新解析
|
|
650
|
+
console.log(`使用缓存的PDF文档: ${pageNo}`);
|
|
651
|
+
setPdfDocument(cachedPdf);
|
|
652
|
+
setIsLoading(false);
|
|
653
|
+
setLoadingStatus('');
|
|
654
|
+
console.log(`页面 ${pageNo} 加载完成(使用缓存)`);
|
|
655
|
+
return cachedPdf;
|
|
656
|
+
}
|
|
605
657
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (cachedPdf) {
|
|
609
|
-
// 如果缓存中有PDF文档,直接使用,无需重新解析
|
|
610
|
-
console.log(`使用缓存的PDF文档: ${pageNo}`);
|
|
611
|
-
setPdfDocument(cachedPdf);
|
|
612
|
-
setIsLoading(false);
|
|
613
|
-
setLoadingStatus('');
|
|
614
|
-
console.log(`页面 ${pageNo} 加载完成(使用缓存)`);
|
|
615
|
-
return cachedPdf;
|
|
616
|
-
}
|
|
658
|
+
// 获取stream数据
|
|
659
|
+
const streamData = await fetchStreamData(pageNo);
|
|
617
660
|
|
|
618
|
-
|
|
619
|
-
|
|
661
|
+
// 使用fileParser解析数据
|
|
662
|
+
const parseResult: ParseResult = await parseFile(streamData, {
|
|
663
|
+
fileName: fileName || 'Stream文档',
|
|
664
|
+
fileType: 'pdf',
|
|
665
|
+
token: authorization,
|
|
666
|
+
});
|
|
620
667
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
fileType: 'pdf',
|
|
625
|
-
token: authorization,
|
|
626
|
-
});
|
|
668
|
+
if (parseResult.error) {
|
|
669
|
+
throw new Error(parseResult.error);
|
|
670
|
+
}
|
|
627
671
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
672
|
+
if (parseResult.type !== 'pdf' || !parseResult.content?.document) {
|
|
673
|
+
throw new Error('解析结果不是有效的PDF文档');
|
|
674
|
+
}
|
|
631
675
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
676
|
+
const pdf = parseResult.content.document;
|
|
677
|
+
console.log('设置PDF文档:', pdf);
|
|
678
|
+
console.log('PDF文档类型:', typeof pdf);
|
|
679
|
+
console.log(
|
|
680
|
+
'PDF文档方法:',
|
|
681
|
+
pdf ? Object.getOwnPropertyNames(Object.getPrototypeOf(pdf)) : '无文档'
|
|
682
|
+
);
|
|
683
|
+
console.log('PDF文档页数:', pdf ? pdf.numPages : '无页数');
|
|
684
|
+
console.log('当前请求的页面:', pageNo);
|
|
685
|
+
console.log('PDF文档包含的页面范围:', pdf ? `1-${pdf.numPages}` : '无页数');
|
|
686
|
+
setPdfDocument(pdf);
|
|
687
|
+
|
|
688
|
+
// 缓存解析后的PDF文档
|
|
689
|
+
const chunkKey = getChunkKey(pageNo, pageSize);
|
|
690
|
+
if (chunkCache.current[chunkKey]) {
|
|
691
|
+
chunkCache.current[chunkKey].pdfDocument = pdf;
|
|
692
|
+
console.log(`缓存PDF文档到chunk: ${chunkKey}`);
|
|
693
|
+
}
|
|
635
694
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
695
|
+
// 设置总页数 - 优先使用用户传入的总页数,如果没有传入则使用PDF文档的实际页数
|
|
696
|
+
if (userTotalPages) {
|
|
697
|
+
console.log(`使用用户传入的总页数: ${userTotalPages}`);
|
|
698
|
+
setTotalPages(userTotalPages);
|
|
699
|
+
} else if (pdf && pdf.numPages) {
|
|
700
|
+
const actualTotalPages = pdf.numPages;
|
|
701
|
+
console.log(`用户未传入总页数,从PDF文档获取实际总页数: ${actualTotalPages}`);
|
|
702
|
+
setTotalPages(actualTotalPages);
|
|
703
|
+
}
|
|
644
704
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (chunkCache.current[chunkKey]) {
|
|
648
|
-
chunkCache.current[chunkKey].pdfDocument = pdf;
|
|
649
|
-
console.log(`缓存PDF文档到chunk: ${chunkKey}`);
|
|
650
|
-
}
|
|
705
|
+
setIsLoading(false);
|
|
706
|
+
setLoadingStatus('');
|
|
651
707
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
708
|
+
console.log(`页面 ${pageNo} 加载完成`);
|
|
709
|
+
return pdf;
|
|
710
|
+
} catch (error: any) {
|
|
711
|
+
console.error('PDF加载失败:', error);
|
|
712
|
+
setError(error.message || 'PDF加载失败,请稍后重试');
|
|
713
|
+
setIsLoading(false);
|
|
714
|
+
setLoadingStatus('');
|
|
715
|
+
throw error;
|
|
660
716
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
}, [fetchStreamData, fileName, authorization, totalPages, getCachedPage, getChunkKey, pageSize, fileType]);
|
|
717
|
+
},
|
|
718
|
+
[
|
|
719
|
+
fetchStreamData,
|
|
720
|
+
fileName,
|
|
721
|
+
authorization,
|
|
722
|
+
totalPages,
|
|
723
|
+
getCachedPage,
|
|
724
|
+
getChunkKey,
|
|
725
|
+
pageSize,
|
|
726
|
+
fileType,
|
|
727
|
+
]
|
|
728
|
+
);
|
|
675
729
|
|
|
676
730
|
/**
|
|
677
731
|
* 检查页面是否在缓存中(用于调试)
|
|
678
732
|
*/
|
|
679
|
-
const isPageInCache = useCallback(
|
|
680
|
-
|
|
681
|
-
|
|
733
|
+
const isPageInCache = useCallback(
|
|
734
|
+
(pageNo: number): boolean => {
|
|
735
|
+
// 根据文件类型决定处理方式
|
|
736
|
+
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
682
737
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
738
|
+
if (!isPDF) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
686
741
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
742
|
+
// 先检查单个页面缓存
|
|
743
|
+
const pageCached = pageCache.current[pageNo];
|
|
744
|
+
if (pageCached && Date.now() - pageCached.timestamp < CACHE_EXPIRY_TIME) {
|
|
745
|
+
return !!pageCached.pdfDocument;
|
|
746
|
+
}
|
|
692
747
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
748
|
+
// 检查chunk缓存
|
|
749
|
+
const chunkKey = getChunkKey(pageNo, pageSize);
|
|
750
|
+
const chunkCached = chunkCache.current[chunkKey];
|
|
751
|
+
if (chunkCached && Date.now() - chunkCached.timestamp < CACHE_EXPIRY_TIME) {
|
|
752
|
+
return chunkCached.pages.includes(pageNo) && !!chunkCached.pdfDocument;
|
|
753
|
+
}
|
|
699
754
|
|
|
700
|
-
|
|
701
|
-
|
|
755
|
+
return false;
|
|
756
|
+
},
|
|
757
|
+
[pageSize, getChunkKey, fileType]
|
|
758
|
+
);
|
|
702
759
|
|
|
703
760
|
// ========== Markdown相关工具函数 ==========
|
|
704
761
|
|
|
@@ -752,7 +809,8 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
752
809
|
});
|
|
753
810
|
|
|
754
811
|
// 获取响应头中的CSRF Token并触发事件
|
|
755
|
-
const responseCsrfToken =
|
|
812
|
+
const responseCsrfToken =
|
|
813
|
+
response.headers['x-csrf-token-out'] || response.headers['X-CSRF-TOKEN-OUT'];
|
|
756
814
|
if (responseCsrfToken) {
|
|
757
815
|
console.log('获取到响应头中的CSRF Token:', responseCsrfToken);
|
|
758
816
|
eventsEmit('request_finish', responseCsrfToken);
|
|
@@ -796,7 +854,7 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
796
854
|
// 缓存markdown内容
|
|
797
855
|
markdownContentCache.current = {
|
|
798
856
|
data: streamData,
|
|
799
|
-
timestamp: Date.now()
|
|
857
|
+
timestamp: Date.now(),
|
|
800
858
|
};
|
|
801
859
|
|
|
802
860
|
setMarkdownContent(streamData);
|
|
@@ -835,17 +893,14 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
835
893
|
// 不传 pageNo/pageSize,获取完整图片二进制
|
|
836
894
|
};
|
|
837
895
|
|
|
838
|
-
const response = await axios.post<ArrayBuffer>(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
headers,
|
|
843
|
-
responseType: 'arraybuffer',
|
|
844
|
-
}
|
|
845
|
-
);
|
|
896
|
+
const response = await axios.post<ArrayBuffer>(streamApiUrl, requestData, {
|
|
897
|
+
headers,
|
|
898
|
+
responseType: 'arraybuffer',
|
|
899
|
+
});
|
|
846
900
|
|
|
847
901
|
// 获取响应头中的CSRF Token并触发事件
|
|
848
|
-
const responseCsrfToken =
|
|
902
|
+
const responseCsrfToken =
|
|
903
|
+
response.headers['x-csrf-token-out'] || response.headers['X-CSRF-TOKEN-OUT'];
|
|
849
904
|
if (responseCsrfToken) {
|
|
850
905
|
console.log('获取到响应头中的CSRF Token:', responseCsrfToken);
|
|
851
906
|
eventsEmit('request_finish', responseCsrfToken);
|
|
@@ -924,17 +979,14 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
924
979
|
|
|
925
980
|
console.log('发送通用文件请求:', requestData);
|
|
926
981
|
|
|
927
|
-
const response = await axios.post<ArrayBuffer>(
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
headers,
|
|
932
|
-
responseType: 'arraybuffer',
|
|
933
|
-
}
|
|
934
|
-
);
|
|
982
|
+
const response = await axios.post<ArrayBuffer>(streamApiUrl, requestData, {
|
|
983
|
+
headers,
|
|
984
|
+
responseType: 'arraybuffer',
|
|
985
|
+
});
|
|
935
986
|
|
|
936
987
|
// 获取响应头中的CSRF Token并触发事件
|
|
937
|
-
const responseCsrfToken =
|
|
988
|
+
const responseCsrfToken =
|
|
989
|
+
response.headers['x-csrf-token-out'] || response.headers['X-CSRF-TOKEN-OUT'];
|
|
938
990
|
if (responseCsrfToken) {
|
|
939
991
|
console.log('获取到响应头中的CSRF Token:', responseCsrfToken);
|
|
940
992
|
eventsEmit('request_finish', responseCsrfToken);
|
|
@@ -974,7 +1026,9 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
974
1026
|
// 检查缓存
|
|
975
1027
|
const cacheKey = `${fileType}_${convertedFilePath}`;
|
|
976
1028
|
const cached = genericContentCache[cacheKey];
|
|
977
|
-
console.log(
|
|
1029
|
+
console.log(
|
|
1030
|
+
`检查通用文档缓存,key: ${cacheKey}, 缓存存在: ${!!cached}, 缓存时间: ${cached ? Date.now() - cached.timestamp : 'N/A'}ms`
|
|
1031
|
+
);
|
|
978
1032
|
|
|
979
1033
|
if (cached && Date.now() - cached.timestamp < CACHE_EXPIRY_TIME) {
|
|
980
1034
|
console.log(`使用缓存的通用文档内容,文件类型: ${fileType}`);
|
|
@@ -1042,8 +1096,8 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1042
1096
|
...genericContentCache,
|
|
1043
1097
|
[cacheKey]: {
|
|
1044
1098
|
content: finalContent,
|
|
1045
|
-
timestamp: Date.now()
|
|
1046
|
-
}
|
|
1099
|
+
timestamp: Date.now(),
|
|
1100
|
+
},
|
|
1047
1101
|
};
|
|
1048
1102
|
setGenericContentCache(newCache);
|
|
1049
1103
|
console.log(`通用文档内容已缓存,文件类型: ${fileType}, 缓存键: ${cacheKey}`);
|
|
@@ -1072,40 +1126,43 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1072
1126
|
/**
|
|
1073
1127
|
* 处理页面变化(仅用于PDF文件类型)
|
|
1074
1128
|
*/
|
|
1075
|
-
const handlePageChange = useCallback(
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1129
|
+
const handlePageChange = useCallback(
|
|
1130
|
+
async (pageNumber: number) => {
|
|
1131
|
+
if (pageNumber === currentPageRef.current) return;
|
|
1132
|
+
if (isLoading) {
|
|
1133
|
+
console.log('页面正在加载中,忽略翻页请求');
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1081
1136
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1137
|
+
// 根据文件类型决定处理方式
|
|
1138
|
+
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
1084
1139
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1140
|
+
if (!isPDF) {
|
|
1141
|
+
console.log(`文件类型 ${fileType} 不支持翻页,忽略翻页请求`);
|
|
1142
|
+
return; // 直接返回,不进行任何操作
|
|
1143
|
+
}
|
|
1089
1144
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1145
|
+
console.log('PDF页面变化:', pageNumber, '当前页:', currentPageRef.current);
|
|
1146
|
+
console.log(`页面 ${pageNumber} 是否在缓存中:`, isPageInCache(pageNumber));
|
|
1092
1147
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1148
|
+
// 更新ref和state
|
|
1149
|
+
currentPageRef.current = pageNumber;
|
|
1150
|
+
setCurrentPage(pageNumber);
|
|
1096
1151
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1152
|
+
try {
|
|
1153
|
+
await loadPDFDocument(pageNumber, false); // 非初始加载
|
|
1154
|
+
// 优先使用用户传入的总页数
|
|
1155
|
+
const finalTotalPages = userTotalPages || totalPages;
|
|
1156
|
+
eventsEmit('pageChange', { pageNumber, totalPages: finalTotalPages });
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
console.error('PDF页面加载失败:', error);
|
|
1159
|
+
// 加载失败时恢复当前页
|
|
1160
|
+
const originalPage = currentPageRef.current;
|
|
1161
|
+
setCurrentPage(originalPage);
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
[loadPDFDocument, totalPages, eventsEmit, isPageInCache, isLoading, fileType]
|
|
1165
|
+
);
|
|
1109
1166
|
|
|
1110
1167
|
// 添加useEffect来监听currentPage变化,确保状态同步
|
|
1111
1168
|
useEffect(() => {
|
|
@@ -1116,10 +1173,13 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1116
1173
|
/**
|
|
1117
1174
|
* 处理缩放变化
|
|
1118
1175
|
*/
|
|
1119
|
-
const handleZoomChange = useCallback(
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1176
|
+
const handleZoomChange = useCallback(
|
|
1177
|
+
(newScale: number) => {
|
|
1178
|
+
setScale(newScale);
|
|
1179
|
+
eventsEmit('zoomChange', { scale: newScale });
|
|
1180
|
+
},
|
|
1181
|
+
[eventsEmit]
|
|
1182
|
+
);
|
|
1123
1183
|
|
|
1124
1184
|
/**
|
|
1125
1185
|
* 处理关闭
|
|
@@ -1225,7 +1285,10 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1225
1285
|
});
|
|
1226
1286
|
|
|
1227
1287
|
// 清理markdown内容缓存
|
|
1228
|
-
if (
|
|
1288
|
+
if (
|
|
1289
|
+
markdownContentCache.current &&
|
|
1290
|
+
now - markdownContentCache.current.timestamp > CACHE_EXPIRY_TIME
|
|
1291
|
+
) {
|
|
1229
1292
|
markdownContentCache.current = null;
|
|
1230
1293
|
console.log('清理过期markdown内容缓存');
|
|
1231
1294
|
}
|
|
@@ -1285,8 +1348,15 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1285
1348
|
try {
|
|
1286
1349
|
// 根据文件类型决定是否使用翻页参数
|
|
1287
1350
|
const isPDF = fileType === 'pdf' || fileType === 'pdf_slides';
|
|
1288
|
-
const effectivePage = isPDF ?
|
|
1289
|
-
console.log(
|
|
1351
|
+
const effectivePage = isPDF ? initialPage || 1 : 1;
|
|
1352
|
+
console.log(
|
|
1353
|
+
'开始初始加载,文件类型:',
|
|
1354
|
+
fileType,
|
|
1355
|
+
'有效页码:',
|
|
1356
|
+
effectivePage,
|
|
1357
|
+
'是否PDF:',
|
|
1358
|
+
isPDF
|
|
1359
|
+
);
|
|
1290
1360
|
|
|
1291
1361
|
if (fileType === 'markdown' || fileType === 'markdown_table') {
|
|
1292
1362
|
// Markdown文件加载完整内容,忽略翻页参数
|
|
@@ -1321,22 +1391,28 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1321
1391
|
setTotalPages(userTotalPages || 1);
|
|
1322
1392
|
eventsEmit('pageChange', { pageNumber: 1, totalPages: userTotalPages || 1 });
|
|
1323
1393
|
}
|
|
1324
|
-
} catch (error) {
|
|
1394
|
+
} catch (error: any) {
|
|
1325
1395
|
console.error('初始加载失败:', error);
|
|
1396
|
+
// 确保错误状态被正确设置,避免组件状态不一致
|
|
1397
|
+
setError(error?.message || '文件加载失败,请稍后重试');
|
|
1398
|
+
setIsLoading(false);
|
|
1399
|
+
setLoadingStatus('');
|
|
1326
1400
|
}
|
|
1327
1401
|
};
|
|
1328
1402
|
|
|
1329
1403
|
loadInitialPage();
|
|
1330
1404
|
}, [initialPage, fileType, convertedFilePath]);
|
|
1331
1405
|
|
|
1406
|
+
// 所有 hooks 必须在条件返回之前调用
|
|
1407
|
+
const pdfStartPage = useMemo(() => {
|
|
1408
|
+
return Math.floor((currentPage - 1) / pageSize) * pageSize + 1;
|
|
1409
|
+
}, [currentPage, pageSize]);
|
|
1410
|
+
|
|
1332
1411
|
if (error) {
|
|
1333
1412
|
return (
|
|
1334
1413
|
<ReaderContainer $theme={mergedTheme} className={className}>
|
|
1335
1414
|
{customComponents?.ErrorComponent ? (
|
|
1336
|
-
<customComponents.ErrorComponent
|
|
1337
|
-
error={error}
|
|
1338
|
-
theme={mergedTheme}
|
|
1339
|
-
/>
|
|
1415
|
+
<customComponents.ErrorComponent error={error} theme={mergedTheme} />
|
|
1340
1416
|
) : (
|
|
1341
1417
|
<ErrorContainer $theme={mergedTheme}>
|
|
1342
1418
|
<div>加载失败</div>
|
|
@@ -1347,10 +1423,6 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1347
1423
|
);
|
|
1348
1424
|
}
|
|
1349
1425
|
|
|
1350
|
-
const pdfStartPage = useMemo(()=>{
|
|
1351
|
-
return Math.floor((currentPage - 1) / pageSize) * pageSize + 1
|
|
1352
|
-
},[currentPage,pageSize])
|
|
1353
|
-
|
|
1354
1426
|
// 渲染加载状态
|
|
1355
1427
|
if (isLoading) {
|
|
1356
1428
|
return (
|
|
@@ -1376,15 +1448,9 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1376
1448
|
|
|
1377
1449
|
{/* 内容区域 - 显示加载状态 */}
|
|
1378
1450
|
{customComponents?.LoadingComponent ? (
|
|
1379
|
-
<customComponents.LoadingComponent
|
|
1380
|
-
status={loadingStatus}
|
|
1381
|
-
theme={mergedTheme}
|
|
1382
|
-
/>
|
|
1451
|
+
<customComponents.LoadingComponent status={loadingStatus} theme={mergedTheme} />
|
|
1383
1452
|
) : (
|
|
1384
|
-
<DefaultLoadingComponent
|
|
1385
|
-
status={loadingStatus}
|
|
1386
|
-
theme={mergedTheme}
|
|
1387
|
-
/>
|
|
1453
|
+
<DefaultLoadingComponent status={loadingStatus} theme={mergedTheme} />
|
|
1388
1454
|
)}
|
|
1389
1455
|
</ReaderContainer>
|
|
1390
1456
|
);
|
|
@@ -1392,8 +1458,8 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1392
1458
|
|
|
1393
1459
|
return (
|
|
1394
1460
|
<ReaderContainer $theme={mergedTheme} className={className}>
|
|
1395
|
-
|
|
1396
|
-
|
|
1461
|
+
{/* Header组件 */}
|
|
1462
|
+
<Header
|
|
1397
1463
|
fileName={getFileName()}
|
|
1398
1464
|
currentPage={currentPage}
|
|
1399
1465
|
totalPage={totalPages}
|
|
@@ -1401,8 +1467,8 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1401
1467
|
isAnnotating={false}
|
|
1402
1468
|
tools={{
|
|
1403
1469
|
...tools,
|
|
1404
|
-
|
|
1405
|
-
|
|
1470
|
+
// 仅PDF和PDF幻灯片显示导航
|
|
1471
|
+
navigation: fileType === 'pdf' || fileType === 'pdf_slides' ? tools.navigation : false,
|
|
1406
1472
|
// 仅图片显示旋转
|
|
1407
1473
|
rotate: fileType === 'image',
|
|
1408
1474
|
}}
|
|
@@ -1419,7 +1485,7 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1419
1485
|
className={headerClass}
|
|
1420
1486
|
/>
|
|
1421
1487
|
|
|
1422
|
-
|
|
1488
|
+
{fileType === 'markdown' || fileType === 'markdown_table' ? (
|
|
1423
1489
|
// Markdown内容渲染 - 使用Fviewer的markdown渲染逻辑
|
|
1424
1490
|
<div
|
|
1425
1491
|
ref={scrollContainerRef}
|
|
@@ -1432,7 +1498,7 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1432
1498
|
>
|
|
1433
1499
|
<Fviewer
|
|
1434
1500
|
data={{
|
|
1435
|
-
content: markdownContent,
|
|
1501
|
+
content: markdownContent, // 直接传递markdown内容字符串
|
|
1436
1502
|
...(getFileName() && { fileName: getFileName() }),
|
|
1437
1503
|
...(fileType && { fileType }),
|
|
1438
1504
|
...(totalPages && { totalPages }),
|
|
@@ -1463,7 +1529,10 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1463
1529
|
console.log('markdownContent:', markdownContent);
|
|
1464
1530
|
console.log('markdownContent长度:', markdownContent.length);
|
|
1465
1531
|
console.log('markdownContent前100字符:', markdownContent.substring(0, 100));
|
|
1466
|
-
console.log(
|
|
1532
|
+
console.log(
|
|
1533
|
+
'markdownContent后100字符:',
|
|
1534
|
+
markdownContent.substring(markdownContent.length - 100)
|
|
1535
|
+
);
|
|
1467
1536
|
return null;
|
|
1468
1537
|
})()}
|
|
1469
1538
|
|
|
@@ -1496,12 +1565,12 @@ const GientechStreamReader: React.FC<GientechStreamReaderProps> = ({
|
|
|
1496
1565
|
// PDF内容渲染
|
|
1497
1566
|
<Fviewer
|
|
1498
1567
|
data={{
|
|
1499
|
-
content: { document: pdfDocument },
|
|
1568
|
+
content: { document: pdfDocument }, // 修复:包装成期望的数据结构
|
|
1500
1569
|
...(getFileName() && { fileName: getFileName() }),
|
|
1501
1570
|
...(fileType && { fileType }),
|
|
1502
1571
|
...(totalPages && { totalPages }),
|
|
1503
1572
|
// 添加PDF起始页信息,用于分页PDF的页码映射
|
|
1504
|
-
pdfStartPage
|
|
1573
|
+
pdfStartPage,
|
|
1505
1574
|
}}
|
|
1506
1575
|
annotationData={annotations}
|
|
1507
1576
|
totalPage={totalPages}
|