@spacecorexdev/core 0.0.2 → 0.0.5
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/package.json +20 -38
- package/public/cmaps/78-EUC-H.bcmap +0 -0
- package/public/cmaps/78-EUC-V.bcmap +0 -0
- package/public/cmaps/78-H.bcmap +0 -0
- package/public/cmaps/78-RKSJ-H.bcmap +0 -0
- package/public/cmaps/78-RKSJ-V.bcmap +0 -0
- package/public/cmaps/78-V.bcmap +0 -0
- package/public/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/public/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/public/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/public/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/public/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/public/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Add-H.bcmap +0 -0
- package/public/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/public/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Add-V.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/public/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/public/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/public/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/public/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/public/cmaps/B5-H.bcmap +0 -0
- package/public/cmaps/B5-V.bcmap +0 -0
- package/public/cmaps/B5pc-H.bcmap +0 -0
- package/public/cmaps/B5pc-V.bcmap +0 -0
- package/public/cmaps/CNS-EUC-H.bcmap +0 -0
- package/public/cmaps/CNS-EUC-V.bcmap +0 -0
- package/public/cmaps/CNS1-H.bcmap +0 -0
- package/public/cmaps/CNS1-V.bcmap +0 -0
- package/public/cmaps/CNS2-H.bcmap +0 -0
- package/public/cmaps/CNS2-V.bcmap +3 -0
- package/public/cmaps/ETHK-B5-H.bcmap +0 -0
- package/public/cmaps/ETHK-B5-V.bcmap +0 -0
- package/public/cmaps/ETen-B5-H.bcmap +0 -0
- package/public/cmaps/ETen-B5-V.bcmap +0 -0
- package/public/cmaps/ETenms-B5-H.bcmap +3 -0
- package/public/cmaps/ETenms-B5-V.bcmap +0 -0
- package/public/cmaps/EUC-H.bcmap +0 -0
- package/public/cmaps/EUC-V.bcmap +0 -0
- package/public/cmaps/Ext-H.bcmap +0 -0
- package/public/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/public/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/public/cmaps/Ext-V.bcmap +0 -0
- package/public/cmaps/GB-EUC-H.bcmap +0 -0
- package/public/cmaps/GB-EUC-V.bcmap +0 -0
- package/public/cmaps/GB-H.bcmap +4 -0
- package/public/cmaps/GB-V.bcmap +0 -0
- package/public/cmaps/GBK-EUC-H.bcmap +0 -0
- package/public/cmaps/GBK-EUC-V.bcmap +0 -0
- package/public/cmaps/GBK2K-H.bcmap +0 -0
- package/public/cmaps/GBK2K-V.bcmap +0 -0
- package/public/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/public/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/public/cmaps/GBT-EUC-H.bcmap +0 -0
- package/public/cmaps/GBT-EUC-V.bcmap +0 -0
- package/public/cmaps/GBT-H.bcmap +0 -0
- package/public/cmaps/GBT-V.bcmap +0 -0
- package/public/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/public/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/public/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/public/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/public/cmaps/H.bcmap +0 -0
- package/public/cmaps/HKdla-B5-H.bcmap +0 -0
- package/public/cmaps/HKdla-B5-V.bcmap +0 -0
- package/public/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/public/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/public/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/public/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/public/cmaps/HKm314-B5-H.bcmap +0 -0
- package/public/cmaps/HKm314-B5-V.bcmap +0 -0
- package/public/cmaps/HKm471-B5-H.bcmap +0 -0
- package/public/cmaps/HKm471-B5-V.bcmap +0 -0
- package/public/cmaps/HKscs-B5-H.bcmap +0 -0
- package/public/cmaps/HKscs-B5-V.bcmap +0 -0
- package/public/cmaps/Hankaku.bcmap +0 -0
- package/public/cmaps/Hiragana.bcmap +0 -0
- package/public/cmaps/KSC-EUC-H.bcmap +0 -0
- package/public/cmaps/KSC-EUC-V.bcmap +0 -0
- package/public/cmaps/KSC-H.bcmap +0 -0
- package/public/cmaps/KSC-Johab-H.bcmap +0 -0
- package/public/cmaps/KSC-Johab-V.bcmap +0 -0
- package/public/cmaps/KSC-V.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/public/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/public/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/public/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/public/cmaps/Katakana.bcmap +0 -0
- package/public/cmaps/LICENSE +36 -0
- package/public/cmaps/NWP-H.bcmap +0 -0
- package/public/cmaps/NWP-V.bcmap +0 -0
- package/public/cmaps/RKSJ-H.bcmap +0 -0
- package/public/cmaps/RKSJ-V.bcmap +0 -0
- package/public/cmaps/Roman.bcmap +0 -0
- package/public/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/public/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/public/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/public/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/public/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/public/cmaps/V.bcmap +0 -0
- package/public/cmaps/WP-Symbol.bcmap +0 -0
- package/public/polyfills/polyfills.js +802 -0
- package/public/vendor/docx/docx.worker.js +5 -0
- package/public/vendor/docx/jszip.min.js +13 -0
- package/public/vendor/libarchive/libarchive.wasm +0 -0
- package/public/vendor/libarchive/worker-bundle.js +6 -0
- package/public/vendor/pptx/pptx.worker.js +26 -0
- package/public/wasm/cad/0.8.2/dwfv-render.wasm +0 -0
- package/public/wasm/cad/0.8.2/dwg-worker.js +24 -0
- package/public/wasm/cad/0.8.2/dwg-worker.js.map +1 -0
- package/public/wasm/cad/0.8.2/libredwg-web.js +2 -0
- package/public/wasm/cad/0.8.2/libredwg-web.wasm +0 -0
- package/public/wasm/cad/dwfv-render.wasm +0 -0
- package/public/wasm/cad/dwg-worker.js +24 -0
- package/public/wasm/cad/dwg-worker.js.map +1 -0
- package/public/wasm/cad/libredwg-web.js +2 -0
- package/public/wasm/cad/libredwg-web.wasm +0 -0
- package/public/wasm/data/sql-wasm.wasm +0 -0
- package/public/wasm/hdiff.wasm +0 -0
- package/public/wasm/model/LICENSE.occt-import-js.txt +504 -0
- package/public/wasm/model/LICENSE.occt.txt +502 -0
- package/public/wasm/model/occt-import-js.js +19 -0
- package/public/wasm/model/occt-import-js.wasm +0 -0
- package/public/wasm/model/occt-worker.js +83 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-Bold.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-BoldOblique.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono-Oblique.ttf +0 -0
- package/public/wasm/typst/fonts/DejaVuSansMono.ttf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Bold.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-BoldItalic.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Italic.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Regular.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-Semibold.otf +0 -0
- package/public/wasm/typst/fonts/LibertinusSerif-SemiboldItalic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Bold.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-BoldItalic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Italic.otf +0 -0
- package/public/wasm/typst/fonts/NewCM10-Regular.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Bold.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Book.otf +0 -0
- package/public/wasm/typst/fonts/NewCMMath-Regular.otf +0 -0
- package/public/wasm/typst/fonts/README.md +7 -0
- package/public/wasm/typst/typst_ts_renderer_bg.wasm +0 -0
- package/public/wasm/typst/typst_ts_web_compiler_bg.wasm +0 -0
- package/scripts/patch-docx-grid.cjs +412 -0
- package/src/api/_base.ts +243 -0
- package/src/api/index.ts +17 -0
- package/src/api/project.ts +1345 -0
- package/src/api/user.ts +1174 -0
- package/src/contract.ts +50 -0
- package/src/hooks/index.ts +2 -0
- package/{dist/hooks/index.js → src/hooks/useLongPress.ts} +53 -49
- package/src/hooks/useOnlineStatus.ts +22 -0
- package/src/index.ts +14 -0
- package/src/types/id.ts +2 -0
- package/src/types/index.ts +5 -0
- package/src/types/project/base.ts +63 -0
- package/src/types/project/contract.ts +79 -0
- package/src/types/project/contractStatus.tsx +15 -0
- package/src/types/project/index.ts +5 -0
- package/src/types/project/member.ts +46 -0
- package/src/types/project/progress.ts +43 -0
- package/src/types/projectRole.ts +17 -0
- package/src/types/theme.ts +1 -0
- package/src/types/user/index.ts +1 -0
- package/src/types/user/role.ts +7 -0
- package/src/ui/CommentTimeline/index.tsx +330 -0
- package/src/ui/FileManager/FileContextMenu.tsx +628 -0
- package/src/ui/FileManager/FileGridView.tsx +529 -0
- package/src/ui/FileManager/FileTableView.tsx +405 -0
- package/src/ui/FileManager/FileToolbar.tsx +119 -0
- package/src/ui/FileManager/FileVersionHistoryModal.tsx +175 -0
- package/src/ui/FileManager/MoveCopyToProjectModal.tsx +119 -0
- package/src/ui/FileManager/ShareToWechatModal.tsx +419 -0
- package/src/ui/FileManager/hooks/useFileManagerActions.ts +2532 -0
- package/src/ui/FileManager/hooks/useFileManagerState.ts +419 -0
- package/src/ui/FileManager/index.tsx +580 -0
- package/src/ui/FileManager/projectFileManagerApi.ts +57 -0
- package/src/ui/FileManager/types.ts +184 -0
- package/src/ui/FileManager/utils/fileDeltaWorker.ts +193 -0
- package/src/ui/FileManager/utils/fileTree.ts +178 -0
- package/src/ui/FileManager/utils/fileUpload.ts +714 -0
- package/src/ui/FileManager/utils/fileUtils.ts +65 -0
- package/src/ui/InvoiceRecordsList/index.tsx +813 -0
- package/src/ui/MyFileSelectorModal.tsx +261 -0
- package/src/ui/ProjectSelector/index.tsx +472 -0
- package/src/ui/ProjectSelector/projectCache.ts +40 -0
- package/src/ui/RoleSelector/index.tsx +473 -0
- package/src/ui/RoleSelector/roleCache.ts +40 -0
- package/src/ui/UIAlert.tsx +399 -0
- package/src/ui/UIAlertExample.tsx +129 -0
- package/src/ui/UIConfirm.tsx +335 -0
- package/src/ui/UIConfirmExample.tsx +165 -0
- package/src/ui/UIDatePicker.tsx +146 -0
- package/src/ui/UIDateRangePicker.tsx +38 -0
- package/src/ui/UIFilePreview/ExcelEditor/index.tsx +617 -0
- package/src/ui/UIFilePreview/ExcelEditor/types.ts +24 -0
- package/src/ui/UIFilePreview/ExportDropdown.css +85 -0
- package/src/ui/UIFilePreview/ExportDropdown.tsx +109 -0
- package/src/ui/UIFilePreview/IndexedDBUtils.ts +564 -0
- package/src/ui/UIFilePreview/MarkdownEditor/exportMarkdownPdf.ts +576 -0
- package/src/ui/UIFilePreview/MarkdownEditor/index.tsx +677 -0
- package/src/ui/UIFilePreview/MarkdownEditor/markdownEditor.css +1005 -0
- package/src/ui/UIFilePreview/MarkdownEditor/types.ts +15 -0
- package/src/ui/UIFilePreview/PPTXEditor/index.tsx +602 -0
- package/src/ui/UIFilePreview/RichDocEditor/exportRDocMarkdown.ts +77 -0
- package/src/ui/UIFilePreview/RichDocEditor/exportRDocPdf.ts +374 -0
- package/src/ui/UIFilePreview/RichDocEditor/index.tsx +730 -0
- package/src/ui/UIFilePreview/RichDocEditor/richdoc-editor.css +59 -0
- package/src/ui/UIFilePreview/UIFilePreview.tsx +611 -0
- package/src/ui/UIFilePreview/WordEditor/index.tsx +3933 -0
- package/src/ui/UIFilePreview/WordEditor/style.ts +1213 -0
- package/src/ui/UIFilePreview/WordEditor/word-editor.css +999 -0
- package/src/ui/UIFilePreview/filePreview.css +193 -0
- package/src/ui/UIFilePreview/filetypes/archive.tsx +66 -0
- package/src/ui/UIFilePreview/filetypes/cad.tsx +287 -0
- package/src/ui/UIFilePreview/filetypes/excel.tsx +355 -0
- package/src/ui/UIFilePreview/filetypes/image.tsx +20 -0
- package/src/ui/UIFilePreview/filetypes/imageLoader.ts +63 -0
- package/src/ui/UIFilePreview/filetypes/pdf.tsx +156 -0
- package/src/ui/UIFilePreview/filetypes/ppt.tsx +535 -0
- package/src/ui/UIFilePreview/filetypes/pptExportPdf.ts +523 -0
- package/src/ui/UIFilePreview/filetypes/video.tsx +482 -0
- package/src/ui/UIFilePreview/filetypes/word.tsx +245 -0
- package/src/ui/UIFilePreview/filetypes/wordExportMarkdown.ts +86 -0
- package/src/ui/UIFilePreview/filetypes/wordExportPdf.tsx +427 -0
- package/src/ui/UIFilePreview/index.ts +35 -0
- package/src/ui/UIFilePreview/pdfPagination.ts +143 -0
- package/src/ui/UIFilePreview/previewUtils.tsx +531 -0
- package/src/ui/UIFileUpload.tsx +382 -0
- package/src/ui/UIImageUpload.tsx +195 -0
- package/src/ui/UILoading.tsx +255 -0
- package/src/ui/UILoadingExample.tsx +139 -0
- package/src/ui/UISelect.tsx +105 -0
- package/src/ui/UIToast.tsx +381 -0
- package/src/ui/UIToastExample.tsx +69 -0
- package/src/ui/UIToastSingle.tsx +279 -0
- package/src/ui/UIViewToggle.tsx +64 -0
- package/src/ui/UserSelector/index.tsx +583 -0
- package/src/ui/index.ts +84 -0
- package/src/ui/upload/image.ts +135 -0
- package/src/ui/upload/index.ts +73 -0
- package/src/ui/upload/submitFile.ts +106 -0
- package/src/ui/upload/submitForm.ts +124 -0
- package/src/ui/upload/upload.err.ts +15 -0
- package/src/ui/upload/upload.ts +250 -0
- package/src/utils/CacheDepartmentInfo.ts +372 -0
- package/src/utils/CacheFileContent.ts +315 -0
- package/src/utils/CachePermissionInfo.ts +235 -0
- package/src/utils/CacheRoleInfo.ts +303 -0
- package/src/utils/CacheUserInfo.ts +818 -0
- package/src/utils/CacheViewToggleInfo.ts +182 -0
- package/src/utils/MessageContentUtils.ts +268 -0
- package/src/utils/clipboard.ts +70 -0
- package/src/utils/companyEmail.ts +19 -0
- package/src/utils/forbidDebugger.ts +59 -0
- package/src/utils/formatters.ts +94 -0
- package/src/utils/htmlUtils.tsx +59 -0
- package/src/utils/index.ts +18 -0
- package/src/utils/keyboard.ts +114 -0
- package/src/utils/mammothApi.ts +16 -0
- package/src/utils/polyfills.ts +928 -0
- package/src/utils/regex.ts +14 -0
- package/src/utils/storage.ts +95 -0
- package/src/utils/workerBootstrap.ts +87 -0
- package/dist/api/index.js +0 -1553
- package/dist/contract.js +0 -5
- package/dist/index.js +0 -4492
- package/dist/types/index.js +0 -49
- package/dist/ui/index.css +0 -1876
- package/dist/ui/index.js +0 -22245
- package/dist/utils/index.js +0 -4296
- /package/{dist → src}/styles/ant-modal.css +0 -0
- /package/{dist → src}/styles/ant-spin.css +0 -0
- /package/{dist → src}/styles/ant-table.css +0 -0
- /package/{dist → src}/styles/index.css +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* BlockNote 编辑器容器样式 */
|
|
2
|
+
.richdoc-editor-host {
|
|
3
|
+
height: 100%;
|
|
4
|
+
overflow-y: auto;
|
|
5
|
+
background: #fff;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.richdoc-editor-host .bn-container {
|
|
9
|
+
height: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* 暗色主题:容器与编辑器统一使用应用表面色。
|
|
13
|
+
BlockNote 暗色编辑器自带 #1f1f1f 底色,与表面色存在色差,
|
|
14
|
+
会让 700px 宽的正文两侧出现一条异色边,这里把编辑器底色改为透明。
|
|
15
|
+
排除导出用离屏容器(同样带 .richdoc-editor-host),保证导出始终为浅色排版。 */
|
|
16
|
+
.dark .richdoc-editor-host:not(.rdoc-export-preview),
|
|
17
|
+
[data-theme="dark"] .richdoc-editor-host:not(.rdoc-export-preview) {
|
|
18
|
+
background: rgb(var(--color-surface));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dark .richdoc-editor-host:not(.rdoc-export-preview) .bn-editor,
|
|
22
|
+
[data-theme="dark"] .richdoc-editor-host:not(.rdoc-export-preview) .bn-editor {
|
|
23
|
+
background-color: transparent;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.richdoc-editor-host .bn-editor {
|
|
27
|
+
height: 100%;
|
|
28
|
+
margin: auto;
|
|
29
|
+
max-width: 700px;
|
|
30
|
+
padding-top: 24px;
|
|
31
|
+
padding-left: 0;
|
|
32
|
+
padding-right: 0;
|
|
33
|
+
/* 光标颜色跟随主题前景色:暗色下默认光标对比度不足,几乎看不见 */
|
|
34
|
+
caret-color: rgb(var(--color-foreground));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.richdoc-editor-host .bn-editor code {
|
|
38
|
+
border-radius: 2px;
|
|
39
|
+
padding-left: 2px;
|
|
40
|
+
padding-right: 2px;
|
|
41
|
+
padding-top: 1px;
|
|
42
|
+
padding-bottom: 1px;
|
|
43
|
+
background: rgb(var(--color-markdown-comment) / 0.3);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.richdoc-editor-host .bn-editor pre code {
|
|
47
|
+
background: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@media (max-width: 768px) {
|
|
51
|
+
.richdoc-editor-host .bn-editor {
|
|
52
|
+
padding-inline: 16px;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* 只读模式下去掉 hover 时的侧边操作按钮占位间隙 */
|
|
57
|
+
.richdoc-editor-host.richdoc-readonly .bn-side-menu {
|
|
58
|
+
display: none;
|
|
59
|
+
}
|
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
|
|
2
|
+
import React, { Suspense, lazy, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import * as febs from 'febs-browser';
|
|
4
|
+
import { Modal, Spin, Tag } from 'antd';
|
|
5
|
+
import { getFileUrl, getFilePreviewType, fetchFileBuffer, getFileExtension, FileDetailFetcher } from './previewUtils';
|
|
6
|
+
import uiToast from '../UIToast';
|
|
7
|
+
import { AbortControllerClass } from 'febs-browser/types/fetch';
|
|
8
|
+
import { destroyImagePreview, loadImagePreview } from './filetypes/imageLoader';
|
|
9
|
+
import { ImagePreview } from './filetypes/image';
|
|
10
|
+
import { VideoPreview } from './filetypes/video';
|
|
11
|
+
import { getLocalFile } from './IndexedDBUtils';
|
|
12
|
+
import type { LocalFileRecord } from './IndexedDBUtils';
|
|
13
|
+
|
|
14
|
+
import './filePreview.css'
|
|
15
|
+
import { isEditableFileType } from '../FileManager/utils/fileUtils';
|
|
16
|
+
import { WarningOutlined } from '@ant-design/icons';
|
|
17
|
+
|
|
18
|
+
const PdfPreview = lazy(() =>
|
|
19
|
+
import('./filetypes/pdf').then((module) => ({ default: module.PdfPreview }))
|
|
20
|
+
);
|
|
21
|
+
const WordPreview = lazy(() =>
|
|
22
|
+
import('./filetypes/word').then((module) => ({ default: module.WordPreview }))
|
|
23
|
+
);
|
|
24
|
+
const ExcelPreview = lazy(() =>
|
|
25
|
+
import('./filetypes/excel').then((module) => ({ default: module.ExcelPreview }))
|
|
26
|
+
);
|
|
27
|
+
const MarkdownEditor = lazy(() => import('./MarkdownEditor').then((module) => ({ default: module.MarkdownEditor })));
|
|
28
|
+
const RichDocEditor = lazy(() => import('./RichDocEditor').then((module) => ({ default: module.RichDocEditor })));
|
|
29
|
+
const ExcelEditor = lazy(() => import('./ExcelEditor').then((module) => ({ default: module.ExcelEditor })));
|
|
30
|
+
const PptPreview = lazy(() =>
|
|
31
|
+
import('./filetypes/ppt').then((module) => ({ default: module.PptPreview }))
|
|
32
|
+
);
|
|
33
|
+
const WordEditor = lazy(() => import('./WordEditor').then((module) => ({ default: module.WordEditor })));
|
|
34
|
+
const ArchivePreview = lazy(() => import('./filetypes/archive').then((module) => ({ default: module.ArchivePreview })));
|
|
35
|
+
const CadPreview = lazy(() => import('./filetypes/cad').then((module) => ({ default: module.CadPreview })));
|
|
36
|
+
|
|
37
|
+
type PreviewType = 'image' | 'pdf' | 'word' | 'ppt' | 'excel' | 'markdown' | 'richdoc' | 'video' | 'archive' | 'cad' | 'unknown';
|
|
38
|
+
|
|
39
|
+
const getPreviewFileName = (fileName: string | undefined, fileUrl: string | null, fallback: string) => {
|
|
40
|
+
if (fileName) {
|
|
41
|
+
return fileName;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let cleanUrl = fileUrl || '';
|
|
45
|
+
const queryIndex = cleanUrl.indexOf('?');
|
|
46
|
+
if (queryIndex !== -1) {
|
|
47
|
+
cleanUrl = cleanUrl.substring(0, queryIndex);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const nameFromUrl = cleanUrl.split('/').filter(Boolean).pop();
|
|
51
|
+
if (!nameFromUrl) {
|
|
52
|
+
return fallback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
return decodeURIComponent(nameFromUrl);
|
|
57
|
+
} catch {
|
|
58
|
+
return nameFromUrl;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const appendTempToken = (url: string, accessToken?: string) => {
|
|
63
|
+
if (!accessToken) {
|
|
64
|
+
return url;
|
|
65
|
+
}
|
|
66
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
67
|
+
return `${url}${separator}tempToken=${encodeURIComponent(accessToken)}`;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const EditorLoading = ({ label }: { label: string }) => (
|
|
71
|
+
<div className='flex min-h-[260px] flex-col items-center justify-center' style={{ width: '100%' }}>
|
|
72
|
+
<Spin />
|
|
73
|
+
<span style={{ marginTop: 16, color: 'rgb(var(--color-muted))' }}>正在加载{label}...</span>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
export const UIFilePreview: React.FC<{
|
|
78
|
+
fileUrl: string | null;
|
|
79
|
+
accessToken?: string;
|
|
80
|
+
visible: boolean;
|
|
81
|
+
onClose: () => void;
|
|
82
|
+
hiddenClose?: boolean; // 是否隐藏关闭按钮
|
|
83
|
+
isCreate?: boolean; // 是否为新建模式
|
|
84
|
+
editable?: boolean; // 是否为编辑模式
|
|
85
|
+
fileName?: string; // 文件名(新建模式下必须提供)
|
|
86
|
+
uploadPercent: number | undefined; // 上传进度.
|
|
87
|
+
uploadSuccess?: boolean | undefined; // 上传成功.
|
|
88
|
+
onUploadBlob?: (initialBlob: Blob | undefined, blob: Blob, fileName: string) => Promise<void>; // 编辑模式下上传回调(用于 Excel/PPTX)
|
|
89
|
+
onUploadMarkdown?: (oldContent: string, content: string, fileName: string) => Promise<void>; // 编辑模式下上传回调(用于 Markdown)
|
|
90
|
+
fileId?: string; // 文件ID,用于缓存管理(服务器文件)
|
|
91
|
+
crc32?: number; // 文件CRC32校验值,用于缓存验证
|
|
92
|
+
/** 文件详情查询函数:不传时使用项目文件接口;CRM 等场景可注入自有接口 */
|
|
93
|
+
fetchFileDetail?: FileDetailFetcher;
|
|
94
|
+
onCacheSaved?: (fileId: string) => void; // 文件缓存保存成功回调
|
|
95
|
+
// ---- 新增:本地文件 / 离线模式支持 ----
|
|
96
|
+
/** 本地文件唯一 ID(本地文件或未同步服务器文件),设置后将从 localFiles store 加载内容,不从服务器 fetch */
|
|
97
|
+
localId?: string;
|
|
98
|
+
/** 是否为仅本地存在(从未上传)*/
|
|
99
|
+
isLocalOnly?: boolean;
|
|
100
|
+
/** 是否有未同步的本地修改 */
|
|
101
|
+
hasUnsyncedChanges?: boolean;
|
|
102
|
+
/** 离线模式:true 时隐藏上传按钮,仅允许本地保存,并显示离线提示 */
|
|
103
|
+
isOffline?: boolean;
|
|
104
|
+
/** 编辑本地/离线文件时,保存(非上传)到本地的回调,更新 localFiles store 内容 */
|
|
105
|
+
onSaveLocalBlob?: (blob: Blob, fileName: string, markUnsynced?: boolean) => Promise<void>;
|
|
106
|
+
/** 编辑本地/离线 Markdown 文件时,保存(非上传)到本地的回调 */
|
|
107
|
+
onSaveLocalMarkdown?: (content: string, fileName: string, markUnsynced?: boolean) => Promise<void>;
|
|
108
|
+
}> = ({ fileUrl, accessToken, visible, isCreate, onClose, hiddenClose = false, editable = false, fileName, uploadPercent, uploadSuccess, onUploadBlob, onUploadMarkdown, fileId, crc32, fetchFileDetail, onCacheSaved, localId, isLocalOnly, hasUnsyncedChanges, isOffline, onSaveLocalBlob, onSaveLocalMarkdown }) => {
|
|
109
|
+
const [previewType, setPreviewType] = useState<PreviewType>('unknown');
|
|
110
|
+
const [previewUrl, setPreviewUrl] = useState('');
|
|
111
|
+
const [previewLoading, setPreviewLoading] = useState(false);
|
|
112
|
+
const [previewLoadingPercent, setPreviewLoadingPercent] = useState(0);
|
|
113
|
+
const [previewError, setPreviewError] = useState<string | null>(null);
|
|
114
|
+
const [markdownContent, setMarkdownContent] = useState<string>('');
|
|
115
|
+
const [richdocContent, setRichdocContent] = useState<string>('');
|
|
116
|
+
const [excelBlob, setExcelBlob] = useState<Blob | null>(null);
|
|
117
|
+
const [excelFile, setExcelFile] = useState<File | null>(null);
|
|
118
|
+
const [pptxFile, setPptxFile] = useState<File | null>(null);
|
|
119
|
+
const [wordBlob, setWordBlob] = useState<Blob | null>(null);
|
|
120
|
+
const [wordFile, setWordFile] = useState<File | null>(null);
|
|
121
|
+
const [archiveFile, setArchiveFile] = useState<File | null>(null);
|
|
122
|
+
const [cadFile, setCadFile] = useState<File | null>(null);
|
|
123
|
+
const [pdfFile, setPdfFile] = useState<File | null>(null);
|
|
124
|
+
const [loadedLocalFile, setLoadedLocalFile] = useState<LocalFileRecord | null>(null);
|
|
125
|
+
|
|
126
|
+
const containerImageRef = useRef<HTMLImageElement | null>(null);
|
|
127
|
+
|
|
128
|
+
const supportedPreviewTypes: PreviewType[] = ['image', 'pdf', 'word', 'ppt', 'excel', 'markdown', 'richdoc', 'video', 'archive', 'cad'];
|
|
129
|
+
const abortControllerRef = useRef<AbortControllerClass>(new febs.net.AbortController());
|
|
130
|
+
const isAbortedRef = useRef(false);
|
|
131
|
+
|
|
132
|
+
// 用 ref 跟踪这些"状态标记"属性,避免它们的变化(如保存/上传后更新标记)
|
|
133
|
+
// 触发 loadFileContent useEffect 重新执行,导致文件重新加载、编辑器 remount、画面闪动。
|
|
134
|
+
// 这些值只在打开文件时需要读取最新值,不需要在值变化时重新加载文件内容。
|
|
135
|
+
const localIdRef = useRef(localId);
|
|
136
|
+
const isLocalOnlyRef = useRef(isLocalOnly);
|
|
137
|
+
const hasUnsyncedChangesRef = useRef(hasUnsyncedChanges);
|
|
138
|
+
localIdRef.current = localId;
|
|
139
|
+
isLocalOnlyRef.current = isLocalOnly;
|
|
140
|
+
hasUnsyncedChangesRef.current = hasUnsyncedChanges;
|
|
141
|
+
// 详情查询函数通过 ref 传递,避免外部内联函数变化触发文件重新加载
|
|
142
|
+
const fetchFileDetailRef = useRef(fetchFileDetail);
|
|
143
|
+
fetchFileDetailRef.current = fetchFileDetail;
|
|
144
|
+
|
|
145
|
+
// 阻止后退.
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
const preventBack = function () {
|
|
148
|
+
window.history.go(1); // 阻止后退,回到当前页面
|
|
149
|
+
}
|
|
150
|
+
window.history.pushState(null, null as any, document.URL);
|
|
151
|
+
window.addEventListener('popstate', preventBack);
|
|
152
|
+
|
|
153
|
+
return () => { window.removeEventListener('popstate', preventBack) };
|
|
154
|
+
}, []);
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (!visible) return;
|
|
159
|
+
|
|
160
|
+
// 清除所有编辑器相关的 blob/内容状态,防止切换文件时残留旧数据
|
|
161
|
+
setWordBlob(null);
|
|
162
|
+
setExcelBlob(null);
|
|
163
|
+
setPptxFile(null);
|
|
164
|
+
setMarkdownContent('');
|
|
165
|
+
setRichdocContent('');
|
|
166
|
+
setLoadedLocalFile(null);
|
|
167
|
+
|
|
168
|
+
const loadFileContent = async () => {
|
|
169
|
+
// 读取 ref 中的最新值(避免将这些状态标记作为 useEffect 依赖)
|
|
170
|
+
const currentLocalId = localIdRef.current;
|
|
171
|
+
// =============== 情况 1:有 localId(本地新建文件 或 服务器文件的未同步修改)===============
|
|
172
|
+
const filename = fileName ? fileName : fileUrl?.substring(fileUrl?.lastIndexOf('/')+1 || 0);
|
|
173
|
+
if (currentLocalId && editable && filename) {
|
|
174
|
+
const type = getFilePreviewType(filename);
|
|
175
|
+
if (!['ppt', 'excel', 'markdown', 'word', 'richdoc'].includes(type)) {
|
|
176
|
+
uiToast.warning('当前文件类型不支持本地编辑');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
setPreviewType(type);
|
|
180
|
+
setPreviewError(null);
|
|
181
|
+
setPreviewLoading(true);
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const local = await getLocalFile(currentLocalId);
|
|
185
|
+
if (!local) {
|
|
186
|
+
setPreviewLoading(false);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
setLoadedLocalFile(local);
|
|
190
|
+
|
|
191
|
+
// 如果本地记录有内容(用户之前保存过),直接加载本地内容
|
|
192
|
+
if (local.content && ((typeof local.content === 'string' && local.content.length > 0) ||
|
|
193
|
+
(typeof local.content !== 'string' && local.content.byteLength > 0))) {
|
|
194
|
+
if (type === 'markdown') {
|
|
195
|
+
setMarkdownContent(typeof local.content === 'string' ? local.content : '');
|
|
196
|
+
} else if (type === 'richdoc') {
|
|
197
|
+
setRichdocContent(typeof local.content === 'string' ? local.content : '');
|
|
198
|
+
} else if (type === 'word') {
|
|
199
|
+
const buf = typeof local.content !== 'string' ? local.content : new ArrayBuffer(0);
|
|
200
|
+
const blob = new Blob([buf], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
|
|
201
|
+
setWordBlob(blob);
|
|
202
|
+
setWordFile(new File([blob], filename, { type: blob.type }));
|
|
203
|
+
} else if (type === 'excel') {
|
|
204
|
+
const buf = typeof local.content !== 'string' ? local.content : new ArrayBuffer(0);
|
|
205
|
+
const blob = new Blob([buf], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
206
|
+
setExcelBlob(blob);
|
|
207
|
+
setExcelFile(new File([blob], filename, { type: blob.type }));
|
|
208
|
+
} else if (type === 'ppt') {
|
|
209
|
+
const buf = typeof local.content !== 'string' ? local.content : new ArrayBuffer(0);
|
|
210
|
+
const pptxBlob = new Blob([buf], { type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' });
|
|
211
|
+
setPptxFile(new File([pptxBlob], filename, { type: pptxBlob.type }));
|
|
212
|
+
}
|
|
213
|
+
setPreviewLoading(false);
|
|
214
|
+
return; // 已加载本地内容,结束
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// 本地记录存在但内容为空(首次编辑已上传文件),继续尝试从服务器加载
|
|
218
|
+
// 如果 fileUrl 存在,会在下面的逻辑中处理
|
|
219
|
+
setPreviewLoading(false);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
console.error('加载本地文件失败:', err);
|
|
222
|
+
setPreviewLoading(false);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// =============== 情况 2:纯新建模式(无 localId 且无 fileUrl)===============
|
|
227
|
+
if (!fileUrl && !currentLocalId && filename && editable) {
|
|
228
|
+
const type = getFilePreviewType(filename);
|
|
229
|
+
if (['ppt', 'excel', 'markdown', 'word', 'richdoc'].includes(type)) {
|
|
230
|
+
setPreviewType(type);
|
|
231
|
+
setPreviewError(null);
|
|
232
|
+
setPreviewLoading(false);
|
|
233
|
+
} else {
|
|
234
|
+
uiToast.warning('当前文件类型不支持新建');
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// =============== 情况 3:从服务器加载文件内容 ===============
|
|
240
|
+
// fileId 可选(如历史版本预览无 fileId),仅 fileUrl 必需;fileId 为空时跳过缓存
|
|
241
|
+
if (!fileUrl) return;
|
|
242
|
+
|
|
243
|
+
// 防御性守卫:当有 crc32(来自文件列表)但 fileId 尚未就绪时,跳过本次调用。
|
|
244
|
+
// 场景:handlePreview 中 React 18 的 useState 批处理 + react-router 的 setSearchParams
|
|
245
|
+
// 可能导致多次渲染。首次渲染时 fileUrl/crc32 已设置但 fileId(依赖 state.files 的更新)
|
|
246
|
+
// 可能尚未就绪,此时 fetchFileBuffer 会跳过 getDetail 直接 fetch,造成浪费的网络请求。
|
|
247
|
+
// 当下一次渲染 fileId 就绪后,useEffect 会重新执行,届时流程正确。
|
|
248
|
+
if (crc32 != null && !fileId) {
|
|
249
|
+
console.log('[UIFilePreview] crc32 已就绪但 fileId 尚未就绪,等待下次渲染...');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 如果有 localId,本地内容为空时,也允许从服务器加载
|
|
254
|
+
const previewFileName = filename || fileUrl;
|
|
255
|
+
const type = getFilePreviewType(previewFileName);
|
|
256
|
+
|
|
257
|
+
if (type === 'unknown') {
|
|
258
|
+
setPreviewType(type);
|
|
259
|
+
uiToast.warning('当前文件类型不支持预览');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
setPreviewType(type);
|
|
264
|
+
setPreviewUrl('');
|
|
265
|
+
setPreviewError(null);
|
|
266
|
+
setExcelBlob(null);
|
|
267
|
+
setExcelFile(null);
|
|
268
|
+
setPptxFile(null);
|
|
269
|
+
setWordBlob(null);
|
|
270
|
+
setWordFile(null);
|
|
271
|
+
setArchiveFile(null);
|
|
272
|
+
setCadFile(null);
|
|
273
|
+
setPdfFile(null);
|
|
274
|
+
setMarkdownContent('');
|
|
275
|
+
setRichdocContent('');
|
|
276
|
+
|
|
277
|
+
destroyImagePreview(containerImageRef);
|
|
278
|
+
|
|
279
|
+
setPreviewLoadingPercent(0);
|
|
280
|
+
setPreviewLoading(true);
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
const url = getFileUrl(fileUrl);
|
|
284
|
+
if (!url) {
|
|
285
|
+
uiToast.error('文件资源路径不可用,无法预览');
|
|
286
|
+
setPreviewLoading(false);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 仅 video 类型在 fetch 前就设置 previewUrl,因为 <video> 组件需要 src 来拉流;
|
|
291
|
+
// 其他类型(image/pdf/word/excel/ppt/archive/cad/markdown)的内容均来自 fetchFileBuffer 的结果,
|
|
292
|
+
// 不应在 fetch 之前就把 fileUrl 暴露给渲染层,否则某些组件挂载时会自发请求(导致"先请求文件资源再请求 detail"的竞态)。
|
|
293
|
+
if (type === 'video') {
|
|
294
|
+
setPreviewUrl(appendTempToken(url, accessToken));
|
|
295
|
+
setPreviewLoading(false);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const buffer = await fetchFileBuffer(fileUrl, accessToken, abortControllerRef.current, setPreviewLoadingPercent, fileId, crc32, fetchFileDetailRef.current);
|
|
300
|
+
|
|
301
|
+
if (fileId && onCacheSaved) {
|
|
302
|
+
onCacheSaved(fileId);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (type === 'image') {
|
|
306
|
+
await loadImagePreview(buffer, containerImageRef);
|
|
307
|
+
} else if (type === 'pdf') {
|
|
308
|
+
const blob = new Blob([buffer.buffer], {
|
|
309
|
+
type: buffer.headers.get('Content-Type') || 'application/pdf',
|
|
310
|
+
});
|
|
311
|
+
setPdfFile(new File([blob], getPreviewFileName(filename, fileUrl, '预览.pdf'), { type: blob.type }));
|
|
312
|
+
} else if (type === 'word') {
|
|
313
|
+
const wordBlob = new Blob([buffer.buffer], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
|
|
314
|
+
setWordBlob(wordBlob);
|
|
315
|
+
setWordFile(new File([wordBlob], getPreviewFileName(filename, fileUrl, '预览.docx'), { type: wordBlob.type }));
|
|
316
|
+
} else if (type === 'excel') {
|
|
317
|
+
const excelBlob = new Blob([buffer.buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
318
|
+
setExcelBlob(excelBlob);
|
|
319
|
+
setExcelFile(new File([excelBlob], getPreviewFileName(filename, fileUrl, '预览.xlsx'), { type: excelBlob.type }));
|
|
320
|
+
} else if (type === 'ppt') {
|
|
321
|
+
const pptxBlob = new Blob([buffer.buffer], { type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' });
|
|
322
|
+
setPptxFile(new File([pptxBlob], getPreviewFileName(filename, fileUrl, '预览.pptx'), { type: pptxBlob.type }));
|
|
323
|
+
} else if (type === 'markdown') {
|
|
324
|
+
const textDecoder = new TextDecoder('utf-8');
|
|
325
|
+
const content = textDecoder.decode(buffer.buffer);
|
|
326
|
+
setMarkdownContent(content);
|
|
327
|
+
} else if (type === 'richdoc') {
|
|
328
|
+
const textDecoder = new TextDecoder('utf-8');
|
|
329
|
+
const content = textDecoder.decode(buffer.buffer);
|
|
330
|
+
setRichdocContent(content);
|
|
331
|
+
} else if (type === 'archive') {
|
|
332
|
+
const blob = new Blob([buffer.buffer], {
|
|
333
|
+
type: buffer.headers.get('Content-Type') || 'application/octet-stream',
|
|
334
|
+
});
|
|
335
|
+
setArchiveFile(new File([blob], getPreviewFileName(filename, fileUrl, '预览.zip'), { type: blob.type }));
|
|
336
|
+
} else if (type === 'cad') {
|
|
337
|
+
const blob = new Blob([buffer.buffer], {
|
|
338
|
+
type: 'application/octet-stream',
|
|
339
|
+
});
|
|
340
|
+
setCadFile(new File([blob], getPreviewFileName(filename, fileUrl, '预览.dwg'), { type: 'application/octet-stream' }));
|
|
341
|
+
}
|
|
342
|
+
} catch (error) {
|
|
343
|
+
if (isAbortedRef.current) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
console.error(error);
|
|
347
|
+
const rawMsg = (error as any)?.message || '';
|
|
348
|
+
const errorName = (error as any)?.name || '';
|
|
349
|
+
// 展示原始错误信息(如 "Network request failed")及请求 URL,方便排查。
|
|
350
|
+
// 注意:CORS 被拦截时 JS 无法读取 HTTP 状态码(如 404),该信息仅在浏览器控制台可见。
|
|
351
|
+
const detailLines: string[] = [];
|
|
352
|
+
detailLines.push('文件预览失败');
|
|
353
|
+
if (errorName) detailLines.push(`错误类型:${errorName}`);
|
|
354
|
+
if (rawMsg) detailLines.push(`错误信息:${rawMsg}`);
|
|
355
|
+
setPreviewError(detailLines.join('\n'));
|
|
356
|
+
} finally {
|
|
357
|
+
setPreviewLoading(false);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
loadFileContent().catch(() => {});
|
|
362
|
+
|
|
363
|
+
return () => {
|
|
364
|
+
isAbortedRef.current = true;
|
|
365
|
+
abortControllerRef.current.abort();
|
|
366
|
+
abortControllerRef.current = new febs.net.AbortController();
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
}, [fileUrl, visible, accessToken, editable, fileName, fileId, crc32]);
|
|
370
|
+
|
|
371
|
+
const handleClose = () => {
|
|
372
|
+
// console.log('[UIFilePreview] handleClose: aborting request');
|
|
373
|
+
isAbortedRef.current = true;
|
|
374
|
+
abortControllerRef.current.abort();
|
|
375
|
+
abortControllerRef.current = new febs.net.AbortController();
|
|
376
|
+
// console.log('[UIFilePreview] handleClose: abortController reset');
|
|
377
|
+
setPreviewLoading(false);
|
|
378
|
+
setPreviewUrl('');
|
|
379
|
+
setExcelBlob(null);
|
|
380
|
+
setExcelFile(null);
|
|
381
|
+
setPptxFile(null);
|
|
382
|
+
setWordBlob(null);
|
|
383
|
+
setWordFile(null);
|
|
384
|
+
setArchiveFile(null);
|
|
385
|
+
setCadFile(null);
|
|
386
|
+
setPdfFile(null);
|
|
387
|
+
setPreviewError(null);
|
|
388
|
+
setMarkdownContent('');
|
|
389
|
+
setRichdocContent('');
|
|
390
|
+
|
|
391
|
+
onClose();
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
return (
|
|
395
|
+
<Modal
|
|
396
|
+
// title={previewFileName ? `预览:${previewFileName}` : '文件预览'}
|
|
397
|
+
open={visible}
|
|
398
|
+
closeIcon={hiddenClose ? null : (
|
|
399
|
+
previewType === 'markdown'
|
|
400
|
+
|| previewType === 'richdoc'
|
|
401
|
+
|| (previewType === 'word' && editable)
|
|
402
|
+
|| (previewType === 'excel' && editable)
|
|
403
|
+
? null
|
|
404
|
+
: undefined)
|
|
405
|
+
}
|
|
406
|
+
onCancel={handleClose}
|
|
407
|
+
footer={null}
|
|
408
|
+
className={"ant-modal-nopadding ant-modal-fullscreen" + (previewType == 'ppt' ? ' ant-modal-ppt' : '')}
|
|
409
|
+
styles={{ body: { padding: 0, justifyContent: 'center', display: 'flex' } }}
|
|
410
|
+
destroyOnHidden
|
|
411
|
+
keyboard={false}
|
|
412
|
+
transitionName={hiddenClose ? 'none' : undefined}
|
|
413
|
+
>
|
|
414
|
+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: (previewType === 'excel' && !editable) ? 'flex-start' : 'center', background: (previewType === 'excel' && !editable) ? '#ffffff' : 'rgb(var(--color-background))', minHeight: '100dvh', position: 'relative' }}>
|
|
415
|
+
|
|
416
|
+
{previewType === 'word' && editable && (
|
|
417
|
+
<Suspense fallback={<EditorLoading label="Word 编辑器" />}>
|
|
418
|
+
<WordEditor
|
|
419
|
+
hiddenClose={hiddenClose}
|
|
420
|
+
isCreate={isCreate}
|
|
421
|
+
visible={previewType === 'word' && visible}
|
|
422
|
+
fileName={getPreviewFileName(fileName, fileUrl, '预览.docx')}
|
|
423
|
+
initialBlob={wordBlob || undefined}
|
|
424
|
+
onClose={handleClose}
|
|
425
|
+
readOnly={!editable}
|
|
426
|
+
onUpload={editable ? onUploadBlob : undefined}
|
|
427
|
+
uploadPercent={uploadPercent}
|
|
428
|
+
isOffline={isOffline}
|
|
429
|
+
isLocalOnly={isLocalOnly}
|
|
430
|
+
hasUnsyncedChanges={hasUnsyncedChanges}
|
|
431
|
+
onSaveLocalBlob={onSaveLocalBlob}
|
|
432
|
+
/>
|
|
433
|
+
</Suspense>
|
|
434
|
+
)}
|
|
435
|
+
{previewType === 'word' && !editable && (
|
|
436
|
+
<Suspense
|
|
437
|
+
fallback={
|
|
438
|
+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 240 }}>
|
|
439
|
+
加载Word预览组件...
|
|
440
|
+
</div>
|
|
441
|
+
}
|
|
442
|
+
>
|
|
443
|
+
<WordPreview file={wordFile} />
|
|
444
|
+
</Suspense>
|
|
445
|
+
)}
|
|
446
|
+
{/* <PptPreview containerRef={containerPptRef} type={previewType} /> */}
|
|
447
|
+
{previewType === 'excel' && editable && (
|
|
448
|
+
<Suspense fallback={<EditorLoading label="Excel 编辑器" />}>
|
|
449
|
+
<ExcelEditor
|
|
450
|
+
hiddenClose={hiddenClose}
|
|
451
|
+
visible={previewType === 'excel' && visible}
|
|
452
|
+
fileName={getPreviewFileName(fileName, fileUrl, '预览.xlsx')}
|
|
453
|
+
initialBlob={excelBlob || undefined}
|
|
454
|
+
isCreate={isCreate}
|
|
455
|
+
onClose={handleClose}
|
|
456
|
+
readOnly={!editable}
|
|
457
|
+
onUpload={editable ? onUploadBlob : undefined}
|
|
458
|
+
uploadPercent={uploadPercent}
|
|
459
|
+
uploadSuccess={uploadSuccess}
|
|
460
|
+
isOffline={isOffline}
|
|
461
|
+
isLocalOnly={isLocalOnly}
|
|
462
|
+
hasUnsyncedChanges={hasUnsyncedChanges}
|
|
463
|
+
onSaveLocalBlob={onSaveLocalBlob}
|
|
464
|
+
/>
|
|
465
|
+
</Suspense>
|
|
466
|
+
)}
|
|
467
|
+
{previewType === 'excel' && !editable && (
|
|
468
|
+
<Suspense
|
|
469
|
+
fallback={
|
|
470
|
+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 240 }}>
|
|
471
|
+
加载Excel预览组件...
|
|
472
|
+
</div>
|
|
473
|
+
}
|
|
474
|
+
>
|
|
475
|
+
<ExcelPreview file={excelFile} />
|
|
476
|
+
</Suspense>
|
|
477
|
+
)}
|
|
478
|
+
{previewType === 'pdf' && (
|
|
479
|
+
<Suspense
|
|
480
|
+
fallback={
|
|
481
|
+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 240 }}>
|
|
482
|
+
加载PDF预览组件...
|
|
483
|
+
</div>
|
|
484
|
+
}
|
|
485
|
+
>
|
|
486
|
+
<PdfPreview
|
|
487
|
+
file={pdfFile}
|
|
488
|
+
progressKey={fileId || (fileName ? `name:${fileName}` : undefined)}
|
|
489
|
+
/>
|
|
490
|
+
</Suspense>
|
|
491
|
+
)}
|
|
492
|
+
<ImagePreview containerRef={containerImageRef} type={previewType} />
|
|
493
|
+
<VideoPreview previewUrl={previewUrl} type={previewType} />
|
|
494
|
+
{previewType === 'archive' && (
|
|
495
|
+
<Suspense fallback={<EditorLoading label="压缩包预览器" />}>
|
|
496
|
+
<ArchivePreview file={archiveFile} />
|
|
497
|
+
</Suspense>
|
|
498
|
+
)}
|
|
499
|
+
{previewType === 'cad' && (
|
|
500
|
+
<Suspense fallback={<EditorLoading label="CAD 图纸预览器" />}>
|
|
501
|
+
<CadPreview file={cadFile} />
|
|
502
|
+
</Suspense>
|
|
503
|
+
)}
|
|
504
|
+
{previewType === 'markdown' && (
|
|
505
|
+
<Suspense fallback={<EditorLoading label="Markdown 编辑器" />}>
|
|
506
|
+
<MarkdownEditor
|
|
507
|
+
hiddenClose={hiddenClose}
|
|
508
|
+
value={markdownContent}
|
|
509
|
+
onClose={handleClose}
|
|
510
|
+
readOnly={!editable}
|
|
511
|
+
isCreate={isCreate}
|
|
512
|
+
visible={previewType === 'markdown' && visible}
|
|
513
|
+
defaultPreviewMode={!editable}
|
|
514
|
+
onUpload={editable ? onUploadMarkdown : undefined}
|
|
515
|
+
fileName={getPreviewFileName(fileName, fileUrl, '预览.md')}
|
|
516
|
+
uploadPercent={uploadPercent}
|
|
517
|
+
uploadSuccess={uploadSuccess}
|
|
518
|
+
isOffline={isOffline}
|
|
519
|
+
isLocalOnly={isLocalOnly}
|
|
520
|
+
hasUnsyncedChanges={hasUnsyncedChanges}
|
|
521
|
+
onSaveLocalMarkdown={onSaveLocalMarkdown}
|
|
522
|
+
/>
|
|
523
|
+
</Suspense>
|
|
524
|
+
)}
|
|
525
|
+
{previewType === 'richdoc' && (
|
|
526
|
+
<Suspense fallback={<EditorLoading label="文档编辑器" />}>
|
|
527
|
+
<RichDocEditor
|
|
528
|
+
hiddenClose={hiddenClose}
|
|
529
|
+
value={richdocContent}
|
|
530
|
+
onClose={handleClose}
|
|
531
|
+
readOnly={!editable}
|
|
532
|
+
isCreate={isCreate}
|
|
533
|
+
visible={previewType === 'richdoc' && visible}
|
|
534
|
+
onUpload={editable ? onUploadMarkdown : undefined}
|
|
535
|
+
fileName={getPreviewFileName(fileName, fileUrl, '预览.rdoc')}
|
|
536
|
+
uploadPercent={uploadPercent}
|
|
537
|
+
uploadSuccess={uploadSuccess}
|
|
538
|
+
isOffline={isOffline}
|
|
539
|
+
isLocalOnly={isLocalOnly}
|
|
540
|
+
hasUnsyncedChanges={hasUnsyncedChanges}
|
|
541
|
+
onSaveLocalMarkdown={onSaveLocalMarkdown}
|
|
542
|
+
/>
|
|
543
|
+
</Suspense>
|
|
544
|
+
)}
|
|
545
|
+
{previewType === 'ppt' && (
|
|
546
|
+
<Suspense
|
|
547
|
+
fallback={
|
|
548
|
+
<div style={{ width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 240 }}>
|
|
549
|
+
加载PPT预览组件...
|
|
550
|
+
</div>
|
|
551
|
+
}
|
|
552
|
+
>
|
|
553
|
+
<PptPreview file={pptxFile} />
|
|
554
|
+
</Suspense>
|
|
555
|
+
)}
|
|
556
|
+
|
|
557
|
+
{previewLoading ? (
|
|
558
|
+
<div style={{
|
|
559
|
+
width: '100%',
|
|
560
|
+
display: 'flex',
|
|
561
|
+
flexDirection: 'column',
|
|
562
|
+
justifyContent: 'center',
|
|
563
|
+
alignItems: 'center',
|
|
564
|
+
position: 'absolute',
|
|
565
|
+
top: 0,
|
|
566
|
+
left: 0,
|
|
567
|
+
right: 0,
|
|
568
|
+
bottom: 0,
|
|
569
|
+
background: 'rgb(var(--color-surface))',
|
|
570
|
+
zIndex: 10
|
|
571
|
+
}}>
|
|
572
|
+
<Spin />
|
|
573
|
+
<span style={{ marginTop: 16, color: 'rgb(var(--color-muted))' }}>正在加载预览内容 {previewLoadingPercent}% ...</span>
|
|
574
|
+
</div>
|
|
575
|
+
) : previewError ? (
|
|
576
|
+
<div style={{
|
|
577
|
+
color: '#ff4d4f',
|
|
578
|
+
width: '100%',
|
|
579
|
+
maxWidth: 640,
|
|
580
|
+
display: 'flex',
|
|
581
|
+
flexDirection: 'column',
|
|
582
|
+
gap: 12,
|
|
583
|
+
justifyContent: 'center',
|
|
584
|
+
alignItems: 'center',
|
|
585
|
+
position: 'absolute',
|
|
586
|
+
top: 0,
|
|
587
|
+
left: 0,
|
|
588
|
+
right: 0,
|
|
589
|
+
bottom: 0,
|
|
590
|
+
background: 'rgb(var(--color-surface))',
|
|
591
|
+
zIndex: 100,
|
|
592
|
+
padding: 24,
|
|
593
|
+
textAlign: 'center',
|
|
594
|
+
whiteSpace: 'pre-line',
|
|
595
|
+
wordBreak: 'break-all',
|
|
596
|
+
}}>
|
|
597
|
+
<WarningOutlined style={{ fontSize: 40, color: '#ff4d4f' }} />
|
|
598
|
+
<span style={{ fontSize: 16, lineHeight: 1.8 }}>{previewError}</span>
|
|
599
|
+
</div>
|
|
600
|
+
) : previewType === 'image' || previewType === 'video' ? (
|
|
601
|
+
<></>
|
|
602
|
+
) : (
|
|
603
|
+
supportedPreviewTypes.includes(previewType) ? null : (
|
|
604
|
+
<div style={{ padding: 24, color: '#555' }}>
|
|
605
|
+
<WarningOutlined style={{ color: '#faad14' }} /> 当前文件类型不支持预览。
|
|
606
|
+
</div>)
|
|
607
|
+
)}
|
|
608
|
+
</div>
|
|
609
|
+
</Modal>
|
|
610
|
+
)
|
|
611
|
+
};
|