@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,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IndexedDB 工具模块
|
|
3
|
+
* 用于本地存储编辑器的文件数据
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const DB_NAME = 'FileEditorDB';
|
|
7
|
+
const DB_VERSION = 2; // 从 1 升级到 2,新增 localFiles store
|
|
8
|
+
const STORE_NAME = 'files';
|
|
9
|
+
const LOCAL_FILES_STORE = 'localFiles';
|
|
10
|
+
|
|
11
|
+
export type FileType = 'pptx' | 'xlsx' | 'md' | 'markdown' | 'docx' | 'rdoc';
|
|
12
|
+
|
|
13
|
+
/** 本地文件记录(包含未上传的新文件和服务器文件的本地未同步修改) */
|
|
14
|
+
export interface LocalFileRecord {
|
|
15
|
+
/** 本地唯一标识 */
|
|
16
|
+
localId: string;
|
|
17
|
+
/** 用户 ID */
|
|
18
|
+
userId: string;
|
|
19
|
+
/** 项目 ID */
|
|
20
|
+
projectId: string;
|
|
21
|
+
/** 父文件夹 ID(服务器文件 ID 或本地文件夹 ID,根目录为 null) */
|
|
22
|
+
parentId: string | null;
|
|
23
|
+
/** 文件名 */
|
|
24
|
+
fileName: string;
|
|
25
|
+
/** 文件类型 */
|
|
26
|
+
fileType: FileType;
|
|
27
|
+
/** 对应服务器文件 ID:null 表示从未上传的本地新文件;非 null 表示该服务器文件的本地修改版本 */
|
|
28
|
+
serverFileId: string | null;
|
|
29
|
+
/** 是否为仅本地存在(从未上传) */
|
|
30
|
+
isLocalOnly: boolean;
|
|
31
|
+
/** 是否有未同步的修改 */
|
|
32
|
+
hasUnsyncedChanges: boolean;
|
|
33
|
+
/** 原始服务器文件快照(用于离线编辑后,上传时可回填服务器元数据,仅 serverFileId 非空时有值) */
|
|
34
|
+
originalServerFile?: any | null;
|
|
35
|
+
/** 原始服务器文件内容(用于差分上传基准,仅 serverFileId 非空时有值;二进制为 ArrayBuffer,Markdown 为 string) */
|
|
36
|
+
originalContent?: ArrayBuffer | string;
|
|
37
|
+
/** 文件实际内容(二进制为 ArrayBuffer,Markdown 为 string) */
|
|
38
|
+
content: ArrayBuffer | string;
|
|
39
|
+
/** 文件大小(字节) */
|
|
40
|
+
fileSize: number;
|
|
41
|
+
/** 创建时间戳 */
|
|
42
|
+
createdAt: number;
|
|
43
|
+
/** 更新时间戳 */
|
|
44
|
+
updatedAt: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 打开 IndexedDB 数据库
|
|
49
|
+
*/
|
|
50
|
+
function openDB(): Promise<IDBDatabase> {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
53
|
+
|
|
54
|
+
request.onerror = () => {
|
|
55
|
+
reject(new Error('打开 IndexedDB 失败'));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
request.onsuccess = () => {
|
|
59
|
+
resolve(request.result);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
request.onupgradeneeded = (event) => {
|
|
63
|
+
const db = (event.target as IDBOpenDBRequest).result;
|
|
64
|
+
// v1: files store
|
|
65
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
66
|
+
const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
|
|
67
|
+
store.createIndex('userId', 'userId', { unique: false });
|
|
68
|
+
store.createIndex('fileName', 'fileName', { unique: false });
|
|
69
|
+
store.createIndex('fileType', 'fileType', { unique: false });
|
|
70
|
+
store.createIndex('userId_fileName_type', ['userId', 'fileName', 'fileType'], { unique: true });
|
|
71
|
+
}
|
|
72
|
+
// v2: localFiles store(文件管理器中可见的本地未上传/未同步文件)
|
|
73
|
+
if (!db.objectStoreNames.contains(LOCAL_FILES_STORE)) {
|
|
74
|
+
const localStore = db.createObjectStore(LOCAL_FILES_STORE, { keyPath: 'localId' });
|
|
75
|
+
localStore.createIndex('userId', 'userId', { unique: false });
|
|
76
|
+
localStore.createIndex('projectId', 'projectId', { unique: false });
|
|
77
|
+
localStore.createIndex('userId_projectId', ['userId', 'projectId'], { unique: false });
|
|
78
|
+
localStore.createIndex('userId_serverFileId', ['userId', 'serverFileId'], { unique: false });
|
|
79
|
+
localStore.createIndex('serverFileId', 'serverFileId', { unique: false });
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 保存文件数据到 IndexedDB
|
|
87
|
+
*/
|
|
88
|
+
export async function saveFile(
|
|
89
|
+
userId: string,
|
|
90
|
+
fileName: string,
|
|
91
|
+
fileType: FileType,
|
|
92
|
+
data: any
|
|
93
|
+
): Promise<void> {
|
|
94
|
+
try {
|
|
95
|
+
const db = await openDB();
|
|
96
|
+
const transaction = db.transaction(STORE_NAME, 'readwrite');
|
|
97
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
98
|
+
|
|
99
|
+
const record = {
|
|
100
|
+
id: `${userId}_${fileName}_${fileType}`,
|
|
101
|
+
userId,
|
|
102
|
+
fileName,
|
|
103
|
+
fileType,
|
|
104
|
+
data,
|
|
105
|
+
updatedAt: Date.now()
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const request = store.put(record);
|
|
110
|
+
request.onsuccess = () => {
|
|
111
|
+
db.close();
|
|
112
|
+
resolve();
|
|
113
|
+
};
|
|
114
|
+
request.onerror = () => {
|
|
115
|
+
db.close();
|
|
116
|
+
reject(new Error('保存文件失败'));
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('保存文件到 IndexedDB 失败:', error);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 从 IndexedDB 读取文件数据
|
|
127
|
+
*/
|
|
128
|
+
export async function loadFile(
|
|
129
|
+
userId: string,
|
|
130
|
+
fileName: string,
|
|
131
|
+
fileType: FileType
|
|
132
|
+
): Promise<any | null> {
|
|
133
|
+
try {
|
|
134
|
+
const db = await openDB();
|
|
135
|
+
const transaction = db.transaction(STORE_NAME, 'readonly');
|
|
136
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
137
|
+
const index = store.index('userId_fileName_type');
|
|
138
|
+
|
|
139
|
+
return new Promise((resolve, reject) => {
|
|
140
|
+
const request = index.get([userId, fileName, fileType]);
|
|
141
|
+
request.onsuccess = () => {
|
|
142
|
+
db.close();
|
|
143
|
+
if (request.result) {
|
|
144
|
+
resolve(request.result.data);
|
|
145
|
+
} else {
|
|
146
|
+
resolve(null);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
request.onerror = () => {
|
|
150
|
+
db.close();
|
|
151
|
+
reject(new Error('读取文件失败'));
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('从 IndexedDB 读取文件失败:', error);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 删除 IndexedDB 中的文件
|
|
162
|
+
*/
|
|
163
|
+
export async function deleteFile(
|
|
164
|
+
userId: string,
|
|
165
|
+
fileName: string,
|
|
166
|
+
fileType: FileType
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
try {
|
|
169
|
+
const db = await openDB();
|
|
170
|
+
const transaction = db.transaction(STORE_NAME, 'readwrite');
|
|
171
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
172
|
+
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const request = store.delete(`${userId}_${fileName}_${fileType}`);
|
|
175
|
+
request.onsuccess = () => {
|
|
176
|
+
db.close();
|
|
177
|
+
resolve();
|
|
178
|
+
};
|
|
179
|
+
request.onerror = () => {
|
|
180
|
+
db.close();
|
|
181
|
+
reject(new Error('删除文件失败'));
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error('从 IndexedDB 删除文件失败:', error);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 获取所有本地缓存的文件列表(指定用户)
|
|
192
|
+
*/
|
|
193
|
+
export async function listFiles(userId: string, fileType?: FileType): Promise<Array<{ fileName: string; fileType: FileType; updatedAt: number }>> {
|
|
194
|
+
try {
|
|
195
|
+
const db = await openDB();
|
|
196
|
+
const transaction = db.transaction(STORE_NAME, 'readonly');
|
|
197
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
198
|
+
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
const request = store.getAll();
|
|
201
|
+
request.onsuccess = () => {
|
|
202
|
+
db.close();
|
|
203
|
+
let results = request.result.filter((item: any) => item.userId === userId);
|
|
204
|
+
if (fileType) {
|
|
205
|
+
results = results.filter((item: any) => item.fileType === fileType);
|
|
206
|
+
}
|
|
207
|
+
resolve(results.map((item: any) => ({
|
|
208
|
+
fileName: item.fileName,
|
|
209
|
+
fileType: item.fileType,
|
|
210
|
+
updatedAt: item.updatedAt
|
|
211
|
+
})));
|
|
212
|
+
};
|
|
213
|
+
request.onerror = () => {
|
|
214
|
+
db.close();
|
|
215
|
+
reject(new Error('获取文件列表失败'));
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error('获取文件列表失败:', error);
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ============================================================
|
|
225
|
+
// 以下是新增的 localFiles store 相关 API(用于文件管理器中可见的本地未上传/未同步文件)
|
|
226
|
+
// ============================================================
|
|
227
|
+
|
|
228
|
+
/** 生成本地文件唯一 ID */
|
|
229
|
+
function generateLocalId(): string {
|
|
230
|
+
return `local_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 计算内容大小(字节)
|
|
235
|
+
*/
|
|
236
|
+
function calculateContentSize(content: ArrayBuffer | string): number {
|
|
237
|
+
if (typeof content === 'string') {
|
|
238
|
+
// UTF-8 字节长度
|
|
239
|
+
return new Blob([content]).size;
|
|
240
|
+
}
|
|
241
|
+
return content.byteLength;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 创建并保存一个新的本地仅存在文件(未上传到服务器)
|
|
246
|
+
*/
|
|
247
|
+
export async function createLocalOnlyFile(params: {
|
|
248
|
+
userId: string;
|
|
249
|
+
projectId: string;
|
|
250
|
+
parentId: string | null;
|
|
251
|
+
fileName: string;
|
|
252
|
+
fileType: FileType;
|
|
253
|
+
content: ArrayBuffer | string;
|
|
254
|
+
}): Promise<LocalFileRecord> {
|
|
255
|
+
const now = Date.now();
|
|
256
|
+
const record: LocalFileRecord = {
|
|
257
|
+
localId: generateLocalId(),
|
|
258
|
+
userId: params.userId,
|
|
259
|
+
projectId: params.projectId,
|
|
260
|
+
parentId: params.parentId,
|
|
261
|
+
fileName: params.fileName,
|
|
262
|
+
fileType: params.fileType,
|
|
263
|
+
serverFileId: null,
|
|
264
|
+
isLocalOnly: true,
|
|
265
|
+
hasUnsyncedChanges: true,
|
|
266
|
+
originalServerFile: null,
|
|
267
|
+
content: params.content,
|
|
268
|
+
fileSize: calculateContentSize(params.content),
|
|
269
|
+
createdAt: now,
|
|
270
|
+
updatedAt: now,
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const db = await openDB();
|
|
275
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readwrite');
|
|
276
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
277
|
+
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
const request = store.put(record);
|
|
280
|
+
request.onsuccess = () => {
|
|
281
|
+
db.close();
|
|
282
|
+
resolve(record);
|
|
283
|
+
};
|
|
284
|
+
request.onerror = () => {
|
|
285
|
+
db.close();
|
|
286
|
+
reject(new Error('创建本地文件失败'));
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
} catch (error) {
|
|
290
|
+
console.error('创建本地文件失败:', error);
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* 为已上传的服务器文件保存本地未同步修改快照
|
|
297
|
+
*/
|
|
298
|
+
export async function saveUnsyncedServerFile(params: {
|
|
299
|
+
userId: string;
|
|
300
|
+
projectId: string;
|
|
301
|
+
parentId: string | null;
|
|
302
|
+
fileName: string;
|
|
303
|
+
fileType: FileType;
|
|
304
|
+
serverFileId: string;
|
|
305
|
+
originalServerFile: any;
|
|
306
|
+
content: ArrayBuffer | string;
|
|
307
|
+
/** 原始服务器文件内容(用于差分上传基准) */
|
|
308
|
+
originalContent?: ArrayBuffer | string;
|
|
309
|
+
markUnsynced?: boolean;
|
|
310
|
+
}): Promise<LocalFileRecord> {
|
|
311
|
+
try {
|
|
312
|
+
// 先检查是否已经存在该 serverFileId 的未同步记录,存在则更新,不存在则新建
|
|
313
|
+
const existing = await getLocalFileByServerId(params.userId, params.serverFileId);
|
|
314
|
+
const now = Date.now();
|
|
315
|
+
const markUnsynced = params.markUnsynced ?? true;
|
|
316
|
+
|
|
317
|
+
const record: LocalFileRecord = existing ? {
|
|
318
|
+
...existing,
|
|
319
|
+
fileName: params.fileName,
|
|
320
|
+
fileType: params.fileType,
|
|
321
|
+
parentId: params.parentId,
|
|
322
|
+
content: params.content,
|
|
323
|
+
fileSize: calculateContentSize(params.content),
|
|
324
|
+
hasUnsyncedChanges: markUnsynced,
|
|
325
|
+
originalServerFile: params.originalServerFile || existing.originalServerFile,
|
|
326
|
+
// 仅在首次创建时存储 originalContent,后续更新不覆盖
|
|
327
|
+
originalContent: existing.originalContent ?? params.originalContent,
|
|
328
|
+
updatedAt: now,
|
|
329
|
+
} : {
|
|
330
|
+
localId: generateLocalId(),
|
|
331
|
+
userId: params.userId,
|
|
332
|
+
projectId: params.projectId,
|
|
333
|
+
parentId: params.parentId,
|
|
334
|
+
fileName: params.fileName,
|
|
335
|
+
fileType: params.fileType,
|
|
336
|
+
serverFileId: params.serverFileId,
|
|
337
|
+
isLocalOnly: false,
|
|
338
|
+
hasUnsyncedChanges: markUnsynced,
|
|
339
|
+
originalServerFile: params.originalServerFile,
|
|
340
|
+
originalContent: params.originalContent,
|
|
341
|
+
content: params.content,
|
|
342
|
+
fileSize: calculateContentSize(params.content),
|
|
343
|
+
createdAt: now,
|
|
344
|
+
updatedAt: now,
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const db = await openDB();
|
|
348
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readwrite');
|
|
349
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
350
|
+
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
const request = store.put(record);
|
|
353
|
+
request.onsuccess = () => {
|
|
354
|
+
db.close();
|
|
355
|
+
resolve(record);
|
|
356
|
+
};
|
|
357
|
+
request.onerror = () => {
|
|
358
|
+
db.close();
|
|
359
|
+
reject(new Error('保存本地未同步文件失败'));
|
|
360
|
+
};
|
|
361
|
+
});
|
|
362
|
+
} catch (error) {
|
|
363
|
+
console.error('保存本地未同步文件失败:', error);
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 更新本地文件内容(用户编辑后)
|
|
370
|
+
*/
|
|
371
|
+
export async function updateLocalFileContent(
|
|
372
|
+
localId: string,
|
|
373
|
+
content: ArrayBuffer | string,
|
|
374
|
+
fileName?: string,
|
|
375
|
+
markUnsynced: boolean = true
|
|
376
|
+
): Promise<LocalFileRecord | null> {
|
|
377
|
+
try {
|
|
378
|
+
const record = await getLocalFile(localId);
|
|
379
|
+
if (!record) return null;
|
|
380
|
+
|
|
381
|
+
const updated: LocalFileRecord = {
|
|
382
|
+
...record,
|
|
383
|
+
content,
|
|
384
|
+
fileSize: calculateContentSize(content),
|
|
385
|
+
fileName: fileName ?? record.fileName,
|
|
386
|
+
hasUnsyncedChanges: markUnsynced,
|
|
387
|
+
updatedAt: Date.now(),
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const db = await openDB();
|
|
391
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readwrite');
|
|
392
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
393
|
+
|
|
394
|
+
return new Promise((resolve, reject) => {
|
|
395
|
+
const request = store.put(updated);
|
|
396
|
+
request.onsuccess = () => {
|
|
397
|
+
db.close();
|
|
398
|
+
resolve(updated);
|
|
399
|
+
};
|
|
400
|
+
request.onerror = () => {
|
|
401
|
+
db.close();
|
|
402
|
+
reject(new Error('更新本地文件内容失败'));
|
|
403
|
+
};
|
|
404
|
+
});
|
|
405
|
+
} catch (error) {
|
|
406
|
+
console.error('更新本地文件内容失败:', error);
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* 获取单个本地文件记录
|
|
413
|
+
*/
|
|
414
|
+
export async function getLocalFile(localId: string): Promise<LocalFileRecord | null> {
|
|
415
|
+
try {
|
|
416
|
+
const db = await openDB();
|
|
417
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readonly');
|
|
418
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
419
|
+
|
|
420
|
+
return new Promise((resolve, reject) => {
|
|
421
|
+
const request = store.get(localId);
|
|
422
|
+
request.onsuccess = () => {
|
|
423
|
+
db.close();
|
|
424
|
+
resolve(request.result || null);
|
|
425
|
+
};
|
|
426
|
+
request.onerror = () => {
|
|
427
|
+
db.close();
|
|
428
|
+
reject(new Error('获取本地文件失败'));
|
|
429
|
+
};
|
|
430
|
+
});
|
|
431
|
+
} catch (error) {
|
|
432
|
+
console.error('获取本地文件失败:', error);
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* 通过服务器文件 ID 查找对应的本地未同步记录
|
|
439
|
+
*/
|
|
440
|
+
export async function getLocalFileByServerId(userId: string, serverFileId: string): Promise<LocalFileRecord | null> {
|
|
441
|
+
try {
|
|
442
|
+
const db = await openDB();
|
|
443
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readonly');
|
|
444
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
445
|
+
const index = store.index('userId_serverFileId');
|
|
446
|
+
|
|
447
|
+
return new Promise((resolve, reject) => {
|
|
448
|
+
const request = index.get([userId, serverFileId]);
|
|
449
|
+
request.onsuccess = () => {
|
|
450
|
+
db.close();
|
|
451
|
+
resolve(request.result || null);
|
|
452
|
+
};
|
|
453
|
+
request.onerror = () => {
|
|
454
|
+
db.close();
|
|
455
|
+
reject(new Error('查找本地未同步文件失败'));
|
|
456
|
+
};
|
|
457
|
+
});
|
|
458
|
+
} catch (error) {
|
|
459
|
+
console.error('查找本地未同步文件失败:', error);
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* 列出指定项目下所有本地文件(本地新文件 + 服务器文件未同步修改)
|
|
466
|
+
*/
|
|
467
|
+
export async function listLocalFilesByProject(userId: string, projectId: string): Promise<LocalFileRecord[]> {
|
|
468
|
+
try {
|
|
469
|
+
const db = await openDB();
|
|
470
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readonly');
|
|
471
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
472
|
+
const index = store.index('userId_projectId');
|
|
473
|
+
|
|
474
|
+
return new Promise((resolve, reject) => {
|
|
475
|
+
const request = index.getAll([userId, projectId]);
|
|
476
|
+
request.onsuccess = () => {
|
|
477
|
+
db.close();
|
|
478
|
+
resolve(request.result || []);
|
|
479
|
+
};
|
|
480
|
+
request.onerror = () => {
|
|
481
|
+
db.close();
|
|
482
|
+
reject(new Error('列出本地文件失败'));
|
|
483
|
+
};
|
|
484
|
+
});
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.error('列出本地文件失败:', error);
|
|
487
|
+
return [];
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* 标记本地文件为已同步(上传成功后调用)。如果 isLocalOnly=true 则删除记录;否则保留但 hasUnsyncedChanges=false
|
|
493
|
+
*/
|
|
494
|
+
export async function markLocalFileSynced(localId: string, uploadedServerFileId?: string): Promise<void> {
|
|
495
|
+
try {
|
|
496
|
+
const record = await getLocalFile(localId);
|
|
497
|
+
if (!record) return;
|
|
498
|
+
|
|
499
|
+
const db = await openDB();
|
|
500
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readwrite');
|
|
501
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
502
|
+
|
|
503
|
+
if (record.isLocalOnly) {
|
|
504
|
+
// 本地新文件上传成功 → 删除本地记录(因为现在服务器有了)
|
|
505
|
+
return new Promise((resolve, reject) => {
|
|
506
|
+
const request = store.delete(localId);
|
|
507
|
+
request.onsuccess = () => {
|
|
508
|
+
db.close();
|
|
509
|
+
resolve();
|
|
510
|
+
};
|
|
511
|
+
request.onerror = () => {
|
|
512
|
+
db.close();
|
|
513
|
+
reject(new Error('删除已上传本地文件记录失败'));
|
|
514
|
+
};
|
|
515
|
+
});
|
|
516
|
+
} else {
|
|
517
|
+
// 服务器文件的离线修改已同步 → 保留记录但标记已同步
|
|
518
|
+
const updated: LocalFileRecord = {
|
|
519
|
+
...record,
|
|
520
|
+
hasUnsyncedChanges: false,
|
|
521
|
+
serverFileId: uploadedServerFileId || record.serverFileId,
|
|
522
|
+
updatedAt: Date.now(),
|
|
523
|
+
};
|
|
524
|
+
return new Promise((resolve, reject) => {
|
|
525
|
+
const request = store.put(updated);
|
|
526
|
+
request.onsuccess = () => {
|
|
527
|
+
db.close();
|
|
528
|
+
resolve();
|
|
529
|
+
};
|
|
530
|
+
request.onerror = () => {
|
|
531
|
+
db.close();
|
|
532
|
+
reject(new Error('标记同步失败'));
|
|
533
|
+
};
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error('标记本地文件同步失败:', error);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* 删除本地文件记录
|
|
543
|
+
*/
|
|
544
|
+
export async function deleteLocalFile(localId: string): Promise<void> {
|
|
545
|
+
try {
|
|
546
|
+
const db = await openDB();
|
|
547
|
+
const transaction = db.transaction(LOCAL_FILES_STORE, 'readwrite');
|
|
548
|
+
const store = transaction.objectStore(LOCAL_FILES_STORE);
|
|
549
|
+
|
|
550
|
+
return new Promise((resolve, reject) => {
|
|
551
|
+
const request = store.delete(localId);
|
|
552
|
+
request.onsuccess = () => {
|
|
553
|
+
db.close();
|
|
554
|
+
resolve();
|
|
555
|
+
};
|
|
556
|
+
request.onerror = () => {
|
|
557
|
+
db.close();
|
|
558
|
+
reject(new Error('删除本地文件失败'));
|
|
559
|
+
};
|
|
560
|
+
});
|
|
561
|
+
} catch (error) {
|
|
562
|
+
console.error('删除本地文件失败:', error);
|
|
563
|
+
}
|
|
564
|
+
}
|