@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,405 @@
1
+ import React, { memo, useCallback, useMemo, useState } from 'react';
2
+ import { useLongPress } from '../../hooks/useLongPress';
3
+ import { Table, Dropdown, MenuProps, TableProps, Tag } from 'antd';
4
+ import type { SortOrder } from 'antd/es/table/interface';
5
+ import { ProjectFile, FileSortBy } from './types';
6
+ import { formatDatetime, formatDisksize } from '../../utils/formatters';
7
+ import { uiFilePreview } from '../UIFilePreview/index';
8
+ import { FileContextMenu } from './FileContextMenu';
9
+ import { CheckOutlined, CloudOutlined, WarningOutlined, LinkOutlined } from '@ant-design/icons';
10
+ import { getDisplayName } from './utils/fileUtils';
11
+ import { sortTree } from './utils/fileTree';
12
+
13
+ interface FileTableViewProps {
14
+ dataSource: ProjectFile[];
15
+ expandedRowKeys: string[];
16
+ selectedFolderId: string | null;
17
+ dragOverId: string | null;
18
+ dragSourceId: string | null;
19
+ smallView: boolean;
20
+ isFolderExpanded: (folderId: string) => boolean;
21
+ onExpand: (expanded: boolean, record: ProjectFile) => void;
22
+ onPreview: (file: ProjectFile) => void;
23
+ onDownload: (file: ProjectFile) => void;
24
+ /** 下载文件夹回调(仅管理员/负责人提供,表格行右键菜单复用该回调) */
25
+ onDownloadFolder?: (file: ProjectFile) => void;
26
+ /** 复制链接回调(未提供时不显示「复制链接」) */
27
+ onCopyLink?: (file: ProjectFile) => void;
28
+ onRename: (file: ProjectFile) => void;
29
+ onEditDescs: (file: ProjectFile) => void;
30
+ onDelete: (fileId: string) => void;
31
+ onEdit?: (file: ProjectFile) => void;
32
+ /** 生成临时文件链接回调 */
33
+ onGenerateTempLink?: (file: ProjectFile) => void;
34
+ onMove: (sourceId: string, targetId: string | null) => void;
35
+ onDragStart: (fileId: string) => void;
36
+ onDragEnd: () => void;
37
+ onDragOver: (fileId: string) => void;
38
+ onDragLeave: (fileId: string) => void;
39
+ onDrop: (sourceId: string, targetId: string) => void;
40
+ onRowContextMenu: (event: React.MouseEvent, record: ProjectFile) => void;
41
+ /** 移动到其他项目回调 */
42
+ onMoveToProject?: (file: ProjectFile) => void;
43
+ /** 复制到其他项目回调 */
44
+ onCopyToProject?: (file: ProjectFile) => void;
45
+ /** 复制副本回调 */
46
+ onCopyToSelf?: (file: ProjectFile) => void;
47
+ /** 查看文件历史版本回调 */
48
+ onViewVersionHistory?: (file: ProjectFile) => void;
49
+ /** 跳转至合同回调 */
50
+ onJumpToContract?: (file: ProjectFile) => void;
51
+ /** 排序字段 */
52
+ sortBy: FileSortBy;
53
+ /** 排序顺序 */
54
+ sortOrder: 'asc' | 'desc';
55
+ /** 切换排序字段回调(如果是相同字段则切换顺序) */
56
+ onSortByChange: (by: FileSortBy) => void;
57
+ }
58
+
59
+ // antd 通过 sortDirections.indexOf(当前顺序) + 1 计算下一次排序;
60
+ // 只给两个方向时,第三次点击会进入“取消排序”并丢失 columnKey,导致只能排序一次。
61
+ // 末尾重复 ascend 可让顺序在“升序 → 降序 → 升序”之间无限循环。
62
+ const SORT_DIRECTIONS: SortOrder[] = ['ascend', 'descend', 'ascend'];
63
+
64
+ const NAME_COL_MIN_WIDTH = 120;
65
+ const NAME_COL_DEFAULT_WIDTH = 400;
66
+
67
+ interface ResizableTitleProps extends React.HTMLAttributes<HTMLTableCellElement> {
68
+ width?: number;
69
+ onResizeStart?: (e: React.MouseEvent) => void;
70
+ }
71
+
72
+ // 可拖拽调宽的表头单元格:仅有 onResizeStart 的列(名称列)渲染拖拽手柄
73
+ const ResizableTitle: React.FC<ResizableTitleProps> = (props) => {
74
+ const { width, onResizeStart, style, children, ...restProps } = props;
75
+ if (!width || !onResizeStart) {
76
+ return <th style={style} {...restProps}>{children}</th>;
77
+ }
78
+ return (
79
+ <th style={{ ...style, position: 'relative' }} {...restProps}>
80
+ {children}
81
+ <span
82
+ className="file-table-col-resizer"
83
+ onMouseDown={onResizeStart}
84
+ onClick={(e) => e.stopPropagation()}
85
+ onDoubleClick={(e) => e.stopPropagation()}
86
+ />
87
+ </th>
88
+ );
89
+ };
90
+
91
+ const FileTableViewComponent: React.FC<FileTableViewProps> = ({
92
+ dataSource,
93
+ expandedRowKeys,
94
+ selectedFolderId,
95
+ dragOverId,
96
+ dragSourceId,
97
+ smallView,
98
+ isFolderExpanded,
99
+ onExpand,
100
+ onPreview,
101
+ onDownload,
102
+ onCopyLink,
103
+ onRename,
104
+ onEditDescs,
105
+ onDelete,
106
+ onEdit,
107
+ onGenerateTempLink,
108
+ onMove,
109
+ onDragStart,
110
+ onDragEnd,
111
+ onDragOver,
112
+ onDragLeave,
113
+ onDrop,
114
+ onRowContextMenu,
115
+ onMoveToProject,
116
+ onCopyToProject,
117
+ onCopyToSelf,
118
+ onViewVersionHistory,
119
+ onJumpToContract,
120
+ sortBy,
121
+ sortOrder,
122
+ onSortByChange,
123
+ }) => {
124
+ const { handleTouchStart, handleTouchMove, handleTouchEnd, handleTouchCancel, wasLongPressed, resetLongPress } = useLongPress<ProjectFile>(
125
+ (record, e) => {
126
+ const touch = e.touches[0];
127
+ const mockEvent = {
128
+ preventDefault: () => {},
129
+ stopPropagation: () => {},
130
+ clientX: touch.clientX,
131
+ clientY: touch.clientY,
132
+ } as unknown as React.MouseEvent;
133
+ onRowContextMenu(mockEvent, record);
134
+ },
135
+ { delay: 500, smallView }
136
+ );
137
+
138
+ // 排序后的数据
139
+ const sortedDataSource = useMemo(() => {
140
+ return sortTree(dataSource, sortBy, sortOrder);
141
+ }, [dataSource, sortBy, sortOrder]);
142
+
143
+ // 名称列宽度(表头右侧手柄拖拽调节)
144
+ const [nameColWidth, setNameColWidth] = useState(NAME_COL_DEFAULT_WIDTH);
145
+
146
+ const handleNameColResizeStart = useCallback((e: React.MouseEvent) => {
147
+ e.preventDefault();
148
+ e.stopPropagation();
149
+ const startX = e.clientX;
150
+ const startWidth = nameColWidth;
151
+ const handleMove = (ev: MouseEvent) => {
152
+ setNameColWidth(Math.max(NAME_COL_MIN_WIDTH, startWidth + ev.clientX - startX));
153
+ };
154
+ const handleUp = () => {
155
+ document.removeEventListener('mousemove', handleMove);
156
+ document.removeEventListener('mouseup', handleUp);
157
+ document.body.style.cursor = '';
158
+ document.body.style.userSelect = '';
159
+ };
160
+ document.addEventListener('mousemove', handleMove);
161
+ document.addEventListener('mouseup', handleUp);
162
+ document.body.style.cursor = 'col-resize';
163
+ document.body.style.userSelect = 'none';
164
+ }, [nameColWidth]);
165
+
166
+ const handleTableChange: TableProps<ProjectFile>['onChange'] = (_pagination, _filters, sorter) => {
167
+ const active = Array.isArray(sorter) ? sorter[0] : sorter;
168
+ const by = active?.columnKey as FileSortBy | undefined;
169
+ if (by !== 'fileName' && by !== 'fileSize' && by !== 'uploadTime') return;
170
+ // 相同字段由上层切换升/降序:antd 第三次点击会给出“取消排序”,这里忽略 order,保证升序↔降序循环
171
+ onSortByChange(by);
172
+ };
173
+
174
+ // 表头排序箭头状态:仅当前排序字段显示箭头
175
+ const columnSortOrder = (by: FileSortBy): 'ascend' | 'descend' | null =>
176
+ sortBy === by ? (sortOrder === 'asc' ? 'ascend' : 'descend') : null;
177
+
178
+ const handleRowClick = (record: ProjectFile) => () => {
179
+ if (!wasLongPressed(record)) {
180
+ if (record.fileType === 'folder') {
181
+ onExpand(!isFolderExpanded(record.id), record);
182
+ }
183
+ }
184
+ resetLongPress(record);
185
+ };
186
+ const indentSize = smallView ? 12 : 16;
187
+
188
+ const columnsBase = [
189
+ {
190
+ title: '名称',
191
+ dataIndex: 'fileName',
192
+ key: 'fileName',
193
+ width: nameColWidth,
194
+ onHeaderCell: () => ({
195
+ width: nameColWidth,
196
+ onResizeStart: handleNameColResizeStart,
197
+ }),
198
+ sorter: true,
199
+ sortDirections: SORT_DIRECTIONS,
200
+ sortOrder: columnSortOrder('fileName'),
201
+ render: (fileName: string, record: ProjectFile) => (
202
+ <div
203
+ style={{ paddingLeft: `${record.level ? record.level * indentSize + 8 : 8}px`, minWidth: 0, opacity: (record.isContractSubfolder || record.isContractLink) && record.contractSigned === false ? 0.55 : undefined }}
204
+ onContextMenu={(e) => {
205
+ e.preventDefault();
206
+ e.stopPropagation();
207
+ onRowContextMenu(e, record);
208
+ }}
209
+ >
210
+ <div className='flex items-center overflow-hidden'>
211
+ {uiFilePreview.getFileIcon({
212
+ fileName,
213
+ fileType: record.fileType,
214
+ isExpanded: isFolderExpanded(record.id),
215
+ isSecure: record.isSecure,
216
+ isVirtualContractFolder: record.isVirtualContractFolder,
217
+ isContractSubfolder: record.isContractSubfolder,
218
+ isContractTagFolder: record.isContractTagFolder,
219
+ contractSigned: record.contractSigned,
220
+ })}
221
+ {record.isContractLink && (
222
+ <LinkOutlined className='ml-1 text-green-600' style={{ fontSize: 12 }} />
223
+ )}
224
+ <span
225
+ className={`truncate ml-1 flex-1 ${record.isContractLink ? 'hover:underline cursor-pointer' : ''}`}
226
+ title={record.isContractLink ? `合同附件${record.descs ? `(${record.descs})` : ''}` : getDisplayName(fileName, { isVirtualContractFolder: record.isVirtualContractFolder, isContractSubfolder: record.isContractSubfolder, descs: record.descs })}
227
+ >
228
+ {getDisplayName(fileName, { isVirtualContractFolder: record.isVirtualContractFolder, isContractSubfolder: record.isContractSubfolder, descs: record.descs })}
229
+ </span>
230
+ {record.isContractSubfolder && record.contractSigned === false && (
231
+ <Tag
232
+ className="ml-1"
233
+ style={{ marginInlineStart: 4 }}
234
+ title="该合同尚未签约,签约后盖章文件会显示在此文件夹中"
235
+ >
236
+ 未签约
237
+ </Tag>
238
+ )}
239
+ {record.isLocalOnly && (
240
+ <Tag
241
+ icon={<CloudOutlined />}
242
+ color="orange"
243
+ className="ml-1"
244
+ style={{ marginInlineStart: 4 }}
245
+ title="仅保存在本地,尚未上传到服务器"
246
+ >
247
+ 本地
248
+ </Tag>
249
+ )}
250
+ {!record.isLocalOnly && record.hasUnsyncedChanges && (
251
+ <Tag
252
+ icon={<WarningOutlined />}
253
+ color="warning"
254
+ className="ml-1"
255
+ style={{ marginInlineStart: 4 }}
256
+ title="本地有未同步的修改,重新上传后可与服务器一致"
257
+ >
258
+ 未同步
259
+ </Tag>
260
+ )}
261
+ {record.hasLocalCache && (
262
+ <span className="ml-1 flex h-3 w-3 items-center justify-center rounded-full bg-green-600 text-white" title="已缓存到本地">
263
+ <CheckOutlined className="w-2 h-2" />
264
+ </span>
265
+ )}
266
+ </div>
267
+ </div>
268
+ ),
269
+ },
270
+ {
271
+ title: '大小',
272
+ dataIndex: 'fileSize',
273
+ key: 'fileSize',
274
+ width: 85,
275
+ className: 'font-thin',
276
+ sorter: true,
277
+ sortDirections: SORT_DIRECTIONS,
278
+ sortOrder: columnSortOrder('fileSize'),
279
+ render: (size: number) => (size == 0 ? '' : formatDisksize(size)),
280
+ },
281
+ ];
282
+
283
+ const columnsDesc =
284
+ {
285
+ title: '备注',
286
+ dataIndex: 'descs',
287
+ key: 'descs',
288
+ className: 'font-thin',
289
+ ellipsis: true,
290
+ render: (descs: string) => descs || '',
291
+ };
292
+
293
+ const columnsTablet = [
294
+ {
295
+ title: '上传人',
296
+ dataIndex: 'uploaderName',
297
+ key: 'uploaderName',
298
+ width: 80,
299
+ className: 'font-thin',
300
+ },
301
+ {
302
+ title: '上传时间',
303
+ dataIndex: 'uploadTime',
304
+ key: 'uploadTime',
305
+ width: 140,
306
+ className: 'font-thin',
307
+ sorter: true,
308
+ sortDirections: SORT_DIRECTIONS,
309
+ sortOrder: columnSortOrder('uploadTime'),
310
+ render: (date: Date) => formatDatetime(date),
311
+ },
312
+ ];
313
+
314
+
315
+ const columns = smallView
316
+ ? columnsBase
317
+ : columnsBase.concat(columnsTablet as any);
318
+
319
+ columns.push(columnsDesc as any);
320
+
321
+ const getRowClassName = (record: ProjectFile) => {
322
+ if (record.fileType === 'folder' && record.id === selectedFolderId) {
323
+ return 'file-table-row-highlight';
324
+ }
325
+ if (record.fileType === 'folder' && dragOverId === record.id) {
326
+ return 'file-table-row-highlight';
327
+ }
328
+ return '';
329
+ };
330
+
331
+ return (
332
+ <div>
333
+ <Table
334
+ className='file-manager-table'
335
+ scroll={{ x: 800 }}
336
+ components={{ header: { cell: ResizableTitle } }}
337
+ columns={columns}
338
+ dataSource={sortedDataSource}
339
+ loading={false}
340
+ rowKey="id"
341
+ pagination={false}
342
+ size="small"
343
+ onChange={handleTableChange}
344
+ expandable={{
345
+ expandedRowKeys,
346
+ onExpand,
347
+ rowExpandable: (record: ProjectFile) => record.fileType === 'folder',
348
+ }}
349
+ expandIcon={() => null}
350
+ onRow={(record: ProjectFile) => ({
351
+ style: { cursor: 'pointer' },
352
+ title: record.isSecure ? '仅管理员可见' : getDisplayName(record.fileName, { isVirtualContractFolder: record.isVirtualContractFolder, isContractSubfolder: record.isContractSubfolder, descs: record.descs }),
353
+ draggable: !record.isContractLink && !record.isVirtualContractFolder && !record.isContractSubfolder && !record.isContractTagFolder,
354
+ onDragStart: (event) => {
355
+ if (record.isContractLink || record.isVirtualContractFolder || record.isContractSubfolder || record.isContractTagFolder) {
356
+ event.preventDefault();
357
+ return;
358
+ }
359
+ event.dataTransfer.setData('text/plain', record.id);
360
+ onDragStart(record.id);
361
+ },
362
+ onDragEnd: () => {
363
+ onDragEnd();
364
+ },
365
+ onDragOver: (event) => {
366
+ if (record.fileType === 'folder') {
367
+ event.preventDefault();
368
+ onDragOver(record.id);
369
+ }
370
+ },
371
+ onDragLeave: () => {
372
+ if (dragOverId === record.id) {
373
+ onDragLeave(record.id);
374
+ }
375
+ },
376
+ onDrop: (event) => {
377
+ if (record.fileType === 'folder') {
378
+ event.preventDefault();
379
+ const sourceId = event.dataTransfer.getData('text/plain');
380
+ if (sourceId) {
381
+ onDrop(sourceId, record.id);
382
+ }
383
+ }
384
+ },
385
+ onDoubleClick: () => {
386
+ if (record.fileType !== 'folder') {
387
+ onPreview(record);
388
+ }
389
+ },
390
+ onClick: handleRowClick(record),
391
+ onTouchStart: handleTouchStart(record),
392
+ onTouchMove: handleTouchMove(record),
393
+ onTouchEnd: handleTouchEnd(record),
394
+ onTouchCancel: handleTouchCancel(record),
395
+ onContextMenu: (event) => {
396
+ onRowContextMenu(event as any, record);
397
+ },
398
+ })}
399
+ rowClassName={getRowClassName}
400
+ />
401
+ </div>
402
+ );
403
+ };
404
+
405
+ export const FileTableView = memo(FileTableViewComponent);
@@ -0,0 +1,119 @@
1
+ import React, { useState, memo } from 'react';
2
+ import { Button, Dropdown, Divider, UploadFile } from 'antd';
3
+ import { FolderAddOutlined, FileMarkdownFilled, FileExcelFilled, FileWordFilled, CaretDownOutlined, FileTextFilled } from '@ant-design/icons';
4
+ import { UIFileUpload } from '../UIFileUpload';
5
+ import { UITableGridViewToggle } from '../UIViewToggle';
6
+ import { Space } from 'antd';
7
+ import { ProjectRole } from './types';
8
+
9
+ interface FileToolbarProps {
10
+ currentUserRole: ProjectRole | null;
11
+ viewMode: 'table' | 'grid';
12
+ onToggleViewMode: (mode: 'table' | 'grid') => void;
13
+ onCreateFolder: () => void;
14
+ onCreateMarkdown: () => void;
15
+ onCreateRdoc: () => void;
16
+ onCreateExcel: () => void;
17
+ onCreateWord: () => void;
18
+ onUploadFiles: (fileList: UploadFile[], serverData: any) => Promise<void> | void;
19
+ }
20
+
21
+ const FileToolbarComponent: React.FC<FileToolbarProps> = ({
22
+ currentUserRole,
23
+ viewMode,
24
+ onToggleViewMode,
25
+ onCreateFolder,
26
+ onCreateMarkdown,
27
+ onCreateRdoc,
28
+ onCreateExcel,
29
+ onCreateWord,
30
+ onUploadFiles,
31
+ }) => {
32
+ const [uploadFileList, setUploadFileList] = useState<UploadFile[]>([]);
33
+
34
+ // 项目所有者/管理员:可新建文件夹、文档并上传文件
35
+ const canManage = currentUserRole === ProjectRole.MANAGER || currentUserRole === ProjectRole.OWNER;
36
+ // 后端策略调整:普通成员也可以上传文件;仅查看者等其他角色保持只读
37
+ const canUpload = canManage || currentUserRole === ProjectRole.MEMBER;
38
+
39
+ return (
40
+ <Space>
41
+ {canManage && (
42
+ <Dropdown
43
+ menu={{
44
+ items: [
45
+ {
46
+ key: '1',
47
+ label: (
48
+ <>
49
+ <FolderAddOutlined className="text-blue-400 mr-1" /> 新建文件夹
50
+ </>
51
+ ),
52
+ onClick: onCreateFolder,
53
+ },
54
+ {
55
+ key: '6',
56
+ label: (
57
+ <>
58
+ <FileTextFilled className="text-yellow-600 mr-1" /> 新建文档
59
+ </>
60
+ ),
61
+ onClick: onCreateRdoc,
62
+ },
63
+ {
64
+ key: '2',
65
+ label: (
66
+ <>
67
+ <FileMarkdownFilled className="text-gray-800 mr-1" /> 新建Markdown
68
+ </>
69
+ ),
70
+ onClick: onCreateMarkdown,
71
+ },
72
+ {
73
+ key: '3',
74
+ label: (
75
+ <>
76
+ <FileWordFilled className="text-blue-600 mr-1" /> 新建Word
77
+ </>
78
+ ),
79
+ onClick: onCreateWord,
80
+ },
81
+ {
82
+ key: '5',
83
+ label: (
84
+ <>
85
+ <FileExcelFilled className="text-green-600 mr-1" /> 新建Excel
86
+ </>
87
+ ),
88
+ onClick: onCreateExcel,
89
+ },
90
+ ],
91
+ }}
92
+ placement="bottom"
93
+ >
94
+ <Button type="text">
95
+ 新建 <CaretDownOutlined />
96
+ </Button>
97
+ </Dropdown>
98
+ )}
99
+ {canUpload && (
100
+ <UIFileUpload
101
+ fileList={uploadFileList}
102
+ onFinish={async (fileList, serverData) => {
103
+ await onUploadFiles(fileList, serverData);
104
+ setUploadFileList([]);
105
+ }}
106
+ onChange={setUploadFileList}
107
+ multiple={false}
108
+ />
109
+ )}
110
+ <Divider type="vertical" />
111
+ <UITableGridViewToggle
112
+ viewMode={viewMode}
113
+ onToggle={onToggleViewMode}
114
+ />
115
+ </Space>
116
+ );
117
+ };
118
+
119
+ export const FileToolbar = memo(FileToolbarComponent);
@@ -0,0 +1,175 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { Modal, Table, Spin, Empty, Button, Space, message } from 'antd';
3
+ import { HistoryOutlined, DownloadOutlined, EyeOutlined, FileOutlined } from '@ant-design/icons';
4
+ import { API } from '../../api/index';
5
+ import { ResponseCode } from '../../api/_base';
6
+ import { uiFilePreview, UIFilePreview } from '../UIFilePreview/index';
7
+ import { ProjectFile } from './types';
8
+ import { formatDatetime, formatDisksize } from '../../utils/formatters';
9
+ import { ColumnsType } from 'antd/es/table';
10
+
11
+ interface FileVersion {
12
+ id: string;
13
+ fileId: string;
14
+ fileSize: number;
15
+ fileResourcePath: string;
16
+ uploadTime: Date;
17
+ uploaderName: string;
18
+ uploadBy: string;
19
+ }
20
+
21
+ interface FileVersionHistoryModalProps {
22
+ visible: boolean;
23
+ file: ProjectFile | null;
24
+ onClose: () => void;
25
+ }
26
+
27
+ export const FileVersionHistoryModal: React.FC<FileVersionHistoryModalProps> = ({
28
+ visible,
29
+ file,
30
+ onClose,
31
+ }) => {
32
+ const [loading, setLoading] = useState(false);
33
+ const [versions, setVersions] = useState<FileVersion[]>([]);
34
+ const [previewUrl, setPreviewUrl] = useState<string | null>(null);
35
+ const [previewVisible, setPreviewVisible] = useState(false);
36
+
37
+ const loadVersions = useCallback(async () => {
38
+ if (!file) return;
39
+
40
+ setLoading(true);
41
+ try {
42
+ const res = await API.project.fileversion.listVersions({ fileId: file.id });
43
+ if (res.code === ResponseCode.SUCCESS && res.data) {
44
+ setVersions(res.data);
45
+ } else {
46
+ message.error('获取文件历史版本失败');
47
+ }
48
+ } catch (error) {
49
+ message.error('获取文件历史版本失败');
50
+ } finally {
51
+ setLoading(false);
52
+ }
53
+ }, [file]);
54
+
55
+ useEffect(() => {
56
+ if (visible && file) {
57
+ loadVersions();
58
+ } else {
59
+ setVersions([]);
60
+ }
61
+ }, [visible, file, loadVersions]);
62
+
63
+ const handlePreview = (version: FileVersion) => {
64
+ setPreviewUrl(version.fileResourcePath);
65
+ setPreviewVisible(true);
66
+ };
67
+
68
+ const handleDownload = (version: FileVersion) => {
69
+ uiFilePreview.downloadFile(version.fileResourcePath, undefined, version.fileId)
70
+ .catch(() => {
71
+ // downloadFile 内部已统一提示下载失败
72
+ });
73
+ };
74
+
75
+ const columns: ColumnsType<FileVersion> = [
76
+ {
77
+ title: '版本',
78
+ key: 'version',
79
+ width: 80,
80
+ render: (_: any, __: any, index: number) => (
81
+ <span className="text-blue-600">v{versions.length - index}</span>
82
+ ),
83
+ },
84
+ {
85
+ title: '文件大小',
86
+ dataIndex: 'fileSize',
87
+ key: 'fileSize',
88
+ width: 100,
89
+ render: (size: number) => formatDisksize(size),
90
+ },
91
+ {
92
+ title: '上传时间',
93
+ dataIndex: 'uploadTime',
94
+ key: 'uploadTime',
95
+ width: 160,
96
+ render: (time: Date) => formatDatetime(time),
97
+ },
98
+ {
99
+ title: '上传人',
100
+ dataIndex: 'uploaderName',
101
+ key: 'uploaderName',
102
+ width: 100,
103
+ },
104
+ {
105
+ title: '操作',
106
+ key: 'action',
107
+ width: 120,
108
+ render: (_: any, record: FileVersion) => (
109
+ <Space>
110
+ <Button
111
+ type="text"
112
+ icon={<EyeOutlined />}
113
+ onClick={() => handlePreview(record)}
114
+ title="预览"
115
+ />
116
+ <Button
117
+ type="text"
118
+ icon={<DownloadOutlined />}
119
+ onClick={() => handleDownload(record)}
120
+ title="下载"
121
+ />
122
+ </Space>
123
+ ),
124
+ },
125
+ ];
126
+
127
+ return (
128
+ <>
129
+ <Modal
130
+ title={
131
+ <div className="flex items-center">
132
+ <HistoryOutlined className="mr-2" />
133
+ <span>文件历史版本 - {file?.fileName}</span>
134
+ </div>
135
+ }
136
+ open={visible}
137
+ onCancel={onClose}
138
+ footer={null}
139
+ width={720}
140
+ destroyOnHidden
141
+ >
142
+ <div className="py-4">
143
+ {loading ? (
144
+ <div className="flex justify-center items-center py-12">
145
+ <Spin />
146
+ </div>
147
+ ) : versions.length === 0 ? (
148
+ <Empty description="暂无历史版本" className="py-12" />
149
+ ) : (
150
+ <Table
151
+ columns={columns}
152
+ dataSource={versions}
153
+ rowKey="id"
154
+ pagination={false}
155
+ scroll={{ y: 400 }}
156
+ size="middle"
157
+ />
158
+ )}
159
+ </div>
160
+ </Modal>
161
+
162
+ {/* 文件预览 */}
163
+ <UIFilePreview
164
+ fileUrl={previewUrl}
165
+ fileName={file?.fileName}
166
+ visible={previewVisible}
167
+ onClose={() => setPreviewVisible(false)}
168
+ editable={false}
169
+ uploadPercent={undefined}
170
+ />
171
+ </>
172
+ );
173
+ };
174
+
175
+ export default FileVersionHistoryModal;