@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,531 @@
|
|
|
1
|
+
import { AuthorizationHandler, ResponseCode } from "../../api/_base";
|
|
2
|
+
import { AbortControllerClass } from "febs-browser/types/fetch";
|
|
3
|
+
import * as febs from 'febs-browser';
|
|
4
|
+
import { FileExcelFilled, FileImageFilled, FileMarkdownFilled, FileOutlined, FilePdfFilled, FilePptFilled, FileWordFilled, FileZipFilled, FolderFilled, FolderOpenFilled, VideoCameraFilled, FileTextFilled, BookFilled } from "@ant-design/icons";
|
|
5
|
+
import uiToast from "../UIToast";
|
|
6
|
+
import { UIToastSingle } from "../UIToastSingle";
|
|
7
|
+
import { CacheFileContent, CacheFileMeta } from "../../utils/CacheFileContent";
|
|
8
|
+
import { API } from "../../api/index";
|
|
9
|
+
|
|
10
|
+
export const ARCHIVE_FILE_EXTENSIONS = [
|
|
11
|
+
'zip',
|
|
12
|
+
'zipx',
|
|
13
|
+
'7z',
|
|
14
|
+
'rar',
|
|
15
|
+
'tar',
|
|
16
|
+
'gz',
|
|
17
|
+
'gzip',
|
|
18
|
+
'tgz',
|
|
19
|
+
'bz2',
|
|
20
|
+
'bzip2',
|
|
21
|
+
'tbz',
|
|
22
|
+
'tbz2',
|
|
23
|
+
'xz',
|
|
24
|
+
'txz',
|
|
25
|
+
'lzma',
|
|
26
|
+
'zst',
|
|
27
|
+
'tzst',
|
|
28
|
+
'cab',
|
|
29
|
+
'ar',
|
|
30
|
+
'cpio',
|
|
31
|
+
'iso',
|
|
32
|
+
'xar',
|
|
33
|
+
'lha',
|
|
34
|
+
'lzh',
|
|
35
|
+
'jar',
|
|
36
|
+
'war',
|
|
37
|
+
'ear',
|
|
38
|
+
'apk',
|
|
39
|
+
'cbz',
|
|
40
|
+
'cbr',
|
|
41
|
+
] as const;
|
|
42
|
+
|
|
43
|
+
export const CAD_FILE_EXTENSIONS = [
|
|
44
|
+
'dwg',
|
|
45
|
+
'dxf',
|
|
46
|
+
'dwf',
|
|
47
|
+
'dwfx',
|
|
48
|
+
'xps',
|
|
49
|
+
'oxps',
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
export const getFileExtension = (fileName: string) => {
|
|
53
|
+
let cleanFileName = fileName;
|
|
54
|
+
|
|
55
|
+
if (/^https?:\/\//i.test(fileName)) {
|
|
56
|
+
try {
|
|
57
|
+
const url = new URL(fileName);
|
|
58
|
+
cleanFileName = url.pathname;
|
|
59
|
+
} catch {
|
|
60
|
+
cleanFileName = fileName.split(/[?#]/)[0] || '';
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
const queryIndex = fileName.indexOf('?');
|
|
64
|
+
if (queryIndex !== -1) {
|
|
65
|
+
cleanFileName = fileName.substring(0, queryIndex);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const extension = cleanFileName.split('.').pop()?.toLowerCase() || '';
|
|
70
|
+
return extension;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const getFileUrl = (fileResourcePath: string) => {
|
|
74
|
+
if (!fileResourcePath) {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const lastSlashIndex = fileResourcePath.lastIndexOf('/');
|
|
79
|
+
if (lastSlashIndex !== -1) {
|
|
80
|
+
let filename = fileResourcePath.substring(lastSlashIndex + 1);
|
|
81
|
+
fileResourcePath = fileResourcePath.substring(0, lastSlashIndex + 1);
|
|
82
|
+
filename = encodeURIComponent(filename);
|
|
83
|
+
fileResourcePath = `${fileResourcePath}${filename}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (/^https?:\/\//i.test(fileResourcePath)) {
|
|
87
|
+
return fileResourcePath;
|
|
88
|
+
}
|
|
89
|
+
if (fileResourcePath.startsWith('/')) {
|
|
90
|
+
return `${import.meta.env.VITE_API_BASE}${fileResourcePath}`;
|
|
91
|
+
}
|
|
92
|
+
return `${import.meta.env.VITE_API_BASE}/${fileResourcePath}`;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const getFilePreviewType = (fileName: string) => {
|
|
96
|
+
if (!fileName || fileName.length === 0) {
|
|
97
|
+
return 'unknown' as const;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const extension = getFileExtension(fileName);
|
|
101
|
+
const mime = '';
|
|
102
|
+
|
|
103
|
+
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'].includes(extension) || mime.startsWith('image/')) {
|
|
104
|
+
return 'image' as const;
|
|
105
|
+
}
|
|
106
|
+
if (extension === 'pdf' || mime.includes('pdf')) {
|
|
107
|
+
return 'pdf' as const;
|
|
108
|
+
}
|
|
109
|
+
if (['doc', 'docx', 'dot', 'dotx'].includes(extension) || mime.includes('word') || mime.includes('msword')) {
|
|
110
|
+
return 'word' as const;
|
|
111
|
+
}
|
|
112
|
+
if (['ppt', 'pptx', 'pps', 'ppsx'].includes(extension) || mime.includes('powerpoint') || mime.includes('presentation')) {
|
|
113
|
+
return 'ppt' as const;
|
|
114
|
+
}
|
|
115
|
+
if (['xls', 'xlsx', 'csv', 'xlsm', 'xlsb'].includes(extension) || mime.includes('excel') || mime.includes('spreadsheet')) {
|
|
116
|
+
return 'excel' as const;
|
|
117
|
+
}
|
|
118
|
+
if (['md', 'markdown'].includes(extension) || mime.includes('markdown')) {
|
|
119
|
+
return 'markdown' as const;
|
|
120
|
+
}
|
|
121
|
+
if (extension === 'rdoc') {
|
|
122
|
+
return 'richdoc' as const;
|
|
123
|
+
}
|
|
124
|
+
if (['mp4', 'mov', 'avi', 'mkv', 'webm', 'flv', 'wmv', 'mpeg', 'ogg'].includes(extension) || mime.startsWith('video/')) {
|
|
125
|
+
return 'video' as const;
|
|
126
|
+
}
|
|
127
|
+
if ((ARCHIVE_FILE_EXTENSIONS as readonly string[]).includes(extension)) {
|
|
128
|
+
return 'archive' as const;
|
|
129
|
+
}
|
|
130
|
+
if ((CAD_FILE_EXTENSIONS as readonly string[]).includes(extension)) {
|
|
131
|
+
return 'cad' as const;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// try {
|
|
135
|
+
// const url = new URL(fileName, 'http://localhost');
|
|
136
|
+
// const pathname = url.pathname;
|
|
137
|
+
// const urlExtension = pathname.split('/').pop()?.split('.').pop()?.toLowerCase();
|
|
138
|
+
// if (urlExtension && (CAD_FILE_EXTENSIONS as readonly string[]).includes(urlExtension)) {
|
|
139
|
+
// return 'cad' as const;
|
|
140
|
+
// }
|
|
141
|
+
// } catch (_) {
|
|
142
|
+
// // ignore
|
|
143
|
+
// }
|
|
144
|
+
|
|
145
|
+
return 'unknown' as const;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 获取文件图标
|
|
150
|
+
* 根据文件类型和扩展名返回对应的图标组件
|
|
151
|
+
* @param record - 文件记录对象
|
|
152
|
+
* @param size - 图标大小,默认22px
|
|
153
|
+
* @returns 图标组件
|
|
154
|
+
*/
|
|
155
|
+
export const getFileIcon = ({
|
|
156
|
+
fileName,
|
|
157
|
+
fileType,
|
|
158
|
+
isExpanded = false,
|
|
159
|
+
isSecure = false,
|
|
160
|
+
isVirtualContractFolder = false,
|
|
161
|
+
isContractSubfolder = false,
|
|
162
|
+
isContractTagFolder = false,
|
|
163
|
+
contractSigned,
|
|
164
|
+
size = 22
|
|
165
|
+
}: {
|
|
166
|
+
fileName: string,
|
|
167
|
+
fileType: string | 'folder',
|
|
168
|
+
isExpanded?: boolean,
|
|
169
|
+
isSecure?: boolean,
|
|
170
|
+
isVirtualContractFolder?: boolean,
|
|
171
|
+
isContractSubfolder?: boolean,
|
|
172
|
+
isContractTagFolder?: boolean,
|
|
173
|
+
contractSigned?: boolean,
|
|
174
|
+
size?: number
|
|
175
|
+
}) => {
|
|
176
|
+
const iconStyle = { fontSize: size, width: size, height: size };
|
|
177
|
+
|
|
178
|
+
// 文件夹图标:展开状态显示打开文件夹,否则显示关闭文件夹
|
|
179
|
+
if (fileType === 'folder') {
|
|
180
|
+
if (isVirtualContractFolder || isContractSubfolder || isContractTagFolder) {
|
|
181
|
+
// 未签约的合同子文件夹使用灰色弱化显示(虚拟"合同"根文件夹与分类标签文件夹不受影响)
|
|
182
|
+
const contractColor = isContractSubfolder && contractSigned === false ? '#9ca3af' : '#367f12';
|
|
183
|
+
return isExpanded
|
|
184
|
+
? <FolderOpenFilled style={{ ...iconStyle, color: contractColor }} />
|
|
185
|
+
: <FolderFilled style={{ ...iconStyle, color: contractColor }} />;
|
|
186
|
+
}
|
|
187
|
+
return isExpanded
|
|
188
|
+
? <FolderOpenFilled style={{ ...iconStyle, color: isSecure ? 'rgb(240 100 80)' : '#1890ff' }} />
|
|
189
|
+
: <FolderFilled style={{ ...iconStyle, color: isSecure ? 'rgb(240 100 80)' : '#1890ff' }} />;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const extension = getFileExtension(fileName);
|
|
193
|
+
const mime = fileType?.toLowerCase() || '';
|
|
194
|
+
|
|
195
|
+
// 根据扩展名或MIME类型返回对应图标
|
|
196
|
+
if (extension === 'pdf' || mime.includes('pdf')) {
|
|
197
|
+
return <FilePdfFilled style={{ ...iconStyle, color: '#e53935' }} />;
|
|
198
|
+
}
|
|
199
|
+
if (['doc', 'docx', 'dot', 'dotx'].includes(extension) || mime.includes('word') || mime.includes('msword')) {
|
|
200
|
+
return <FileWordFilled style={{ ...iconStyle, color: '#1e88e5' }} />;
|
|
201
|
+
}
|
|
202
|
+
if (['ppt', 'pptx', 'pps', 'ppsx'].includes(extension) || mime.includes('powerpoint') || mime.includes('presentation')) {
|
|
203
|
+
return <FilePptFilled style={{ ...iconStyle, color: '#f97316' }} />;
|
|
204
|
+
}
|
|
205
|
+
if (['xls', 'xlsx', 'csv', 'xlsm', 'xlsb'].includes(extension) || mime.includes('excel') || mime.includes('spreadsheet')) {
|
|
206
|
+
return <FileExcelFilled style={{ ...iconStyle, color: '#43a047' }} />;
|
|
207
|
+
}
|
|
208
|
+
if (['md', 'markdown'].includes(extension)) {
|
|
209
|
+
return <FileMarkdownFilled style={{ ...iconStyle, color: '#333' }} />;
|
|
210
|
+
}
|
|
211
|
+
if (extension === 'rdoc') {
|
|
212
|
+
return <FileTextFilled style={{ ...iconStyle, color: '#f9aa16' }} />;
|
|
213
|
+
}
|
|
214
|
+
if (mime.startsWith('image/') || ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'].includes(extension)) {
|
|
215
|
+
return <FileImageFilled style={{ ...iconStyle, color: '#8e24aa' }} />;
|
|
216
|
+
}
|
|
217
|
+
if (mime.startsWith('video/') || ['mp4', 'mov', 'avi', 'mkv', 'webm'].includes(extension)) {
|
|
218
|
+
return <VideoCameraFilled style={{ ...iconStyle, color: '#3949ab' }} />;
|
|
219
|
+
}
|
|
220
|
+
if ((ARCHIVE_FILE_EXTENSIONS as readonly string[]).includes(extension)) {
|
|
221
|
+
return <FileZipFilled style={{ ...iconStyle, color: '#8b5cf6' }} />;
|
|
222
|
+
}
|
|
223
|
+
if ((CAD_FILE_EXTENSIONS as readonly string[]).includes(extension)) {
|
|
224
|
+
return <FileTextFilled style={{ ...iconStyle, color: '#00acc1' }} />;
|
|
225
|
+
}
|
|
226
|
+
// if ((EBOOK_FILE_EXTENSIONS as readonly string[]).includes(extension)) {
|
|
227
|
+
// return <BookFilled style={{ ...iconStyle, color: '#6f5a2d' }} />;
|
|
228
|
+
// }
|
|
229
|
+
// 默认文件图标
|
|
230
|
+
return <FileOutlined style={{ ...iconStyle, color: '#757575' }} />;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 下载 Blob 到本地文件
|
|
235
|
+
*/
|
|
236
|
+
export const downloadBlob = (blob: Blob, fileName: string) => {
|
|
237
|
+
const url = URL.createObjectURL(blob);
|
|
238
|
+
const a = document.createElement('a');
|
|
239
|
+
a.href = url;
|
|
240
|
+
a.download = fileName;
|
|
241
|
+
document.body.appendChild(a);
|
|
242
|
+
a.click();
|
|
243
|
+
document.body.removeChild(a);
|
|
244
|
+
URL.revokeObjectURL(url);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 下载文件
|
|
249
|
+
* 优先从本地缓存获取,若无缓存则从网络下载
|
|
250
|
+
* @param fileResourcePath 文件资源路径
|
|
251
|
+
* @param fileName 下载文件名(可选)
|
|
252
|
+
* @param fileId 文件ID(可选,用于缓存查找)
|
|
253
|
+
* @param expectedCrc32 期望的CRC32校验值(可选)
|
|
254
|
+
* @returns 下载完成后的文件路径
|
|
255
|
+
*/
|
|
256
|
+
export const downloadFile = async (fileResourcePath: string, fileName?: string, fileId?: string, expectedCrc32?: number) => {
|
|
257
|
+
const url = getFileUrl(fileResourcePath);
|
|
258
|
+
if (!url) {
|
|
259
|
+
throw new Error('文件资源路径不可用');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const defaultFileName = fileName || fileResourcePath.split('/').pop() || 'downloaded_file';
|
|
263
|
+
|
|
264
|
+
// 优先从缓存获取
|
|
265
|
+
if (fileId) {
|
|
266
|
+
try {
|
|
267
|
+
if (expectedCrc32 !== undefined) {
|
|
268
|
+
const isValid = await CacheFileContent.validateCache(fileId, expectedCrc32);
|
|
269
|
+
if (isValid) {
|
|
270
|
+
const cached = await CacheFileContent.getCachedContent(fileId);
|
|
271
|
+
if (cached) {
|
|
272
|
+
console.log('[downloadFile] 使用本地缓存下载');
|
|
273
|
+
downloadBlob(cached.content, defaultFileName);
|
|
274
|
+
uiToast.success('文件已下载,请查看浏览器的下载文件夹');
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
const cached = await CacheFileContent.getCachedContent(fileId);
|
|
280
|
+
if (cached) {
|
|
281
|
+
console.log('[downloadFile] 使用本地缓存下载(无CRC校验)');
|
|
282
|
+
downloadBlob(cached.content, defaultFileName);
|
|
283
|
+
uiToast.success('文件已下载,请查看浏览器的下载文件夹');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error('[downloadFile] 读取缓存失败,将从网络下载:', error);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 从网络下载
|
|
293
|
+
console.log('[downloadFile] 从网络下载');
|
|
294
|
+
let headers = {} as any;
|
|
295
|
+
headers.set = (key: string, value: string) => {
|
|
296
|
+
headers[key] = value;
|
|
297
|
+
}
|
|
298
|
+
AuthorizationHandler.requestHandleSid({ headers });
|
|
299
|
+
|
|
300
|
+
uiToast.info('即将开始下载,请稍后...');
|
|
301
|
+
let abortController: AbortControllerClass|null = new febs.net.AbortController();
|
|
302
|
+
try {
|
|
303
|
+
const response = await febs.net.fetch(url, {
|
|
304
|
+
headers: { Authorization: headers.Authorization || '' },
|
|
305
|
+
credentials: 'include',
|
|
306
|
+
mode: 'cors',
|
|
307
|
+
timeout: Number(import.meta.env.VITE_API_FILEVIEW_TIMEOUT) || 100000,
|
|
308
|
+
signal: abortController.signal,
|
|
309
|
+
progress: (percent: number) => {
|
|
310
|
+
UIToastSingle.info({
|
|
311
|
+
key: url,
|
|
312
|
+
message:
|
|
313
|
+
(<div>
|
|
314
|
+
下载进度: { Math.floor(percent * 100) } %
|
|
315
|
+
</div>),
|
|
316
|
+
// 进行中 duration 必须为 0(不自动关闭):toast 自动超时会触发 onClose,
|
|
317
|
+
// 导致大文件下载超过超时时间被 abort。完成后给 2 秒自动消失。
|
|
318
|
+
// onClose 只会在用户手动点关闭按钮时触发(见 UIToastSingle)。
|
|
319
|
+
duration: percent >= 1 ? 2 : 0,
|
|
320
|
+
onClose: () => {
|
|
321
|
+
abortController && abortController.abort();
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
UIToastSingle.close(url);
|
|
329
|
+
if (response.status == 402) {
|
|
330
|
+
uiToast.error(`无权查看此文件`);
|
|
331
|
+
throw new Error(`无权查看此文件`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
uiToast.error(`文件加载失败,状态码 ${response.status}`);
|
|
335
|
+
throw new Error(`文件加载失败,状态码 ${response.status}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let buffer = await response.arrayBuffer();
|
|
339
|
+
abortController = null;
|
|
340
|
+
UIToastSingle.close(url);
|
|
341
|
+
|
|
342
|
+
const blob = new Blob([buffer], { type: response.headers.get('Content-Type') || 'application/octet-stream' });
|
|
343
|
+
|
|
344
|
+
// 下载后保存到缓存(如果有fileId)— 同时传入 Content-Type,避免 Safari IndexedDB 丢失 Blob.type
|
|
345
|
+
if (fileId) {
|
|
346
|
+
try {
|
|
347
|
+
await CacheFileContent.saveToCache(fileId, blob, expectedCrc32, blob.size, blob.type);
|
|
348
|
+
console.log('[downloadFile] 已保存到本地缓存');
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.error('[downloadFile] 保存到缓存失败:', error);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
downloadBlob(blob, defaultFileName);
|
|
355
|
+
uiToast.success('文件已下载,请查看浏览器的下载文件夹');
|
|
356
|
+
} catch (error) {
|
|
357
|
+
// 网络错误(CORS、超时、断网等):febs.net.fetch 会抛出 NetworkFailed 等异常,
|
|
358
|
+
// 此处统一捕获并提示,避免页面无任何反应。
|
|
359
|
+
abortController = null;
|
|
360
|
+
UIToastSingle.close(url);
|
|
361
|
+
const errMsg = (error as any)?.message;
|
|
362
|
+
// HTTP 状态码错误已在上方抛出并提示过 toast,避免重复提示
|
|
363
|
+
const isHttpStatusError = errMsg && /^无权查看此文件|^文件加载失败,状态码/.test(errMsg);
|
|
364
|
+
if (!isHttpStatusError) {
|
|
365
|
+
const rawMsg = errMsg || String(error) || '未知错误';
|
|
366
|
+
uiToast.error(`文件下载失败:${rawMsg}`);
|
|
367
|
+
}
|
|
368
|
+
console.error('[downloadFile] 下载失败:', error, 'url:', url);
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* 文件详情查询函数(用于按业务场景切换详情接口,如项目文件 / CRM 客户文件)
|
|
375
|
+
*/
|
|
376
|
+
export type FileDetailFetcher = (fileId: string) => Promise<{
|
|
377
|
+
code: number;
|
|
378
|
+
data?: { crc32?: number; projectId?: string } | null;
|
|
379
|
+
}>;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @desc 文件预览组件,支持图片、PDF、Office文档等常见格式的预览。根据文件类型自动选择合适的预览方式,提供加载状态和错误提示。
|
|
383
|
+
* @example
|
|
384
|
+
* <UIFilePreview
|
|
385
|
+
* fileUrl={previewUrl}
|
|
386
|
+
* visible={previewVisible}
|
|
387
|
+
* onClose={() => setPreviewVisible(false)} />
|
|
388
|
+
*/
|
|
389
|
+
export const fetchFileBuffer = async (
|
|
390
|
+
fileResourcePath: string,
|
|
391
|
+
accessToken: string|undefined,
|
|
392
|
+
abortController: AbortControllerClass | null,
|
|
393
|
+
onProgress?: (percent: number) => void,
|
|
394
|
+
fileId?: string,
|
|
395
|
+
expectedCrc32?: number,
|
|
396
|
+
detailFetcher?: FileDetailFetcher,
|
|
397
|
+
) => {
|
|
398
|
+
const url = getFileUrl(fileResourcePath);
|
|
399
|
+
if (!url) {
|
|
400
|
+
throw new Error('文件资源路径不可用');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let actualCrc32 = expectedCrc32;
|
|
404
|
+
|
|
405
|
+
// 合同链接文件(ID 以 contract-file- 开头)是虚拟文件,无需查询 detail
|
|
406
|
+
const isContractLinkFile = fileId?.startsWith('contract-file-');
|
|
407
|
+
|
|
408
|
+
// —— 第 1 步:必须调用 getDetail,获取服务器最新 crc32(权威值) ——
|
|
409
|
+
if (fileId && !isContractLinkFile) {
|
|
410
|
+
try {
|
|
411
|
+
const detailResponse = detailFetcher
|
|
412
|
+
? await detailFetcher(fileId)
|
|
413
|
+
: await API.project.file.getDetail({ fileId });
|
|
414
|
+
if (detailResponse?.code === ResponseCode.SUCCESS && detailResponse.data) {
|
|
415
|
+
const detailCrc32 = detailResponse.data.crc32;
|
|
416
|
+
// 仅当 detail 返回有效值时才覆盖(避免 null/undefined 把 prop 的有效值冲掉)
|
|
417
|
+
if (detailCrc32 != null) {
|
|
418
|
+
actualCrc32 = detailCrc32;
|
|
419
|
+
}
|
|
420
|
+
// 持久化单条文件元数据缓存(用于离线列表显示)
|
|
421
|
+
if (detailResponse.data.projectId) {
|
|
422
|
+
CacheFileMeta.saveFileMeta(detailResponse.data.projectId, detailResponse.data).catch(err =>
|
|
423
|
+
console.warn('持久化单条文件元数据缓存失败:', err)
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error('获取文件详情失败:', error);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// —— 第 2 步:用最新的 actualCrc32 校验缓存 ——
|
|
433
|
+
// crc32 相同 → 直接打开缓存(跳过文件资源网络请求)
|
|
434
|
+
// crc32 不同 / 无 crc32 / 无缓存 → 走网络下载
|
|
435
|
+
if (fileId && !isContractLinkFile) {
|
|
436
|
+
let cached: { content: Blob; crc32: number; contentType: string } | null = null;
|
|
437
|
+
if (actualCrc32 != null) {
|
|
438
|
+
const isValid = await CacheFileContent.validateCache(fileId, actualCrc32);
|
|
439
|
+
if (isValid) {
|
|
440
|
+
cached = await CacheFileContent.getCachedContent(fileId);
|
|
441
|
+
if (cached) {
|
|
442
|
+
// Safari IndexedDB Blob 完整性校验:
|
|
443
|
+
// Safari 存在 IndexedDB Blob 损坏问题——缓存的 Blob 可能因内存回收/配额限制
|
|
444
|
+
// 变成空 Blob 或损坏 Blob。如果 size 为 0,直接视为缓存失效,删除并走网络。
|
|
445
|
+
if (cached.content.size === 0) {
|
|
446
|
+
console.warn('[fetchFileBuffer] 缓存 Blob 为空(size=0),Safari IndexedDB 可能已损坏,删除缓存并从网络加载');
|
|
447
|
+
await CacheFileContent.removeFromCache(fileId);
|
|
448
|
+
} else {
|
|
449
|
+
try {
|
|
450
|
+
const rawBuffer = await cached.content.arrayBuffer();
|
|
451
|
+
// Safari 兼容性:克隆 ArrayBuffer 创建新副本,避免 IndexedDB 派生的 ArrayBuffer
|
|
452
|
+
// 在创建 Blob/File 时出现 WebKitBlobResource error 1 等问题。
|
|
453
|
+
const buffer = rawBuffer.slice(0);
|
|
454
|
+
console.log('[fetchFileBuffer] 缓存命中(detail crc32 校验通过),size:', buffer.byteLength, '跳过文件资源请求');
|
|
455
|
+
const hitHeaders = new Headers();
|
|
456
|
+
if (cached.contentType) {
|
|
457
|
+
hitHeaders.set('Content-Type', cached.contentType);
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
buffer,
|
|
461
|
+
headers: hitHeaders,
|
|
462
|
+
status: 200,
|
|
463
|
+
fromCache: true,
|
|
464
|
+
};
|
|
465
|
+
} catch (cacheError) {
|
|
466
|
+
console.warn('[fetchFileBuffer] 读取缓存 Blob 失败(Safari 可能损坏),删除缓存并从网络加载:', cacheError);
|
|
467
|
+
await CacheFileContent.removeFromCache(fileId);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
} else {
|
|
472
|
+
console.log('[fetchFileBuffer] 缓存 crc32 与服务器不一致,将从网络加载最新文件');
|
|
473
|
+
}
|
|
474
|
+
} else {
|
|
475
|
+
console.log('[fetchFileBuffer] 无法校验 crc32(服务器未返回),跳过缓存检查,将从网络加载');
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// add sid to headers.
|
|
480
|
+
let headers = {} as any;
|
|
481
|
+
headers.set = (key: string, value: string) => {
|
|
482
|
+
headers[key] = value;
|
|
483
|
+
}
|
|
484
|
+
AuthorizationHandler.requestHandleSid({ headers });
|
|
485
|
+
|
|
486
|
+
let response;
|
|
487
|
+
try {
|
|
488
|
+
response = await febs.net.fetch(url + (accessToken? `?tempToken=${accessToken}` : ''), {
|
|
489
|
+
headers: { Authorization: headers.Authorization || '' },
|
|
490
|
+
credentials: 'include',
|
|
491
|
+
mode: 'cors',
|
|
492
|
+
timeout: Number(import.meta.env.VITE_API_FILEVIEW_TIMEOUT) || 100000,
|
|
493
|
+
progress: (percent: number) => onProgress?.(Math.floor(percent * 100)),
|
|
494
|
+
signal: abortController? abortController.signal : null,
|
|
495
|
+
});
|
|
496
|
+
} catch (error) {
|
|
497
|
+
// 网络错误(CORS、超时、断网等):febs.net.fetch 抛出 NetworkFailed,
|
|
498
|
+
// 统一提示,避免仅依赖调用方的 previewError 文本(可能不够醒目或被遮挡)。
|
|
499
|
+
// 注意:CORS 被拦截时 JS 无法读取 HTTP 状态码(如 404),仅能拿到 error.message。
|
|
500
|
+
const rawMsg = (error as any)?.message || String(error) || '未知错误';
|
|
501
|
+
uiToast.error(`文件加载失败:${rawMsg}`);
|
|
502
|
+
console.error('[fetchFileBuffer] 网络请求失败:', error, 'url:', url);
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (!response.ok) {
|
|
507
|
+
if (response.status == 402) {
|
|
508
|
+
uiToast.error(`无权查看此文件`);
|
|
509
|
+
throw new Error(`无权查看此文件`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
uiToast.error(`文件加载失败,状态码 ${response.status}`);
|
|
513
|
+
throw new Error(`文件加载失败,状态码 ${response.status}`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const buffer = await response.arrayBuffer();
|
|
517
|
+
|
|
518
|
+
if (fileId) {
|
|
519
|
+
// 从响应头取出 Content-Type 并独立传入缓存,避免 Safari IndexedDB 把 Blob.type 清空
|
|
520
|
+
const responseContentType = response.headers?.get?.('Content-Type') || '';
|
|
521
|
+
const blob = new Blob([buffer], { type: responseContentType });
|
|
522
|
+
await CacheFileContent.saveToCache(fileId, blob, actualCrc32, blob.size, responseContentType);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return {
|
|
526
|
+
buffer,
|
|
527
|
+
headers: response.headers,
|
|
528
|
+
status: response.status,
|
|
529
|
+
fromCache: false,
|
|
530
|
+
}
|
|
531
|
+
};
|