@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.
Files changed (345) hide show
  1. package/package.json +20 -38
  2. package/public/cmaps/78-EUC-H.bcmap +0 -0
  3. package/public/cmaps/78-EUC-V.bcmap +0 -0
  4. package/public/cmaps/78-H.bcmap +0 -0
  5. package/public/cmaps/78-RKSJ-H.bcmap +0 -0
  6. package/public/cmaps/78-RKSJ-V.bcmap +0 -0
  7. package/public/cmaps/78-V.bcmap +0 -0
  8. package/public/cmaps/78ms-RKSJ-H.bcmap +0 -0
  9. package/public/cmaps/78ms-RKSJ-V.bcmap +0 -0
  10. package/public/cmaps/83pv-RKSJ-H.bcmap +0 -0
  11. package/public/cmaps/90ms-RKSJ-H.bcmap +0 -0
  12. package/public/cmaps/90ms-RKSJ-V.bcmap +0 -0
  13. package/public/cmaps/90msp-RKSJ-H.bcmap +0 -0
  14. package/public/cmaps/90msp-RKSJ-V.bcmap +0 -0
  15. package/public/cmaps/90pv-RKSJ-H.bcmap +0 -0
  16. package/public/cmaps/90pv-RKSJ-V.bcmap +0 -0
  17. package/public/cmaps/Add-H.bcmap +0 -0
  18. package/public/cmaps/Add-RKSJ-H.bcmap +0 -0
  19. package/public/cmaps/Add-RKSJ-V.bcmap +0 -0
  20. package/public/cmaps/Add-V.bcmap +0 -0
  21. package/public/cmaps/Adobe-CNS1-0.bcmap +0 -0
  22. package/public/cmaps/Adobe-CNS1-1.bcmap +0 -0
  23. package/public/cmaps/Adobe-CNS1-2.bcmap +0 -0
  24. package/public/cmaps/Adobe-CNS1-3.bcmap +0 -0
  25. package/public/cmaps/Adobe-CNS1-4.bcmap +0 -0
  26. package/public/cmaps/Adobe-CNS1-5.bcmap +0 -0
  27. package/public/cmaps/Adobe-CNS1-6.bcmap +0 -0
  28. package/public/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  29. package/public/cmaps/Adobe-GB1-0.bcmap +0 -0
  30. package/public/cmaps/Adobe-GB1-1.bcmap +0 -0
  31. package/public/cmaps/Adobe-GB1-2.bcmap +0 -0
  32. package/public/cmaps/Adobe-GB1-3.bcmap +0 -0
  33. package/public/cmaps/Adobe-GB1-4.bcmap +0 -0
  34. package/public/cmaps/Adobe-GB1-5.bcmap +0 -0
  35. package/public/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  36. package/public/cmaps/Adobe-Japan1-0.bcmap +0 -0
  37. package/public/cmaps/Adobe-Japan1-1.bcmap +0 -0
  38. package/public/cmaps/Adobe-Japan1-2.bcmap +0 -0
  39. package/public/cmaps/Adobe-Japan1-3.bcmap +0 -0
  40. package/public/cmaps/Adobe-Japan1-4.bcmap +0 -0
  41. package/public/cmaps/Adobe-Japan1-5.bcmap +0 -0
  42. package/public/cmaps/Adobe-Japan1-6.bcmap +0 -0
  43. package/public/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  44. package/public/cmaps/Adobe-Korea1-0.bcmap +0 -0
  45. package/public/cmaps/Adobe-Korea1-1.bcmap +0 -0
  46. package/public/cmaps/Adobe-Korea1-2.bcmap +0 -0
  47. package/public/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  48. package/public/cmaps/B5-H.bcmap +0 -0
  49. package/public/cmaps/B5-V.bcmap +0 -0
  50. package/public/cmaps/B5pc-H.bcmap +0 -0
  51. package/public/cmaps/B5pc-V.bcmap +0 -0
  52. package/public/cmaps/CNS-EUC-H.bcmap +0 -0
  53. package/public/cmaps/CNS-EUC-V.bcmap +0 -0
  54. package/public/cmaps/CNS1-H.bcmap +0 -0
  55. package/public/cmaps/CNS1-V.bcmap +0 -0
  56. package/public/cmaps/CNS2-H.bcmap +0 -0
  57. package/public/cmaps/CNS2-V.bcmap +3 -0
  58. package/public/cmaps/ETHK-B5-H.bcmap +0 -0
  59. package/public/cmaps/ETHK-B5-V.bcmap +0 -0
  60. package/public/cmaps/ETen-B5-H.bcmap +0 -0
  61. package/public/cmaps/ETen-B5-V.bcmap +0 -0
  62. package/public/cmaps/ETenms-B5-H.bcmap +3 -0
  63. package/public/cmaps/ETenms-B5-V.bcmap +0 -0
  64. package/public/cmaps/EUC-H.bcmap +0 -0
  65. package/public/cmaps/EUC-V.bcmap +0 -0
  66. package/public/cmaps/Ext-H.bcmap +0 -0
  67. package/public/cmaps/Ext-RKSJ-H.bcmap +0 -0
  68. package/public/cmaps/Ext-RKSJ-V.bcmap +0 -0
  69. package/public/cmaps/Ext-V.bcmap +0 -0
  70. package/public/cmaps/GB-EUC-H.bcmap +0 -0
  71. package/public/cmaps/GB-EUC-V.bcmap +0 -0
  72. package/public/cmaps/GB-H.bcmap +4 -0
  73. package/public/cmaps/GB-V.bcmap +0 -0
  74. package/public/cmaps/GBK-EUC-H.bcmap +0 -0
  75. package/public/cmaps/GBK-EUC-V.bcmap +0 -0
  76. package/public/cmaps/GBK2K-H.bcmap +0 -0
  77. package/public/cmaps/GBK2K-V.bcmap +0 -0
  78. package/public/cmaps/GBKp-EUC-H.bcmap +0 -0
  79. package/public/cmaps/GBKp-EUC-V.bcmap +0 -0
  80. package/public/cmaps/GBT-EUC-H.bcmap +0 -0
  81. package/public/cmaps/GBT-EUC-V.bcmap +0 -0
  82. package/public/cmaps/GBT-H.bcmap +0 -0
  83. package/public/cmaps/GBT-V.bcmap +0 -0
  84. package/public/cmaps/GBTpc-EUC-H.bcmap +0 -0
  85. package/public/cmaps/GBTpc-EUC-V.bcmap +0 -0
  86. package/public/cmaps/GBpc-EUC-H.bcmap +0 -0
  87. package/public/cmaps/GBpc-EUC-V.bcmap +0 -0
  88. package/public/cmaps/H.bcmap +0 -0
  89. package/public/cmaps/HKdla-B5-H.bcmap +0 -0
  90. package/public/cmaps/HKdla-B5-V.bcmap +0 -0
  91. package/public/cmaps/HKdlb-B5-H.bcmap +0 -0
  92. package/public/cmaps/HKdlb-B5-V.bcmap +0 -0
  93. package/public/cmaps/HKgccs-B5-H.bcmap +0 -0
  94. package/public/cmaps/HKgccs-B5-V.bcmap +0 -0
  95. package/public/cmaps/HKm314-B5-H.bcmap +0 -0
  96. package/public/cmaps/HKm314-B5-V.bcmap +0 -0
  97. package/public/cmaps/HKm471-B5-H.bcmap +0 -0
  98. package/public/cmaps/HKm471-B5-V.bcmap +0 -0
  99. package/public/cmaps/HKscs-B5-H.bcmap +0 -0
  100. package/public/cmaps/HKscs-B5-V.bcmap +0 -0
  101. package/public/cmaps/Hankaku.bcmap +0 -0
  102. package/public/cmaps/Hiragana.bcmap +0 -0
  103. package/public/cmaps/KSC-EUC-H.bcmap +0 -0
  104. package/public/cmaps/KSC-EUC-V.bcmap +0 -0
  105. package/public/cmaps/KSC-H.bcmap +0 -0
  106. package/public/cmaps/KSC-Johab-H.bcmap +0 -0
  107. package/public/cmaps/KSC-Johab-V.bcmap +0 -0
  108. package/public/cmaps/KSC-V.bcmap +0 -0
  109. package/public/cmaps/KSCms-UHC-H.bcmap +0 -0
  110. package/public/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  111. package/public/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  112. package/public/cmaps/KSCms-UHC-V.bcmap +0 -0
  113. package/public/cmaps/KSCpc-EUC-H.bcmap +0 -0
  114. package/public/cmaps/KSCpc-EUC-V.bcmap +0 -0
  115. package/public/cmaps/Katakana.bcmap +0 -0
  116. package/public/cmaps/LICENSE +36 -0
  117. package/public/cmaps/NWP-H.bcmap +0 -0
  118. package/public/cmaps/NWP-V.bcmap +0 -0
  119. package/public/cmaps/RKSJ-H.bcmap +0 -0
  120. package/public/cmaps/RKSJ-V.bcmap +0 -0
  121. package/public/cmaps/Roman.bcmap +0 -0
  122. package/public/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  123. package/public/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  124. package/public/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  125. package/public/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  126. package/public/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  127. package/public/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  128. package/public/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  129. package/public/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  130. package/public/cmaps/UniGB-UCS2-H.bcmap +0 -0
  131. package/public/cmaps/UniGB-UCS2-V.bcmap +0 -0
  132. package/public/cmaps/UniGB-UTF16-H.bcmap +0 -0
  133. package/public/cmaps/UniGB-UTF16-V.bcmap +0 -0
  134. package/public/cmaps/UniGB-UTF32-H.bcmap +0 -0
  135. package/public/cmaps/UniGB-UTF32-V.bcmap +0 -0
  136. package/public/cmaps/UniGB-UTF8-H.bcmap +0 -0
  137. package/public/cmaps/UniGB-UTF8-V.bcmap +0 -0
  138. package/public/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  139. package/public/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  140. package/public/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  141. package/public/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  142. package/public/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  143. package/public/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  144. package/public/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  145. package/public/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  146. package/public/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  147. package/public/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  148. package/public/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  149. package/public/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  150. package/public/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  151. package/public/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  152. package/public/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  153. package/public/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  154. package/public/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  155. package/public/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  156. package/public/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  157. package/public/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  158. package/public/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  159. package/public/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  160. package/public/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  161. package/public/cmaps/UniKS-UCS2-H.bcmap +0 -0
  162. package/public/cmaps/UniKS-UCS2-V.bcmap +0 -0
  163. package/public/cmaps/UniKS-UTF16-H.bcmap +0 -0
  164. package/public/cmaps/UniKS-UTF16-V.bcmap +0 -0
  165. package/public/cmaps/UniKS-UTF32-H.bcmap +0 -0
  166. package/public/cmaps/UniKS-UTF32-V.bcmap +0 -0
  167. package/public/cmaps/UniKS-UTF8-H.bcmap +0 -0
  168. package/public/cmaps/UniKS-UTF8-V.bcmap +0 -0
  169. package/public/cmaps/V.bcmap +0 -0
  170. package/public/cmaps/WP-Symbol.bcmap +0 -0
  171. package/public/polyfills/polyfills.js +802 -0
  172. package/public/vendor/docx/docx.worker.js +5 -0
  173. package/public/vendor/docx/jszip.min.js +13 -0
  174. package/public/vendor/libarchive/libarchive.wasm +0 -0
  175. package/public/vendor/libarchive/worker-bundle.js +6 -0
  176. package/public/vendor/pptx/pptx.worker.js +26 -0
  177. package/public/wasm/cad/0.8.2/dwfv-render.wasm +0 -0
  178. package/public/wasm/cad/0.8.2/dwg-worker.js +24 -0
  179. package/public/wasm/cad/0.8.2/dwg-worker.js.map +1 -0
  180. package/public/wasm/cad/0.8.2/libredwg-web.js +2 -0
  181. package/public/wasm/cad/0.8.2/libredwg-web.wasm +0 -0
  182. package/public/wasm/cad/dwfv-render.wasm +0 -0
  183. package/public/wasm/cad/dwg-worker.js +24 -0
  184. package/public/wasm/cad/dwg-worker.js.map +1 -0
  185. package/public/wasm/cad/libredwg-web.js +2 -0
  186. package/public/wasm/cad/libredwg-web.wasm +0 -0
  187. package/public/wasm/data/sql-wasm.wasm +0 -0
  188. package/public/wasm/hdiff.wasm +0 -0
  189. package/public/wasm/model/LICENSE.occt-import-js.txt +504 -0
  190. package/public/wasm/model/LICENSE.occt.txt +502 -0
  191. package/public/wasm/model/occt-import-js.js +19 -0
  192. package/public/wasm/model/occt-import-js.wasm +0 -0
  193. package/public/wasm/model/occt-worker.js +83 -0
  194. package/public/wasm/typst/fonts/DejaVuSansMono-Bold.ttf +0 -0
  195. package/public/wasm/typst/fonts/DejaVuSansMono-BoldOblique.ttf +0 -0
  196. package/public/wasm/typst/fonts/DejaVuSansMono-Oblique.ttf +0 -0
  197. package/public/wasm/typst/fonts/DejaVuSansMono.ttf +0 -0
  198. package/public/wasm/typst/fonts/LibertinusSerif-Bold.otf +0 -0
  199. package/public/wasm/typst/fonts/LibertinusSerif-BoldItalic.otf +0 -0
  200. package/public/wasm/typst/fonts/LibertinusSerif-Italic.otf +0 -0
  201. package/public/wasm/typst/fonts/LibertinusSerif-Regular.otf +0 -0
  202. package/public/wasm/typst/fonts/LibertinusSerif-Semibold.otf +0 -0
  203. package/public/wasm/typst/fonts/LibertinusSerif-SemiboldItalic.otf +0 -0
  204. package/public/wasm/typst/fonts/NewCM10-Bold.otf +0 -0
  205. package/public/wasm/typst/fonts/NewCM10-BoldItalic.otf +0 -0
  206. package/public/wasm/typst/fonts/NewCM10-Italic.otf +0 -0
  207. package/public/wasm/typst/fonts/NewCM10-Regular.otf +0 -0
  208. package/public/wasm/typst/fonts/NewCMMath-Bold.otf +0 -0
  209. package/public/wasm/typst/fonts/NewCMMath-Book.otf +0 -0
  210. package/public/wasm/typst/fonts/NewCMMath-Regular.otf +0 -0
  211. package/public/wasm/typst/fonts/README.md +7 -0
  212. package/public/wasm/typst/typst_ts_renderer_bg.wasm +0 -0
  213. package/public/wasm/typst/typst_ts_web_compiler_bg.wasm +0 -0
  214. package/scripts/patch-docx-grid.cjs +412 -0
  215. package/src/api/_base.ts +243 -0
  216. package/src/api/index.ts +17 -0
  217. package/src/api/project.ts +1345 -0
  218. package/src/api/user.ts +1174 -0
  219. package/src/contract.ts +50 -0
  220. package/src/hooks/index.ts +2 -0
  221. package/{dist/hooks/index.js → src/hooks/useLongPress.ts} +53 -49
  222. package/src/hooks/useOnlineStatus.ts +22 -0
  223. package/src/index.ts +14 -0
  224. package/src/types/id.ts +2 -0
  225. package/src/types/index.ts +5 -0
  226. package/src/types/project/base.ts +63 -0
  227. package/src/types/project/contract.ts +79 -0
  228. package/src/types/project/contractStatus.tsx +15 -0
  229. package/src/types/project/index.ts +5 -0
  230. package/src/types/project/member.ts +46 -0
  231. package/src/types/project/progress.ts +43 -0
  232. package/src/types/projectRole.ts +17 -0
  233. package/src/types/theme.ts +1 -0
  234. package/src/types/user/index.ts +1 -0
  235. package/src/types/user/role.ts +7 -0
  236. package/src/ui/CommentTimeline/index.tsx +330 -0
  237. package/src/ui/FileManager/FileContextMenu.tsx +628 -0
  238. package/src/ui/FileManager/FileGridView.tsx +529 -0
  239. package/src/ui/FileManager/FileTableView.tsx +405 -0
  240. package/src/ui/FileManager/FileToolbar.tsx +119 -0
  241. package/src/ui/FileManager/FileVersionHistoryModal.tsx +175 -0
  242. package/src/ui/FileManager/MoveCopyToProjectModal.tsx +119 -0
  243. package/src/ui/FileManager/ShareToWechatModal.tsx +419 -0
  244. package/src/ui/FileManager/hooks/useFileManagerActions.ts +2532 -0
  245. package/src/ui/FileManager/hooks/useFileManagerState.ts +419 -0
  246. package/src/ui/FileManager/index.tsx +580 -0
  247. package/src/ui/FileManager/projectFileManagerApi.ts +57 -0
  248. package/src/ui/FileManager/types.ts +184 -0
  249. package/src/ui/FileManager/utils/fileDeltaWorker.ts +193 -0
  250. package/src/ui/FileManager/utils/fileTree.ts +178 -0
  251. package/src/ui/FileManager/utils/fileUpload.ts +714 -0
  252. package/src/ui/FileManager/utils/fileUtils.ts +65 -0
  253. package/src/ui/InvoiceRecordsList/index.tsx +813 -0
  254. package/src/ui/MyFileSelectorModal.tsx +261 -0
  255. package/src/ui/ProjectSelector/index.tsx +472 -0
  256. package/src/ui/ProjectSelector/projectCache.ts +40 -0
  257. package/src/ui/RoleSelector/index.tsx +473 -0
  258. package/src/ui/RoleSelector/roleCache.ts +40 -0
  259. package/src/ui/UIAlert.tsx +399 -0
  260. package/src/ui/UIAlertExample.tsx +129 -0
  261. package/src/ui/UIConfirm.tsx +335 -0
  262. package/src/ui/UIConfirmExample.tsx +165 -0
  263. package/src/ui/UIDatePicker.tsx +146 -0
  264. package/src/ui/UIDateRangePicker.tsx +38 -0
  265. package/src/ui/UIFilePreview/ExcelEditor/index.tsx +617 -0
  266. package/src/ui/UIFilePreview/ExcelEditor/types.ts +24 -0
  267. package/src/ui/UIFilePreview/ExportDropdown.css +85 -0
  268. package/src/ui/UIFilePreview/ExportDropdown.tsx +109 -0
  269. package/src/ui/UIFilePreview/IndexedDBUtils.ts +564 -0
  270. package/src/ui/UIFilePreview/MarkdownEditor/exportMarkdownPdf.ts +576 -0
  271. package/src/ui/UIFilePreview/MarkdownEditor/index.tsx +677 -0
  272. package/src/ui/UIFilePreview/MarkdownEditor/markdownEditor.css +1005 -0
  273. package/src/ui/UIFilePreview/MarkdownEditor/types.ts +15 -0
  274. package/src/ui/UIFilePreview/PPTXEditor/index.tsx +602 -0
  275. package/src/ui/UIFilePreview/RichDocEditor/exportRDocMarkdown.ts +77 -0
  276. package/src/ui/UIFilePreview/RichDocEditor/exportRDocPdf.ts +374 -0
  277. package/src/ui/UIFilePreview/RichDocEditor/index.tsx +730 -0
  278. package/src/ui/UIFilePreview/RichDocEditor/richdoc-editor.css +59 -0
  279. package/src/ui/UIFilePreview/UIFilePreview.tsx +611 -0
  280. package/src/ui/UIFilePreview/WordEditor/index.tsx +3933 -0
  281. package/src/ui/UIFilePreview/WordEditor/style.ts +1213 -0
  282. package/src/ui/UIFilePreview/WordEditor/word-editor.css +999 -0
  283. package/src/ui/UIFilePreview/filePreview.css +193 -0
  284. package/src/ui/UIFilePreview/filetypes/archive.tsx +66 -0
  285. package/src/ui/UIFilePreview/filetypes/cad.tsx +287 -0
  286. package/src/ui/UIFilePreview/filetypes/excel.tsx +355 -0
  287. package/src/ui/UIFilePreview/filetypes/image.tsx +20 -0
  288. package/src/ui/UIFilePreview/filetypes/imageLoader.ts +63 -0
  289. package/src/ui/UIFilePreview/filetypes/pdf.tsx +156 -0
  290. package/src/ui/UIFilePreview/filetypes/ppt.tsx +535 -0
  291. package/src/ui/UIFilePreview/filetypes/pptExportPdf.ts +523 -0
  292. package/src/ui/UIFilePreview/filetypes/video.tsx +482 -0
  293. package/src/ui/UIFilePreview/filetypes/word.tsx +245 -0
  294. package/src/ui/UIFilePreview/filetypes/wordExportMarkdown.ts +86 -0
  295. package/src/ui/UIFilePreview/filetypes/wordExportPdf.tsx +427 -0
  296. package/src/ui/UIFilePreview/index.ts +35 -0
  297. package/src/ui/UIFilePreview/pdfPagination.ts +143 -0
  298. package/src/ui/UIFilePreview/previewUtils.tsx +531 -0
  299. package/src/ui/UIFileUpload.tsx +382 -0
  300. package/src/ui/UIImageUpload.tsx +195 -0
  301. package/src/ui/UILoading.tsx +255 -0
  302. package/src/ui/UILoadingExample.tsx +139 -0
  303. package/src/ui/UISelect.tsx +105 -0
  304. package/src/ui/UIToast.tsx +381 -0
  305. package/src/ui/UIToastExample.tsx +69 -0
  306. package/src/ui/UIToastSingle.tsx +279 -0
  307. package/src/ui/UIViewToggle.tsx +64 -0
  308. package/src/ui/UserSelector/index.tsx +583 -0
  309. package/src/ui/index.ts +84 -0
  310. package/src/ui/upload/image.ts +135 -0
  311. package/src/ui/upload/index.ts +73 -0
  312. package/src/ui/upload/submitFile.ts +106 -0
  313. package/src/ui/upload/submitForm.ts +124 -0
  314. package/src/ui/upload/upload.err.ts +15 -0
  315. package/src/ui/upload/upload.ts +250 -0
  316. package/src/utils/CacheDepartmentInfo.ts +372 -0
  317. package/src/utils/CacheFileContent.ts +315 -0
  318. package/src/utils/CachePermissionInfo.ts +235 -0
  319. package/src/utils/CacheRoleInfo.ts +303 -0
  320. package/src/utils/CacheUserInfo.ts +818 -0
  321. package/src/utils/CacheViewToggleInfo.ts +182 -0
  322. package/src/utils/MessageContentUtils.ts +268 -0
  323. package/src/utils/clipboard.ts +70 -0
  324. package/src/utils/companyEmail.ts +19 -0
  325. package/src/utils/forbidDebugger.ts +59 -0
  326. package/src/utils/formatters.ts +94 -0
  327. package/src/utils/htmlUtils.tsx +59 -0
  328. package/src/utils/index.ts +18 -0
  329. package/src/utils/keyboard.ts +114 -0
  330. package/src/utils/mammothApi.ts +16 -0
  331. package/src/utils/polyfills.ts +928 -0
  332. package/src/utils/regex.ts +14 -0
  333. package/src/utils/storage.ts +95 -0
  334. package/src/utils/workerBootstrap.ts +87 -0
  335. package/dist/api/index.js +0 -1553
  336. package/dist/contract.js +0 -5
  337. package/dist/index.js +0 -4492
  338. package/dist/types/index.js +0 -49
  339. package/dist/ui/index.css +0 -1876
  340. package/dist/ui/index.js +0 -22245
  341. package/dist/utils/index.js +0 -4296
  342. /package/{dist → src}/styles/ant-modal.css +0 -0
  343. /package/{dist → src}/styles/ant-spin.css +0 -0
  344. /package/{dist → src}/styles/ant-table.css +0 -0
  345. /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
+ };