@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,818 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Copyright (c) 2025 SPACECORE Co.,Ltd. All Rights Reserved.
5
+ * Author: brian.li
6
+ * Date: 2025-04-02 11:43
7
+ * Desc: 用户信息工具类 - 支持Dexie缓存
8
+ *
9
+ * @example 使用方法
10
+ *
11
+ * // 1. 获取当前登录用户信息
12
+ * import { CacheUserInfo } from './CacheUserInfo';
13
+ * const userInfo = await CacheUserInfo.getUserInfo({});
14
+ * console.log(userInfo?.nickname);
15
+ *
16
+ * // 2. 获取指定用户信息
17
+ * const userInfo = await CacheUserInfo.getUserInfo({ user_id: 'user123' });
18
+ *
19
+ * // 3. 强制刷新缓存(不使用缓存)
20
+ * const userInfo = await CacheUserInfo.getUserInfo({ user_id: 'user123', forceRefresh: true });
21
+ *
22
+ * // 4. 批量获取多个用户信息
23
+ * import { CacheUserInfo } from './CacheUserInfo';
24
+ * const userMap = await CacheUserInfo.getUserInfos({ userIds: ['user1', 'user2', 'user3'] });
25
+ * const user1Info = userMap.get('user1');
26
+ *
27
+ * // 5. 清除用户缓存
28
+ * import { CacheUserInfo } from './CacheUserInfo';
29
+ * await CacheUserInfo.clearUserCache(); // 清除所有缓存
30
+ * await CacheUserInfo.clearUserCache('user123'); // 清除指定用户缓存
31
+ *
32
+ * // 6. 获取缓存统计信息
33
+ * import { CacheUserInfo } from './CacheUserInfo';
34
+ * const stats = await CacheUserInfo.getCacheStats();
35
+ * console.log(`缓存数量: ${stats.count}`);
36
+ */
37
+
38
+ import * as febs from 'febs-browser';
39
+ import Dexie, { Table } from 'dexie';
40
+ import { API } from "../api";
41
+ import { AuthorizationHandler, ResponseCode } from "../api/_base";
42
+ import { storage } from "./storage";
43
+
44
+ /** 用户信息缓存时间(毫秒)24小时 */
45
+ const CACHE_EXPIRATION_MS = 24 * 60 * 60 * 1000;
46
+
47
+ /** 用户头像缓存数据结构 */
48
+ interface UserAvatarCache {
49
+ id: string;
50
+ avatar: {
51
+ avatar: string | undefined;
52
+ avatar_small: string | undefined;
53
+ avatar_tick: number;
54
+ }
55
+ timestamp: number;
56
+ }
57
+
58
+ /** 用户信息缓存数据结构 */
59
+ interface UserInfoCache {
60
+ id: string;
61
+ data: UserInfo;
62
+ timestamp: number;
63
+ }
64
+
65
+ /** 用户信息数据类型 */
66
+ export interface UserInfo {
67
+ avatar?: {
68
+ avatar: string | undefined;
69
+ avatar_small: string | undefined;
70
+ avatar_tick: number;
71
+ };
72
+ phone: string;
73
+ nickname: string;
74
+ username: string;
75
+ id: string;
76
+ is_forbidden: boolean;
77
+ role_ids: string[];
78
+ isAdmin: boolean;
79
+ email: string;
80
+ /** 后端保存的可显示模块 JSON 字符串。 */
81
+ displayModules?: string;
82
+ title: string;
83
+ manager_id: string;
84
+ created_at: Date;
85
+ thirdPlatformInfo?: { platform_user_id: string; platform_type: string }[] | null;
86
+ unreadMessageCount?: number;
87
+ tick_avatar_self?: number;
88
+
89
+ departmentInfo?: UserDepartmentInfo;
90
+ }
91
+
92
+ export interface UserDepartmentInfo {
93
+ departments?: {
94
+ id: string;
95
+ name: string;
96
+ position?: string;
97
+ }[];
98
+ department_ids?: string[];
99
+ department_names?: string[];
100
+ }
101
+
102
+ /** Dexie 数据库类 */
103
+ class UserInfoDatabase extends Dexie {
104
+ userCache!: Table<UserInfoCache, string>;
105
+
106
+ constructor() {
107
+ super('UserInfoDB');
108
+ this.version(1).stores({
109
+ userCache: 'id, timestamp'
110
+ });
111
+ }
112
+ }class UserAvatarDatabase extends Dexie {
113
+ userCache!: Table<UserAvatarCache, string>;
114
+
115
+ constructor() {
116
+ super('UserAvatarDB');
117
+ this.version(1).stores({
118
+ userCache: 'id, timestamp'
119
+ });
120
+ }
121
+ }
122
+
123
+ /** 单例数据库实例 */
124
+ const db = new UserInfoDatabase();
125
+ const avatarDb = new UserAvatarDatabase();
126
+
127
+ /**
128
+ * 从缓存获取用户头像
129
+ * @param userId 用户ID
130
+ * @returns 缓存的用户信息或null
131
+ */
132
+ const getAvatarFromCache = async (userId: string): Promise<{
133
+ avatar: string | undefined;
134
+ avatar_small: string | undefined;
135
+ avatar_tick: number;
136
+ } | null> => {
137
+ try {
138
+ const cached = await avatarDb.userCache.get(userId);
139
+ if (cached) {
140
+ const now = Date.now();
141
+ if (now - cached.timestamp < CACHE_EXPIRATION_MS) {
142
+ return cached.avatar;
143
+ }
144
+ await avatarDb.userCache.delete(userId);
145
+ }
146
+ return null;
147
+ } catch (error) {
148
+ console.error('读取用户头像缓存失败:', error);
149
+ return null;
150
+ }
151
+ };
152
+
153
+ /**
154
+ * 从缓存获取用户信息
155
+ * @param userId 用户ID
156
+ * @returns 缓存的用户信息或null
157
+ */
158
+ const getFromCache = async (userId: string): Promise<UserInfo | null> => {
159
+ try {
160
+ const cached = await db.userCache.get(userId);
161
+ if (cached) {
162
+ const now = Date.now();
163
+
164
+ // 检查头像缓存
165
+ const avatarCached = await avatarDb.userCache.get(userId);
166
+ if (avatarCached) {
167
+ // 检查头像缓存是否过期
168
+ if (now - avatarCached.timestamp < CACHE_EXPIRATION_MS) {
169
+ cached.data.avatar = avatarCached.avatar;
170
+ }
171
+ else {
172
+ // 头像缓存过期,清空头像
173
+ cached.data.avatar = undefined;
174
+ await avatarDb.userCache.delete(userId);
175
+ }
176
+ } else {
177
+ // 没有头像缓存,清空头像
178
+ cached.data.avatar = undefined;
179
+ }
180
+
181
+ if (now - cached.timestamp < CACHE_EXPIRATION_MS) {
182
+ return cached.data;
183
+ }
184
+ // 缓存过期,删除
185
+ await db.userCache.delete(userId);
186
+ }
187
+ return null;
188
+ } catch (error) {
189
+ console.error('读取用户缓存失败:', error);
190
+ return null;
191
+ }
192
+ };
193
+
194
+ /**
195
+ * 设置用户信息到缓存
196
+ * @param userId 用户ID
197
+ * @param data 用户信息
198
+ */
199
+ const setAvatarToCache = async (userId: string, data: {
200
+ avatar: string | undefined;
201
+ avatar_small: string | undefined;
202
+ avatar_tick: number;
203
+ }): Promise<void> => {
204
+ try {
205
+ // 缓存头像
206
+ if (data) {
207
+ await avatarDb.userCache.put({
208
+ id: userId,
209
+ avatar: data,
210
+ timestamp: Date.now()
211
+ });
212
+ }
213
+ } catch (error) {
214
+ console.error('写入用户头像缓存失败:', error);
215
+ }
216
+ };
217
+
218
+ /**
219
+ * 设置用户信息到缓存
220
+ * @param userId 用户ID
221
+ * @param data 用户信息
222
+ */
223
+ const setToCache = async (userId: string, data: UserInfo): Promise<void> => {
224
+ try {
225
+ // 缓存头像
226
+ if (data.avatar) {
227
+ await avatarDb.userCache.put({
228
+ id: userId,
229
+ avatar: data.avatar,
230
+ timestamp: Date.now()
231
+ });
232
+ }
233
+ let avatar = data.avatar;
234
+ data.avatar = undefined;
235
+ await db.userCache.put({
236
+ id: userId,
237
+ data,
238
+ timestamp: Date.now()
239
+ });
240
+ // 恢复头像
241
+ data.avatar = avatar;
242
+ } catch (error) {
243
+ console.error('写入用户缓存失败:', error);
244
+ }
245
+ };
246
+
247
+ /**
248
+ * 批量从缓存获取用户信息
249
+ * @param userIds 用户ID数组
250
+ * @returns 缓存的用户信息映射表
251
+ */
252
+ const getMultipleFromCache = async (userIds: string[]): Promise<Map<string, UserInfo>> => {
253
+ const result = new Map<string, UserInfo>();
254
+ try {
255
+ const cached = await db.userCache.bulkGet(userIds);
256
+ const now = Date.now();
257
+
258
+ for (let i = 0; i < userIds.length; i++) {
259
+ const item = cached[i];
260
+ if (item && now - item.timestamp < CACHE_EXPIRATION_MS) {
261
+ result.set(userIds[i], item.data);
262
+ }
263
+ }
264
+
265
+ const avatarCached = await avatarDb.userCache.bulkGet(userIds);
266
+
267
+ for (let i = 0; i < userIds.length; i++) {
268
+ const item = avatarCached[i];
269
+ if (!item) continue;
270
+ const user = result.get(item.id);
271
+ if (user && now - item.timestamp < CACHE_EXPIRATION_MS) {
272
+ user.avatar = item.avatar;
273
+ }
274
+ }
275
+ } catch (error) {
276
+ console.error('批量读取用户缓存失败:', error);
277
+ }
278
+ return result;
279
+ };
280
+
281
+ /**
282
+ * 批量设置用户信息到缓存
283
+ * @param users 用户信息数组
284
+ */
285
+ const setMultipleToCache = async (users: { id: string; data: UserInfo }[]): Promise<void> => {
286
+ try {
287
+ const entries = users.map(u => ({
288
+ id: u.id,
289
+ data: u.data,
290
+ timestamp: Date.now()
291
+ }));
292
+ // 缓存头像
293
+ let avatarEntries = users.map(u => ({
294
+ id: u.id,
295
+ avatar: u.data.avatar,
296
+ timestamp: Date.now()
297
+ }));
298
+ // 过滤掉空头像
299
+ avatarEntries = avatarEntries.filter(e => e.avatar);
300
+
301
+ await avatarDb.userCache.bulkPut(avatarEntries as any);
302
+
303
+ entries.forEach(e => {
304
+ e.data.avatar = undefined;
305
+ });
306
+ await db.userCache.bulkPut(entries);
307
+ } catch (error) {
308
+ console.error('批量写入用户缓存失败:', error);
309
+ }
310
+ };
311
+
312
+ /**
313
+ * 获取所有有效缓存的用户信息
314
+ * @returns 缓存的用户信息映射表
315
+ */
316
+ const getAllFromCache = async (): Promise<Map<string, UserInfo>> => {
317
+ const result = new Map<string, UserInfo>();
318
+ try {
319
+ const now = Date.now();
320
+ const all = await db.userCache.toArray();
321
+ for (const item of all) {
322
+ if (now - item.timestamp < CACHE_EXPIRATION_MS) {
323
+ // 检查头像缓存
324
+ const avatarCached = await avatarDb.userCache.get(item.id);
325
+ if (avatarCached && now - avatarCached.timestamp < CACHE_EXPIRATION_MS) {
326
+ item.data.avatar = avatarCached.avatar;
327
+ }
328
+ result.set(item.id, item.data);
329
+ } else {
330
+ // 清理过期缓存
331
+ await db.userCache.delete(item.id);
332
+ }
333
+ }
334
+ } catch (error) {
335
+ console.error('获取所有缓存失败:', error);
336
+ }
337
+ return result;
338
+ };
339
+
340
+ /**
341
+ * 清除所有用户缓存
342
+ */
343
+ const clearCache = async (): Promise<void> => {
344
+ try {
345
+ await db.userCache.clear();
346
+ await avatarDb.userCache.clear();
347
+ } catch (error) {
348
+ console.error('清除用户缓存失败:', error);
349
+ }
350
+ };
351
+
352
+ /**
353
+ * 获取当前登录用户信息
354
+ * @param user_id 用户ID(可选,不传则获取当前登录用户)
355
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
356
+ * @returns 用户信息
357
+ */
358
+ const getUserInfo = async (
359
+ {
360
+ user_id,
361
+ forceRefresh = false,
362
+ forceAvatar = false,
363
+ }: {
364
+ user_id?: string,
365
+ forceRefresh?: boolean,
366
+ forceAvatar?: boolean
367
+ }
368
+ ): Promise<UserInfo | null> => {
369
+
370
+ let r: any = {
371
+ code: ResponseCode.SUCCESS,
372
+ data: {
373
+ user_id,
374
+ isLogin: true,
375
+ }
376
+ };
377
+
378
+ let isLoginNetworkError = false;
379
+
380
+ if (!user_id) {
381
+ try {
382
+ r = await API.user.gateway.isLogin();
383
+ } catch (e) {
384
+ // 网络不可达 / 服务器宕机:视为"接口未知状态",不清除会话 token(用户很可能仍有效),
385
+ // 也不向上抛错 —— 走下面的本地缓存降级逻辑,保证页面可正常渲染。
386
+ isLoginNetworkError = true;
387
+ }
388
+ }
389
+
390
+ // —— 接口网络异常:走纯本地缓存分支,不做任何清除 token / 跳登录的行为 ——
391
+ if (isLoginNetworkError) {
392
+ // 1) 从 bp.ss.user 拿本地上一次保存的 user 快照,优先对齐 Dexie
393
+ let localUserId: string | undefined;
394
+ try {
395
+ const rawUser = storage.namespace('bp.ss').get('user');
396
+ if (rawUser) {
397
+ const parsed = JSON.parse(rawUser) as UserInfo;
398
+ localUserId = parsed?.id;
399
+ }
400
+ } catch {
401
+ /* ignore parse error */
402
+ }
403
+
404
+ // 2) 如果未指定 user_id,就用 localStorage 中的当前用户 id 查 Dexie 缓存
405
+ const queryId = user_id ?? localUserId;
406
+ if (queryId) {
407
+ const cached = await getFromCache(queryId);
408
+ if (cached) {
409
+ // 补全头像
410
+ const av = await getUserAvatar({ user_id: queryId, forceRefresh: false, serverTick: cached.tick_avatar_self });
411
+ if (av) cached.avatar = av;
412
+ return cached;
413
+ }
414
+ }
415
+
416
+ // 3) 连 Dexie 也没有:如果本地 raw user 存在,直接用它兜底(至少能展示导航栏和用户名)
417
+ try {
418
+ const rawUser = storage.namespace('bp.ss').get('user');
419
+ if (rawUser) return JSON.parse(rawUser) as UserInfo;
420
+ } catch {
421
+ /* ignore */
422
+ }
423
+
424
+ return null;
425
+ }
426
+
427
+ if (r?.code === ResponseCode.SUCCESS && r.data?.isLogin) {
428
+ let userId = r.data?.user_id;
429
+ let isAdminFlag = r.data?.isAdmin || false;
430
+
431
+ // 从缓存获取用户
432
+ let cachedUserInfo = await getFromCache(userId);
433
+ if (forceRefresh || !cachedUserInfo) {
434
+ try {
435
+ let r = await API.user.user.getInfo({ id: userId });
436
+ if (r?.code == ResponseCode.SUCCESS) {
437
+
438
+ if (!user_id) {
439
+ storage.namespace('bp.ss').set('user', JSON.stringify(r.data));
440
+ }
441
+
442
+ const userInfo = {
443
+ ...r.data,
444
+ } as UserInfo;
445
+
446
+ // 写入缓存
447
+ if (userId) {
448
+ await setToCache(userId, userInfo);
449
+ }
450
+
451
+ try {
452
+ let avatar = await getUserAvatar({ user_id: userId, forceRefresh: forceAvatar, serverTick: r.data?.tick_avatar_self });
453
+ if (avatar) {
454
+ userInfo.avatar = avatar;
455
+ }
456
+ } catch {
457
+ // 头像接口失败不阻塞用户主信息返回
458
+ }
459
+
460
+ return userInfo;
461
+ } else if (cachedUserInfo) {
462
+ // 接口返回非 SUCCESS,但本地有缓存:降级返回缓存,避免页面进入空白态
463
+ return cachedUserInfo;
464
+ } else {
465
+ return null;
466
+ }
467
+ } catch (e) {
468
+ // getInfo 网络异常:有缓存就用缓存,否则返回 null 但不清除会话
469
+ if (cachedUserInfo) return cachedUserInfo;
470
+ // 至少返回本地 localStorage 里的 raw user 作为兜底
471
+ try {
472
+ const rawUser = storage.namespace('bp.ss').get('user');
473
+ if (rawUser) return JSON.parse(rawUser) as UserInfo;
474
+ } catch { /* ignore */ }
475
+ return null;
476
+ }
477
+ }
478
+
479
+ try {
480
+ let avatar = await getUserAvatar({ user_id: userId, forceRefresh: forceAvatar, serverTick: cachedUserInfo.tick_avatar_self });
481
+ if (avatar) {
482
+ cachedUserInfo.avatar = avatar;
483
+ }
484
+ } catch {
485
+ // 头像接口失败不阻塞用户返回
486
+ }
487
+ return cachedUserInfo;
488
+ } else {
489
+ AuthorizationHandler.clearStoreToken();
490
+ return null;
491
+ }
492
+ }
493
+
494
+ /**
495
+ * 获取用户信息头像
496
+ * @param user_id 用户ID(可选,不传则获取当前登录用户)
497
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
498
+ * @returns 用户信息头像
499
+ */
500
+ const getUserAvatar = async (
501
+ {
502
+ user_id,
503
+ forceRefresh = false,
504
+ serverTick = Number.MAX_SAFE_INTEGER, // 服务器上最新的tick.
505
+ }: {
506
+ user_id?: string,
507
+ forceRefresh?: boolean,
508
+ serverTick?: number,
509
+ }
510
+ ): Promise<{
511
+ avatar: string | undefined;
512
+ avatar_small: string | undefined;
513
+ avatar_tick: number;
514
+ } | undefined> => {
515
+
516
+ if (!user_id) {
517
+ return undefined;
518
+ }
519
+
520
+ // 从缓存获取用户头像
521
+ let cachedUserInfo = await getAvatarFromCache(user_id);
522
+
523
+ if (forceRefresh || !cachedUserInfo) {
524
+ const tickSelf = cachedUserInfo?.avatar_tick || -1;
525
+ if (tickSelf < serverTick) {
526
+ try {
527
+ let rAvatar = await API.user.user.getAvatar({ id: user_id, tick: tickSelf as any });
528
+ if (rAvatar?.code == ResponseCode.SUCCESS && tickSelf != rAvatar.data?.tick_self) {
529
+ cachedUserInfo = {
530
+ avatar: febs.string.isEmpty(rAvatar.data?.avatar) ? undefined : rAvatar.data?.avatar,
531
+ avatar_small: febs.string.isEmpty(rAvatar.data?.avatar_small) ? undefined : rAvatar.data?.avatar_small,
532
+ avatar_tick: rAvatar.data?.tick_self || -1
533
+ };
534
+ await setAvatarToCache(user_id, cachedUserInfo);
535
+ }
536
+ } catch {
537
+ // 头像接口网络/服务异常:直接返回缓存值,不向上抛出
538
+ }
539
+ }
540
+ }
541
+
542
+ return cachedUserInfo || undefined;
543
+ };
544
+
545
+ const current = async (options?: { forceRefresh?: boolean }): Promise<UserInfo | null> => {
546
+ options = options || {forceRefresh: false};
547
+ return await getUserInfo(options);
548
+ }
549
+
550
+ /**
551
+ * 获取本地存储的当前登录用户ID
552
+ */
553
+ const currentLocalUser = (): UserInfo | null => {
554
+ let user = storage.namespace('bp.ss').get('user');
555
+ if (user) {
556
+ return JSON.parse(user);
557
+ }
558
+ return null;
559
+ }
560
+
561
+ /**
562
+ * 批量获取多个用户信息;
563
+ * @param keywords 搜索关键词, 可选,与userIds不能同时提供.
564
+ * @param userIds 用户ID数组, length=0, 则获取前100个.
565
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
566
+ * @returns 用户信息映射表(key为用户ID,value为用户信息)
567
+ */
568
+ const getUserInfos = async (
569
+ {
570
+ userIds,
571
+ keywords,
572
+ forceRefresh = false,
573
+ }:
574
+ {
575
+ userIds?: string[],
576
+ keywords?: string,
577
+ forceRefresh?: boolean,
578
+ }
579
+ ): Promise<Map<string, UserInfo>> => {
580
+ const result = new Map<string, UserInfo>();
581
+ if (!userIds) {
582
+ // 先检查缓存是否有100个用户
583
+ if (!forceRefresh && (!keywords || keywords.length === 0)) {
584
+ const cachedUsers = await getAllFromCache();
585
+ if (cachedUsers.size >= 100) {
586
+ const top100 = new Map<string, UserInfo>();
587
+ let count = 0;
588
+ for (const [id, info] of cachedUsers) {
589
+ if (count >= 100) break;
590
+
591
+ const avatar = await getUserAvatar({ user_id: id, forceRefresh: false, serverTick: info.tick_avatar_self });
592
+ info.avatar = avatar;
593
+ top100.set(id, info);
594
+ count++;
595
+ }
596
+ return top100;
597
+ }
598
+ return cachedUsers;
599
+ }
600
+
601
+ // 从API获取前100个用户
602
+ let listRes;
603
+ if (keywords && keywords.length > 0) {
604
+ listRes = await API.user.user.search({ pageNum: 1, pageSize: 100, keyword: keywords });
605
+ if (listRes?.code !== ResponseCode.SUCCESS) {
606
+ return result;
607
+ }
608
+ }
609
+ else {
610
+ listRes = await API.user.user.list({ pageNum: 1, pageSize: 100 });
611
+ if (listRes?.code !== ResponseCode.SUCCESS) {
612
+ return result;
613
+ }
614
+ }
615
+
616
+ const users = listRes.data?.list || [];
617
+ const userInfos: { id: string; data: UserInfo }[] = [];
618
+
619
+ for (const user of users) {
620
+ // const r3 = await API.user.role.listUserRoles({ user_id: user.id || '' });
621
+
622
+ const userInfo = {
623
+ ...user,
624
+ } as UserInfo;
625
+
626
+ result.set(user.id, userInfo);
627
+ userInfos.push({ id: user.id, data: userInfo });
628
+ }
629
+
630
+ // 写入缓存
631
+ if (userInfos.length > 0) {
632
+ await setMultipleToCache(userInfos);
633
+ }
634
+
635
+ // 批量获取只取小头像.
636
+ for (let i = 0; i < userInfos.length; i++) {
637
+ let avatar = await getUserAvatar({ user_id: userInfos[i].id, serverTick: userInfos[i].data.tick_avatar_self });
638
+ userInfos[i].data.avatar = avatar;
639
+ }
640
+
641
+ return result;
642
+ }
643
+
644
+ if (userIds.length == 0) {
645
+ return result;
646
+ }
647
+
648
+ // 去重
649
+ const uniqueIds = [...new Set(userIds)];
650
+
651
+ // 尝试从缓存获取
652
+ if (!forceRefresh) {
653
+ const cachedUsers = await getMultipleFromCache(uniqueIds);
654
+ cachedUsers.forEach((info, id) => {
655
+ result.set(id, info);
656
+ });
657
+ }
658
+
659
+ // 获取未缓存的用户ID
660
+ const uncachedIds = uniqueIds.filter(id => !result.has(id));
661
+
662
+ if (uncachedIds.length === 0) {
663
+ return result;
664
+ }
665
+
666
+ try {
667
+ let resUsers = await API.user.user.listByIds({ ids: JSON.stringify(uncachedIds) });
668
+ if (resUsers?.code != ResponseCode.SUCCESS) {
669
+ return result;
670
+ }
671
+ let users = resUsers.data?.list || [];
672
+
673
+ // 写入缓存
674
+ if (users.length > 0) {
675
+ let r = [];
676
+ for (const user of users) {
677
+ const userInfo = {
678
+ ...user,
679
+ } as UserInfo;
680
+ r.push({ id: user.id, data: userInfo });
681
+ }
682
+ await setMultipleToCache(r);
683
+ }
684
+
685
+ let userAvatarCache = [] as {
686
+ id: string;
687
+ avatar_small: string;
688
+ avatar_tick: number;
689
+ }[];
690
+
691
+ if (users.length > 0) {
692
+ for (const user of users) {
693
+ const avatar = await getUserAvatar({ user_id: user.id, serverTick: user.tick_avatar_self || -1 });
694
+ userAvatarCache.push({
695
+ id: user.id,
696
+ avatar_small: avatar?.avatar_small || '',
697
+ avatar_tick: user.tick_avatar_self || -1,
698
+ });
699
+ }
700
+ }
701
+
702
+ for (const user of users) {
703
+ const avatar = userAvatarCache.find(v => v.id == user.id);
704
+
705
+ const userInfo = {
706
+ ...user,
707
+ avatar: {
708
+ avatar: '',
709
+ avatar_small: avatar?.avatar_small || '',
710
+ avatar_tick: avatar?.avatar_tick || -1,
711
+ },
712
+ } as UserInfo;
713
+
714
+ // 获取用户角色
715
+ // const roleRes = await API.user.role.listUserRoles({ user_id: user.id });
716
+ // if (roleRes.code === ResponseCode.SUCCESS && roleRes.data?.length) {
717
+ // userInfo.role_ids = roleRes.data.map((role) => role.id);
718
+ // }
719
+
720
+ result.set(user.id, userInfo);
721
+ }
722
+
723
+ } catch (error) {
724
+ console.error('批量获取用户信息失败:', error);
725
+ }
726
+
727
+ return result;
728
+ };
729
+
730
+ /**
731
+ * 清除指定用户的缓存
732
+ * @param userId 用户ID
733
+ */
734
+ const clearUserCache = async (userId?: string): Promise<void> => {
735
+ if (userId) {
736
+ await db.userCache.delete(userId);
737
+ } else {
738
+ await clearCache();
739
+ }
740
+ };
741
+
742
+ /**
743
+ * 获取缓存统计信息
744
+ * @returns 缓存统计信息
745
+ */
746
+ const getCacheStats = async (): Promise<{ count: number; oldest: number | null; newest: number | null }> => {
747
+ try {
748
+ const all = await db.userCache.toArray();
749
+ if (all.length === 0) {
750
+ return { count: 0, oldest: null, newest: null };
751
+ }
752
+ const timestamps = all.map(item => item.timestamp);
753
+ return {
754
+ count: all.length,
755
+ oldest: Math.min(...timestamps),
756
+ newest: Math.max(...timestamps)
757
+ };
758
+ } catch (error) {
759
+ console.error('获取缓存统计失败:', error);
760
+ return { count: 0, oldest: null, newest: null };
761
+ }
762
+ };
763
+
764
+ /**
765
+ * 用户信息缓存管理对象
766
+ * @description 提供用户信息的缓存读写、批量获取、缓存清除等功能
767
+ * @example
768
+ * import { CacheUserInfo } from './CacheUserInfo';
769
+ * const userInfo = await CacheUserInfo.getUserInfo({});
770
+ * const users = await CacheUserInfo.getUserInfos({ userIds: ['id1', 'id2'] });
771
+ * await CacheUserInfo.clearUserCache();
772
+ */
773
+ export const CacheUserInfo = {
774
+ /**
775
+ * 从缓存获取用户信息
776
+ * @param userId 用户ID
777
+ * @returns 缓存的用户信息或null
778
+ */
779
+ getFromCache,
780
+ getAvatarFromCache,
781
+ /**
782
+ * 获取当前登录用户信息
783
+ * @param user_id 用户ID(可选,不传则获取当前登录用户)
784
+ * @param isAdmin 是否为管理员
785
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
786
+ * @returns 用户信息
787
+ */
788
+ getUserInfo,
789
+ getUserAvatar,
790
+ /**
791
+ * 获取当前登录角色
792
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
793
+ * @returns 用户信息
794
+ */
795
+ current,
796
+ /**
797
+ * 获取本地存储的当前登录用户信息
798
+ */
799
+ currentLocalUser,
800
+ /**
801
+ * 批量获取多个用户信息;
802
+ * @param keywords 搜索关键词, 可选,与userIds不能同时提供.
803
+ * @param userIds 用户ID数组, length=0, 则获取前100个.
804
+ * @param forceRefresh 是否强制刷新缓存(默认false,使用缓存)
805
+ * @returns 用户信息映射表(key为用户ID,value为用户信息)
806
+ */
807
+ getUserInfos,
808
+ /**
809
+ * 清除指定用户的缓存
810
+ * @param userId 用户ID
811
+ */
812
+ clearUserCache,
813
+ /**
814
+ * 获取缓存统计信息
815
+ * @returns 缓存统计信息
816
+ */
817
+ getCacheStats,
818
+ }