@robot-admin/naive-ui-components 0.8.1 → 0.9.0

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 (381) hide show
  1. package/README.md +294 -279
  2. package/dist/C_ActionBar-DYG0Yf3A.css.map +1 -0
  3. package/dist/C_ActionBar-MAjRhqcI.css.map +1 -0
  4. package/dist/C_ActionBar.cjs +1 -1
  5. package/dist/C_ActionBar.css +47 -47
  6. package/dist/C_ActionBar.js +1 -1
  7. package/dist/C_ActionBar.js.map +1 -1
  8. package/dist/C_ActionBar2.js +1 -1
  9. package/dist/C_ActionBar2.js.map +1 -1
  10. package/dist/{C_AntV-A3NXx_sF.css.map → C_AntV-BY8jqqmi.css.map} +1 -1
  11. package/dist/{C_AntV-D2Zp2qQF.css.map → C_AntV-BbkHc-_a.css.map} +1 -1
  12. package/dist/C_AntV.cjs +1 -1
  13. package/dist/C_AntV.css +78 -78
  14. package/dist/C_AntV.js +1 -1
  15. package/dist/C_AntV.js.map +1 -1
  16. package/dist/C_AntV2.js +3 -3
  17. package/dist/C_AntV2.js.map +1 -1
  18. package/dist/{C_AudioPlayer-CXl4yP_m.css.map → C_AudioPlayer-DKRIGhi7.css.map} +1 -1
  19. package/dist/{C_AudioPlayer-CcBtt71m.css.map → C_AudioPlayer-DlB6eNsa.css.map} +1 -1
  20. package/dist/C_AudioPlayer.cjs +1 -1
  21. package/dist/C_AudioPlayer.css +47 -47
  22. package/dist/C_AudioPlayer.js +1 -1
  23. package/dist/C_AudioPlayer.js.map +1 -1
  24. package/dist/C_AudioPlayer2.js +1 -1
  25. package/dist/C_AudioPlayer2.js.map +1 -1
  26. package/dist/{C_AvatarGroup-CtPhfH9h.css.map → C_AvatarGroup-D02zci-i.css.map} +1 -1
  27. package/dist/{C_AvatarGroup-M1dNPH3E.css.map → C_AvatarGroup-DatHaUlY.css.map} +1 -1
  28. package/dist/C_AvatarGroup.css +21 -21
  29. package/dist/C_AvatarGroup.js.map +1 -1
  30. package/dist/C_AvatarGroup2.js +1 -1
  31. package/dist/C_AvatarGroup2.js.map +1 -1
  32. package/dist/{C_Barcode-DjTmDkbQ.css.map → C_Barcode-DYDRDe2O.css.map} +1 -1
  33. package/dist/{C_Barcode-Do1Ozsmh.css.map → C_Barcode-muJdc_O4.css.map} +1 -1
  34. package/dist/C_Barcode.css +7 -7
  35. package/dist/C_Barcode.js.map +1 -1
  36. package/dist/C_Barcode2.js +1 -1
  37. package/dist/C_Barcode2.js.map +1 -1
  38. package/dist/C_Breadcrumb.cjs +1 -1
  39. package/dist/C_Breadcrumb.js +1 -1
  40. package/dist/C_Breadcrumb.js.map +1 -1
  41. package/dist/C_Breadcrumb2.js +1 -1
  42. package/dist/C_Breadcrumb2.js.map +1 -1
  43. package/dist/{C_Captcha-CZmAETly.css.map → C_Captcha-9_hk6VmY.css.map} +1 -1
  44. package/dist/{C_Captcha-Ccq3DMrR.css.map → C_Captcha-MtASlJ0f.css.map} +1 -1
  45. package/dist/C_Captcha.css +19 -19
  46. package/dist/C_Captcha.js.map +1 -1
  47. package/dist/C_Captcha2.js +1 -1
  48. package/dist/C_Captcha2.js.map +1 -1
  49. package/dist/C_Cascade.js.map +1 -1
  50. package/dist/C_Cascade2.js +1 -1
  51. package/dist/C_Cascade2.js.map +1 -1
  52. package/dist/{C_Chat-CJ8KESTM.css.map → C_Chat-Csjz_BFw.css.map} +1 -1
  53. package/dist/{C_Chat-DzV4AFLd.css.map → C_Chat-DO1ZBA_0.css.map} +1 -1
  54. package/dist/C_Chat.cjs +1 -1
  55. package/dist/C_Chat.css +65 -65
  56. package/dist/C_Chat.js +1 -1
  57. package/dist/C_Chat.js.map +1 -1
  58. package/dist/C_Chat2.js +1 -1
  59. package/dist/C_Chat2.js.map +1 -1
  60. package/dist/{C_City-Cv5BESaN.css.map → C_City-Bam08Qv3.css.map} +1 -1
  61. package/dist/{C_City-DNKv4MpH.css.map → C_City-Bb3W-KaN.css.map} +1 -1
  62. package/dist/C_City.css +29 -29
  63. package/dist/C_City.js.map +1 -1
  64. package/dist/C_City2.js +1 -1
  65. package/dist/C_City2.js.map +1 -1
  66. package/dist/C_Code-BFi5xxnM.css.map +1 -0
  67. package/dist/C_Code-CZ7yfnri.css.map +1 -0
  68. package/dist/C_Code.cjs +1 -1
  69. package/dist/C_Code.css +3 -3
  70. package/dist/C_Code.js +1 -1
  71. package/dist/C_Code.js.map +1 -1
  72. package/dist/C_Code2.js +1 -1
  73. package/dist/C_Code2.js.map +1 -1
  74. package/dist/{C_CollapsePanel-CedsEM0N.css.map → C_CollapsePanel-CWkFCqNQ.css.map} +1 -1
  75. package/dist/{C_CollapsePanel-BkOivqn3.css.map → C_CollapsePanel-pcVJA_4z.css.map} +1 -1
  76. package/dist/C_CollapsePanel.cjs +1 -1
  77. package/dist/C_CollapsePanel.css +35 -35
  78. package/dist/C_CollapsePanel.js +1 -1
  79. package/dist/C_CollapsePanel.js.map +1 -1
  80. package/dist/C_CollapsePanel2.js +1 -1
  81. package/dist/C_CollapsePanel2.js.map +1 -1
  82. package/dist/{C_ContextMenu-CCsCeI39.css.map → C_ContextMenu-B3Cgz_wJ.css.map} +1 -1
  83. package/dist/{C_ContextMenu-DOTBeltf.css.map → C_ContextMenu-u1LixF3_.css.map} +1 -1
  84. package/dist/C_ContextMenu.cjs +1 -1
  85. package/dist/C_ContextMenu.css +17 -17
  86. package/dist/C_ContextMenu.js +1 -1
  87. package/dist/C_ContextMenu.js.map +1 -1
  88. package/dist/C_ContextMenu2.js +1 -1
  89. package/dist/C_ContextMenu2.js.map +1 -1
  90. package/dist/{C_Cron-C0-8b5af.css.map → C_Cron-Civir5-I.css.map} +1 -1
  91. package/dist/{C_Cron-DqHQ92LN.css.map → C_Cron-iw3qpMsy.css.map} +1 -1
  92. package/dist/C_Cron.cjs +1 -1
  93. package/dist/C_Cron.css +37 -37
  94. package/dist/C_Cron.js +1 -1
  95. package/dist/C_Cron.js.map +1 -1
  96. package/dist/C_Cron2.js +1 -1
  97. package/dist/C_Cron2.js.map +1 -1
  98. package/dist/C_Date.js.map +1 -1
  99. package/dist/C_Date2.js +1 -1
  100. package/dist/C_Date2.js.map +1 -1
  101. package/dist/{C_Draggable-Bq6o0qXn.css.map → C_Draggable-BCjIvIwT.css.map} +1 -1
  102. package/dist/{C_Draggable-r6nhx3yM.css.map → C_Draggable-DwkSlCOS.css.map} +1 -1
  103. package/dist/C_Draggable.css +46 -46
  104. package/dist/C_Draggable.js.map +1 -1
  105. package/dist/C_Draggable2.js +1 -1
  106. package/dist/C_Draggable2.js.map +1 -1
  107. package/dist/C_Editor-BfjjYQ9B.css.map +1 -0
  108. package/dist/C_Editor-Do2StvoJ.css.map +1 -0
  109. package/dist/C_Editor.css +55 -55
  110. package/dist/C_Editor.js.map +1 -1
  111. package/dist/C_Editor2.js +1 -1
  112. package/dist/C_Editor2.js.map +1 -1
  113. package/dist/{C_FilePreview-BVarVvnD.css.map → C_FilePreview-BhcbiXsV.css.map} +1 -1
  114. package/dist/{C_FilePreview-DHGlV4OR.css.map → C_FilePreview-DJudcIbW.css.map} +1 -1
  115. package/dist/C_FilePreview.cjs +1 -1
  116. package/dist/C_FilePreview.css +91 -91
  117. package/dist/C_FilePreview.js +1 -1
  118. package/dist/C_FilePreview.js.map +1 -1
  119. package/dist/C_FilePreview2.js +1 -1
  120. package/dist/C_FilePreview2.js.map +1 -1
  121. package/dist/{C_Form-BciQUPpS.css.map → C_Form-BtcAPIRi.css.map} +1 -1
  122. package/dist/{C_Form-CKHvXL3O.css.map → C_Form-D_gwQ7hC.css.map} +1 -1
  123. package/dist/C_Form.cjs +1 -1
  124. package/dist/C_Form.css +222 -222
  125. package/dist/C_Form.js +1 -1
  126. package/dist/C_Form.js.map +1 -1
  127. package/dist/C_Form2.js +1 -1
  128. package/dist/C_Form2.js.map +1 -1
  129. package/dist/{C_FormSearch-Bmd2CmG6.css.map → C_FormSearch-Bi4XYjjk.css.map} +1 -1
  130. package/dist/{C_FormSearch-DBNtnjaL.css.map → C_FormSearch-DUGOoX0u.css.map} +1 -1
  131. package/dist/C_FormSearch.css +45 -45
  132. package/dist/C_FormSearch.js.map +1 -1
  133. package/dist/C_FormSearch2.js +1 -1
  134. package/dist/C_FormSearch2.js.map +1 -1
  135. package/dist/{C_FormulaEditor-3WG2vtQl.css.map → C_FormulaEditor-CJk3SSUJ.css.map} +1 -1
  136. package/dist/{C_FormulaEditor-Cm0CokN5.css.map → C_FormulaEditor-Cy7mjfVO.css.map} +1 -1
  137. package/dist/C_FormulaEditor.cjs +1 -1
  138. package/dist/C_FormulaEditor.css +78 -78
  139. package/dist/C_FormulaEditor.js +1 -1
  140. package/dist/C_FormulaEditor.js.map +1 -1
  141. package/dist/C_FormulaEditor2.js +1 -1
  142. package/dist/C_FormulaEditor2.js.map +1 -1
  143. package/dist/C_FullCalendar-BQA0OjGB.css.map +1 -0
  144. package/dist/C_FullCalendar-ChJUosAi.css.map +1 -0
  145. package/dist/C_FullCalendar.css +3 -3
  146. package/dist/C_FullCalendar.js.map +1 -1
  147. package/dist/C_FullCalendar2.js +1 -1
  148. package/dist/C_FullCalendar2.js.map +1 -1
  149. package/dist/C_GlobalSearch.js.map +1 -1
  150. package/dist/C_GlobalSearch2.js.map +1 -1
  151. package/dist/C_Guide.cjs +1 -1
  152. package/dist/C_Guide.js +1 -1
  153. package/dist/C_Guide.js.map +1 -1
  154. package/dist/C_Guide2.js +1 -1
  155. package/dist/C_Guide2.js.map +1 -1
  156. package/dist/C_Icon.js.map +1 -1
  157. package/dist/C_Icon2.js +1 -1
  158. package/dist/C_Icon2.js.map +1 -1
  159. package/dist/{C_ImageCropper-D3L2-J_J.css.map → C_ImageCropper-BqZpkZfU.css.map} +1 -1
  160. package/dist/{C_ImageCropper-DrmUlaLi.css.map → C_ImageCropper-CylwGuzS.css.map} +1 -1
  161. package/dist/C_ImageCropper.cjs +1 -1
  162. package/dist/C_ImageCropper.css +10 -10
  163. package/dist/C_ImageCropper.js +1 -1
  164. package/dist/C_ImageCropper.js.map +1 -1
  165. package/dist/C_ImageCropper2.js +1 -1
  166. package/dist/C_ImageCropper2.js.map +1 -1
  167. package/dist/C_Language.cjs +1 -1
  168. package/dist/C_Language.js +1 -1
  169. package/dist/C_Language.js.map +1 -1
  170. package/dist/C_Language2.js +1 -1
  171. package/dist/C_Language2.js.map +1 -1
  172. package/dist/{C_Login-Cst_W1XC.css.map → C_Login-BkdnkBKX.css.map} +1 -1
  173. package/dist/{C_Login-DWZ_6K1x.css.map → C_Login-VkMM6OJ2.css.map} +1 -1
  174. package/dist/C_Login.cjs +1 -1
  175. package/dist/C_Login.css +72 -72
  176. package/dist/C_Login.js +1 -1
  177. package/dist/C_Login.js.map +1 -1
  178. package/dist/C_Login2.js +1 -1
  179. package/dist/C_Login2.js.map +1 -1
  180. package/dist/{C_Map-BCJmDnJT.css.map → C_Map-DNnBcY70.css.map} +1 -1
  181. package/dist/{C_Map-WUMXSAfy.css.map → C_Map-LEXIx6zM.css.map} +1 -1
  182. package/dist/C_Map.css +4 -4
  183. package/dist/C_Map.js.map +1 -1
  184. package/dist/C_Map2.js +1 -1
  185. package/dist/C_Map2.js.map +1 -1
  186. package/dist/{C_Markdown-7J0uPEuk.css.map → C_Markdown-DwmI0_0Q.css.map} +1 -1
  187. package/dist/{C_Markdown-C7Lg0_9z.css.map → C_Markdown-k0794RW0.css.map} +1 -1
  188. package/dist/C_Markdown.css +33 -33
  189. package/dist/C_Markdown.js.map +1 -1
  190. package/dist/C_Markdown2.js +1 -1
  191. package/dist/C_Markdown2.js.map +1 -1
  192. package/dist/C_Menu.js.map +1 -1
  193. package/dist/C_Menu2.js +1 -1
  194. package/dist/C_Menu2.js.map +1 -1
  195. package/dist/C_NotificationCenter.cjs +1 -1
  196. package/dist/C_NotificationCenter.js +1 -1
  197. package/dist/C_NotificationCenter.js.map +1 -1
  198. package/dist/C_NotificationCenter2.js +1 -1
  199. package/dist/C_NotificationCenter2.js.map +1 -1
  200. package/dist/C_OrgChart.js.map +1 -1
  201. package/dist/C_OrgChart2.js +1 -1
  202. package/dist/C_OrgChart2.js.map +1 -1
  203. package/dist/C_Progress.js.map +1 -1
  204. package/dist/C_Progress2.js +1 -1
  205. package/dist/C_Progress2.js.map +1 -1
  206. package/dist/{C_QRCode-DMxSyogU.css.map → C_QRCode-CFNTda_1.css.map} +1 -1
  207. package/dist/{C_QRCode-G7fiAkm4.css.map → C_QRCode-CmWr9lK-.css.map} +1 -1
  208. package/dist/C_QRCode.css +9 -9
  209. package/dist/C_QRCode.js.map +1 -1
  210. package/dist/C_QRCode2.js +1 -1
  211. package/dist/C_QRCode2.js.map +1 -1
  212. package/dist/{C_Signature-BJMvVPWT.css.map → C_Signature-BDx4ctsE.css.map} +1 -1
  213. package/dist/{C_Signature-BJUHx2BF.css.map → C_Signature-Bz_uNbwv.css.map} +1 -1
  214. package/dist/C_Signature.cjs +1 -1
  215. package/dist/C_Signature.css +15 -15
  216. package/dist/C_Signature.js +1 -1
  217. package/dist/C_Signature.js.map +1 -1
  218. package/dist/C_Signature2.js +1 -1
  219. package/dist/C_Signature2.js.map +1 -1
  220. package/dist/C_Skeleton.js.map +1 -1
  221. package/dist/C_Skeleton2.js +1 -1
  222. package/dist/C_Skeleton2.js.map +1 -1
  223. package/dist/{C_SplitPane-Br2eK8IG.css.map → C_SplitPane-BOwr1C7K.css.map} +1 -1
  224. package/dist/{C_SplitPane-DuyzUhKB.css.map → C_SplitPane-N-a_D-7F.css.map} +1 -1
  225. package/dist/C_SplitPane.cjs +1 -1
  226. package/dist/C_SplitPane.css +31 -31
  227. package/dist/C_SplitPane.js +1 -1
  228. package/dist/C_SplitPane.js.map +1 -1
  229. package/dist/C_SplitPane2.js +1 -1
  230. package/dist/C_SplitPane2.js.map +1 -1
  231. package/dist/C_Steps-Bk1krgiR.css.map +1 -0
  232. package/dist/C_Steps-Dn2CMpy1.css.map +1 -0
  233. package/dist/C_Steps.css +38 -38
  234. package/dist/C_Steps.js.map +1 -1
  235. package/dist/C_Steps2.js +1 -1
  236. package/dist/C_Steps2.js.map +1 -1
  237. package/dist/C_Table.cjs +1 -1
  238. package/dist/C_Table.js +1 -1
  239. package/dist/C_Table.js.map +1 -1
  240. package/dist/C_Table2.js +2 -2
  241. package/dist/C_Table2.js.map +1 -1
  242. package/dist/{C_TagsView-BsutyC3U.css.map → C_TagsView-DX3LecK1.css.map} +1 -1
  243. package/dist/{C_TagsView-Crm7yWg9.css.map → C_TagsView-DqOTa8bL.css.map} +1 -1
  244. package/dist/C_TagsView.cjs +1 -1
  245. package/dist/C_TagsView.css +36 -36
  246. package/dist/C_TagsView.js +1 -1
  247. package/dist/C_TagsView.js.map +1 -1
  248. package/dist/C_TagsView2.js +1 -1
  249. package/dist/C_TagsView2.js.map +1 -1
  250. package/dist/C_Theme.cjs +1 -1
  251. package/dist/C_Theme.js +1 -1
  252. package/dist/C_Theme.js.map +1 -1
  253. package/dist/C_Theme2.js +1 -1
  254. package/dist/C_Theme2.js.map +1 -1
  255. package/dist/C_Time-BzyQVvTS.css.map +1 -0
  256. package/dist/C_Time-DmpKLQHc.css.map +1 -0
  257. package/dist/C_Time.css +5 -5
  258. package/dist/C_Time.js.map +1 -1
  259. package/dist/C_Time2.js +1 -1
  260. package/dist/C_Time2.js.map +1 -1
  261. package/dist/{C_Timeline-DG70WtJP.css.map → C_Timeline-BKkimrZx.css.map} +1 -1
  262. package/dist/{C_Timeline-Dzxmmdjg.css.map → C_Timeline-DTuSCX6p.css.map} +1 -1
  263. package/dist/C_Timeline.cjs +1 -1
  264. package/dist/C_Timeline.css +45 -45
  265. package/dist/C_Timeline.js +1 -1
  266. package/dist/C_Timeline.js.map +1 -1
  267. package/dist/C_Timeline2.js +1 -1
  268. package/dist/C_Timeline2.js.map +1 -1
  269. package/dist/{C_Transfer-CCEqnC-v.css.map → C_Transfer-BOB6OBqS.css.map} +1 -1
  270. package/dist/{C_Transfer-CStPm4NP.css.map → C_Transfer-Dpq7ezWC.css.map} +1 -1
  271. package/dist/C_Transfer.cjs +1 -1
  272. package/dist/C_Transfer.css +31 -31
  273. package/dist/C_Transfer.js +1 -1
  274. package/dist/C_Transfer.js.map +1 -1
  275. package/dist/C_Transfer2.js +1 -1
  276. package/dist/C_Transfer2.js.map +1 -1
  277. package/dist/{C_Tree-B-Le4hjQ.css.map → C_Tree-D98nX9qT.css.map} +1 -1
  278. package/dist/{C_Tree-DnGc_MPb.css.map → C_Tree-ulfm7b-P.css.map} +1 -1
  279. package/dist/C_Tree.cjs +1 -1
  280. package/dist/C_Tree.css +33 -33
  281. package/dist/C_Tree.js +1 -1
  282. package/dist/C_Tree.js.map +1 -1
  283. package/dist/C_Tree2.js +1 -1
  284. package/dist/C_Tree2.js.map +1 -1
  285. package/dist/{C_Upload-CFAxVGVz.css.map → C_Upload-BR9fg5r4.css.map} +1 -1
  286. package/dist/{C_Upload-D8_QeSV0.css.map → C_Upload-CPqf74Ea.css.map} +1 -1
  287. package/dist/C_Upload.cjs +1 -1
  288. package/dist/C_Upload.css +4 -4
  289. package/dist/C_Upload.js +1 -1
  290. package/dist/C_Upload.js.map +1 -1
  291. package/dist/C_Upload2.js +2 -2
  292. package/dist/C_Upload2.js.map +1 -1
  293. package/dist/{C_VideoPlayer-Cdgv4Zq0.css.map → C_VideoPlayer-4J96tKfK.css.map} +1 -1
  294. package/dist/{C_VideoPlayer-rm0MODUv.css.map → C_VideoPlayer-D35seHkm.css.map} +1 -1
  295. package/dist/C_VideoPlayer.css +13 -13
  296. package/dist/C_VideoPlayer.js.map +1 -1
  297. package/dist/C_VideoPlayer2.js +3 -3
  298. package/dist/C_VideoPlayer2.js.map +1 -1
  299. package/dist/{C_VtableGantt-BpY-Rng3.css.map → C_VtableGantt-C2lxFmWg.css.map} +1 -1
  300. package/dist/{C_VtableGantt-DB87-jdS.css.map → C_VtableGantt-Dwnkw_WL.css.map} +1 -1
  301. package/dist/C_VtableGantt.cjs +1 -1
  302. package/dist/C_VtableGantt.css +15 -15
  303. package/dist/C_VtableGantt.js +1 -1
  304. package/dist/C_VtableGantt.js.map +1 -1
  305. package/dist/C_VtableGantt2.js +1 -1
  306. package/dist/C_VtableGantt2.js.map +1 -1
  307. package/dist/C_WaterFall.js.map +1 -1
  308. package/dist/C_WaterFall2.js +1 -1
  309. package/dist/C_WaterFall2.js.map +1 -1
  310. package/dist/{C_WorkFlow-7F6op6qN.css.map → C_WorkFlow-2hJfvvTK.css.map} +1 -1
  311. package/dist/{C_WorkFlow-Cy3HWA6A.css.map → C_WorkFlow-DHoNjl8-.css.map} +1 -1
  312. package/dist/C_WorkFlow.cjs +1 -1
  313. package/dist/C_WorkFlow.css +108 -108
  314. package/dist/C_WorkFlow.js +1 -1
  315. package/dist/C_WorkFlow.js.map +1 -1
  316. package/dist/C_WorkFlow2.js +1 -1
  317. package/dist/C_WorkFlow2.js.map +1 -1
  318. package/dist/constants.d.ts +3 -3
  319. package/dist/constants2.d.ts +4 -4
  320. package/dist/constants3.d.ts +3 -3
  321. package/dist/constants4.d.ts +4 -4
  322. package/dist/constants5.d.ts +2 -2
  323. package/dist/data.d.ts +2 -2
  324. package/dist/index.cjs.map +1 -1
  325. package/dist/index.js.map +1 -1
  326. package/dist/index.vue.d.ts +1 -1
  327. package/dist/index10.vue.d.ts +1 -1
  328. package/dist/index11.vue.d.ts +4 -4
  329. package/dist/index12.vue.d.ts +1 -1
  330. package/dist/index13.vue.d.ts +2 -2
  331. package/dist/index14.vue.d.ts +3 -3
  332. package/dist/index15.vue.d.ts +3 -3
  333. package/dist/index16.vue.d.ts +2 -2
  334. package/dist/index17.vue.d.ts +1 -1
  335. package/dist/index18.vue.d.ts +5 -5
  336. package/dist/index2.vue.d.ts +1 -1
  337. package/dist/index20.vue.d.ts +1 -1
  338. package/dist/index22.vue.d.ts +1 -1
  339. package/dist/index23.vue.d.ts +2 -2
  340. package/dist/index24.vue.d.ts +1 -1
  341. package/dist/index26.vue.d.ts +3 -3
  342. package/dist/index27.vue.d.ts +2 -2
  343. package/dist/index28.vue.d.ts +3 -3
  344. package/dist/index3.vue.d.ts +3 -3
  345. package/dist/index4.vue.d.ts +2 -2
  346. package/dist/index6.vue.d.ts +6 -6
  347. package/dist/index7.vue.d.ts +2 -2
  348. package/dist/index8.vue.d.ts +1 -1
  349. package/dist/index9.vue.d.ts +2 -2
  350. package/dist/menuAdapter.js.map +1 -1
  351. package/dist/resolver.cjs.map +1 -1
  352. package/dist/resolver.js.map +1 -1
  353. package/dist/style.css +1483 -1483
  354. package/dist/themes/glass-morphism.css +1 -0
  355. package/dist/useCalendarEvents.d.ts +1 -1
  356. package/dist/useCollapsePanel.d.ts +1 -1
  357. package/dist/useCropperCore.d.ts +2 -2
  358. package/dist/useDraggableLayout.d.ts +4 -4
  359. package/dist/useDynamicFormState.d.ts +21 -21
  360. package/dist/useEdgeInteraction.d.ts +2 -2
  361. package/dist/useModalEdit.d.ts +1 -1
  362. package/dist/useQRCode.d.ts +3 -3
  363. package/dist/useSearchState.d.ts +2 -2
  364. package/dist/useSignatureHistory.d.ts +4 -4
  365. package/dist/useSplitResize.d.ts +2 -2
  366. package/dist/useTimeSelection.d.ts +2 -2
  367. package/dist/useTreeOperations.d.ts +3 -3
  368. package/dist/useWorkflowValidation.d.ts +6 -6
  369. package/package.json +11 -8
  370. package/dist/C_ActionBar-jZPsiXtT.css.map +0 -1
  371. package/dist/C_ActionBar-nnfbZCea.css.map +0 -1
  372. package/dist/C_Code-DPZlNSxL.css.map +0 -1
  373. package/dist/C_Code-avZjAnHD.css.map +0 -1
  374. package/dist/C_Editor-C49qURgb.css.map +0 -1
  375. package/dist/C_Editor-DuxBD9Qg.css.map +0 -1
  376. package/dist/C_FullCalendar-1U4VlG7X.css.map +0 -1
  377. package/dist/C_FullCalendar-DLUdCtqf.css.map +0 -1
  378. package/dist/C_Steps-BHYNJI1l.css.map +0 -1
  379. package/dist/C_Steps-DY7vl-4I.css.map +0 -1
  380. package/dist/C_Time-Bd_e1YDN.css.map +0 -1
  381. package/dist/C_Time-CKb_fwdm.css.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"C_FilePreview2.js","names":["totalPages","pdfUrl","headings","content","sheets","$emit"],"sources":["../src/components/C_FilePreview/data.ts","../src/components/C_FilePreview/components/PdfViewer/index.vue","../src/components/C_FilePreview/components/PdfViewer/index.vue","../src/components/C_FilePreview/components/PdfViewer/index.vue","../src/components/C_FilePreview/components/WordViewer/index.vue","../src/components/C_FilePreview/components/WordViewer/index.vue","../src/components/C_FilePreview/components/WordViewer/index.vue","../src/components/C_FilePreview/components/ExcelViewer/index.vue","../src/components/C_FilePreview/components/ExcelViewer/index.vue","../src/components/C_FilePreview/components/ExcelViewer/index.vue","../src/components/C_FilePreview/composables/useFilePreview.ts","../src/components/C_FilePreview/composables/useFullscreen.ts","../src/components/C_FilePreview/index.vue","../src/components/C_FilePreview/index.vue","../src/components/C_FilePreview/index.vue"],"sourcesContent":["/**\r\n * C_FilePreview 常量配置与工具函数\r\n * 类型定义统一在 ./types.ts\r\n */\r\nimport { type Ref } from \"vue\";\r\nimport * as XLSX from \"xlsx\";\r\nimport mammoth from \"mammoth\";\r\nimport type {\r\n FilePreviewType,\r\n FileConfig,\r\n ZoomConfig,\r\n ExcelRow,\r\n ExcelColumn,\r\n ExcelSheet,\r\n DocHeading,\r\n PdfLoadResult,\r\n WordLoadResult,\r\n ExcelLoadResult,\r\n} from \"./types\";\r\n\r\n/* ==================== 常量配置 ==================== */\r\n\r\nexport const FILE_TYPE_MAP: Record<string, FilePreviewType> = {\r\n pdf: \"pdf\",\r\n doc: \"word\",\r\n docx: \"word\",\r\n xls: \"excel\",\r\n xlsx: \"excel\",\r\n};\r\n\r\nexport const FILE_CONFIGS: Record<string, FileConfig> = {\r\n pdf: {\r\n tagType: \"error\",\r\n icon: \"ic:outline-picture-as-pdf\",\r\n color: \"#dc2626\",\r\n },\r\n word: { tagType: \"info\", icon: \"ic:outline-description\", color: \"#2563eb\" },\r\n excel: { tagType: \"success\", icon: \"ic:outline-grid-on\", color: \"#16a34a\" },\r\n unknown: {\r\n tagType: \"default\",\r\n icon: \"ic:outline-insert-drive-file\",\r\n color: \"#6b7280\",\r\n },\r\n};\r\n\r\nexport const ZOOM_CONFIGS: Record<string, ZoomConfig> = {\r\n pdf: { min: 0.5, max: 3, step: 0.25, default: 1 },\r\n word: { min: 50, max: 200, step: 10, default: 100 },\r\n};\r\n\r\nexport const PAGE_SIZE_OPTIONS = [20, 50, 100, 200];\r\n\r\nexport const FULLSCREEN_EVENTS = [\r\n \"fullscreenchange\",\r\n \"webkitfullscreenchange\",\r\n \"mozfullscreenchange\",\r\n \"MSFullscreenChange\",\r\n];\r\n\r\n/* ==================== 文件信息工具函数 ==================== */\r\n\r\nexport const extractFileNameFromUrl = (url: string): string => {\r\n try {\r\n const urlPath = url.split(\"/\").pop() || url.split(\"\\\\\").pop();\r\n if (urlPath?.includes(\".\")) {\r\n const decodedName = decodeURIComponent(urlPath.split(\"?\")[0]);\r\n if (decodedName && decodedName !== url) return decodedName;\r\n }\r\n } catch (error) {\r\n console.warn(\"解析URL文件名失败:\", error);\r\n }\r\n return \"未知文件\";\r\n};\r\n\r\nexport const formatFileSize = (bytes: number): string => {\r\n if (bytes === 0) return \"0 B\";\r\n const k = 1024;\r\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + \" \" + sizes[i];\r\n};\r\n\r\nexport const getFileType = (fileName: string): FilePreviewType => {\r\n if (!fileName || fileName === \"未知文件\") return \"unknown\";\r\n const ext = fileName.toLowerCase().split(\".\").pop();\r\n if (!ext) return \"unknown\";\r\n return FILE_TYPE_MAP[ext] || \"unknown\";\r\n};\r\n\r\nexport const getFileConfig = (fileType: string): FileConfig => {\r\n return FILE_CONFIGS[fileType] || FILE_CONFIGS.unknown;\r\n};\r\n\r\n/* ==================== 缩放工具 ==================== */\r\n\r\nexport const createZoomHandler = (\r\n valueRef: Ref<number>,\r\n config: ZoomConfig,\r\n) => {\r\n return (action: \"in\" | \"out\" | \"reset\") => {\r\n const { min, max, step, default: defaultValue } = config;\r\n switch (action) {\r\n case \"reset\":\r\n valueRef.value = defaultValue;\r\n break;\r\n case \"in\":\r\n if (valueRef.value < max) valueRef.value += step;\r\n break;\r\n case \"out\":\r\n if (valueRef.value > min) valueRef.value -= step;\r\n break;\r\n }\r\n };\r\n};\r\n\r\n/* ==================== Excel 工具函数 ==================== */\r\n\r\nexport const getColumnLetter = (index: number): string => {\r\n let result = \"\";\r\n while (index >= 0) {\r\n result = String.fromCharCode(65 + (index % 26)) + result;\r\n index = Math.floor(index / 26) - 1;\r\n }\r\n return result;\r\n};\r\n\r\nexport const formatCellValue = (value: any): string => {\r\n if (!value) return \"\";\r\n const strValue = String(value).trim();\r\n\r\n if (!isNaN(Number(strValue)) && strValue !== \"\" && strValue.length < 15) {\r\n const num = Number(strValue);\r\n return Number.isInteger(num)\r\n ? num.toLocaleString()\r\n : num.toLocaleString(undefined, { maximumFractionDigits: 2 });\r\n }\r\n return strValue;\r\n};\r\n\r\nexport const getCellClass = (value: any): string => {\r\n if (!value) return \"cell-empty\";\r\n const strValue = String(value).trim();\r\n\r\n if (!isNaN(Number(strValue)) && strValue !== \"\") return \"cell-number\";\r\n if (strValue.match(/[■▬▪▫─━]/)) return \"cell-gantt\";\r\n if (\r\n strValue.match(/^\\d{4}[-/]\\d{2}[-/]\\d{2}/) ||\r\n strValue.match(/^\\d{2}[-/]\\d{2}[-/]\\d{4}/)\r\n )\r\n return \"cell-date\";\r\n if ([\"true\", \"false\"].includes(strValue.toLowerCase())) return \"cell-boolean\";\r\n return strValue.length > 20 ? \"cell-text cell-long\" : \"cell-text\";\r\n};\r\n\r\nexport const processExcelSheet = (\r\n worksheet: any,\r\n merges: any[],\r\n): { data: ExcelRow[]; columns: ExcelColumn[] } => {\r\n const range = XLSX.utils.decode_range(worksheet[\"!ref\"] || \"A1:A1\");\r\n const { c: maxCol, r: maxRow } = range.e;\r\n\r\n const columns: ExcelColumn[] = Array.from({ length: maxCol + 1 }, (_, c) => {\r\n const cellAddress = XLSX.utils.encode_cell({ r: 0, c });\r\n const cell = worksheet[cellAddress];\r\n const columnName = cell ? String(cell.v || \"\").trim() : `列${c + 1}`;\r\n return {\r\n title: columnName || `列${c + 1}`,\r\n key: `col_${c}`,\r\n width: Math.min(Math.max(columnName.length * 12, 80), 200),\r\n };\r\n });\r\n\r\n const mergeMap = new Map();\r\n merges.forEach(({ s: { r: sRow, c: sCol }, e: { r: eRow, c: eCol } }) => {\r\n for (let r = sRow; r <= eRow; r++) {\r\n for (let c = sCol; c <= eCol; c++) {\r\n mergeMap.set(`${r}-${c}`, {\r\n isMain: r === sRow && c === sCol,\r\n rowspan: eRow - sRow + 1,\r\n colspan: eCol - sCol + 1,\r\n });\r\n }\r\n }\r\n });\r\n\r\n const data: ExcelRow[] = Array.from({ length: maxRow + 1 }, (_, r) => {\r\n const row: ExcelRow = {};\r\n for (let c = 0; c <= maxCol; c++) {\r\n const cellAddress = XLSX.utils.encode_cell({ r, c });\r\n const cell = worksheet[cellAddress];\r\n const mergeInfo = mergeMap.get(`${r}-${c}`);\r\n\r\n row[`col_${c}`] = {\r\n value: cell ? cell.v || \"\" : \"\",\r\n merged: !!mergeInfo,\r\n hidden: mergeInfo && !mergeInfo.isMain,\r\n rowspan: mergeInfo?.isMain ? mergeInfo.rowspan : 1,\r\n colspan: mergeInfo?.isMain ? mergeInfo.colspan : 1,\r\n };\r\n }\r\n return row;\r\n });\r\n\r\n return { data, columns };\r\n};\r\n\r\n/* ==================== 文件加载器 ==================== */\r\n\r\nexport async function loadPdf(file: File): Promise<PdfLoadResult> {\r\n const fileUrl = URL.createObjectURL(file);\r\n return {\r\n url: fileUrl + \"#toolbar=1&navpanes=1&scrollbar=1&view=FitH\",\r\n totalPages: 1,\r\n };\r\n}\r\n\r\nexport async function loadWord(file: File): Promise<WordLoadResult> {\r\n const arrayBuffer = await file.arrayBuffer();\r\n const result = await mammoth.convertToHtml({\r\n arrayBuffer,\r\n styleMap: [\r\n \"p[style-name='Heading 1'] => h1:fresh\",\r\n \"p[style-name='Heading 2'] => h2:fresh\",\r\n \"p[style-name='Heading 3'] => h3:fresh\",\r\n \"p[style-name='Title'] => h1.title:fresh\",\r\n ],\r\n } as any);\r\n\r\n let content = result.value;\r\n const headings: DocHeading[] = [];\r\n\r\n /* 提取标题并注入 id */\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.innerHTML = content;\r\n const headingElements = tempDiv.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\r\n\r\n Array.from(headingElements).forEach((el, index) => {\r\n const id = `heading-${index}`;\r\n const level = parseInt(el.tagName.charAt(1));\r\n const text = el.textContent || \"\";\r\n\r\n content = content.replace(\r\n el.outerHTML,\r\n el.outerHTML.replace(\r\n el.tagName.toLowerCase(),\r\n `${el.tagName.toLowerCase()} id=\"${id}\"`,\r\n ),\r\n );\r\n\r\n headings.push({ id, text, level });\r\n });\r\n\r\n return { content, headings };\r\n}\r\n\r\nexport async function loadExcel(file: File): Promise<ExcelLoadResult> {\r\n const arrayBuffer = await file.arrayBuffer();\r\n const workbook = XLSX.read(arrayBuffer, {\r\n type: \"array\",\r\n cellStyles: true,\r\n cellFormula: true,\r\n cellDates: true,\r\n });\r\n\r\n if (!workbook.SheetNames.length) {\r\n throw new Error(\"Excel文件中没有找到工作表\");\r\n }\r\n\r\n const sheets: ExcelSheet[] = workbook.SheetNames.map((name) => {\r\n const worksheet = workbook.Sheets[name];\r\n const merges = worksheet[\"!merges\"] || [];\r\n const { data, columns } = processExcelSheet(worksheet, merges);\r\n return { name, data, merges, columns };\r\n });\r\n\r\n return { sheets };\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n PdfViewer — PDF 文件预览子组件\r\n 负责: 工具栏(翻页+缩放) + iframe 渲染\r\n-->\r\n<template>\r\n <div class=\"file-container pdf-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <!-- 翻页控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage <= 1\"\r\n @click=\"changePage('prev')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-left\" />\r\n </template>\r\n </NButton>\r\n <NInputNumber\r\n v-model:value=\"currentPage\"\r\n size=\"small\"\r\n :min=\"1\"\r\n :max=\"totalPages\"\r\n style=\"width: 80px\"\r\n @update:value=\"changePage as any\"\r\n />\r\n <span class=\"text-sm text-gray-600\">/ {{ totalPages }}</span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage >= totalPages\"\r\n @click=\"changePage('next')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-right\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale <= 0.5\"\r\n @click=\"adjustZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ Math.round(scale * 100) }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale >= 3\"\r\n @click=\"adjustZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n @click=\"adjustZoom('reset')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 适应\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-viewer\">\r\n <iframe\r\n v-if=\"pdfUrl\"\r\n :src=\"pdfUrl\"\r\n class=\"w-full h-full border-0\"\r\n title=\"PDF预览\"\r\n frameborder=\"0\"\r\n allowfullscreen\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref } from 'vue'\r\n import { NButton, NInputNumber } from 'naive-ui'\r\n import { createZoomHandler, ZOOM_CONFIGS } from '../../data'\r\n\r\n const props = defineProps<{\r\n pdfUrl: string\r\n totalPages: number\r\n }>()\r\n\r\n const currentPage = ref(1)\r\n const scale = ref(1)\r\n\r\n const adjustZoom = createZoomHandler(scale, ZOOM_CONFIGS.pdf)\r\n\r\n const changePage = (action: 'prev' | 'next' | number) => {\r\n if (typeof action === 'number') {\r\n currentPage.value = Math.max(1, Math.min(action, props.totalPages))\r\n } else {\r\n const delta = action === 'prev' ? -1 : 1\r\n currentPage.value = Math.max(\r\n 1,\r\n Math.min(currentPage.value + delta, props.totalPages)\r\n )\r\n }\r\n }\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n PdfViewer — PDF 文件预览子组件\r\n 负责: 工具栏(翻页+缩放) + iframe 渲染\r\n-->\r\n<template>\r\n <div class=\"file-container pdf-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <!-- 翻页控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage <= 1\"\r\n @click=\"changePage('prev')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-left\" />\r\n </template>\r\n </NButton>\r\n <NInputNumber\r\n v-model:value=\"currentPage\"\r\n size=\"small\"\r\n :min=\"1\"\r\n :max=\"totalPages\"\r\n style=\"width: 80px\"\r\n @update:value=\"changePage as any\"\r\n />\r\n <span class=\"text-sm text-gray-600\">/ {{ totalPages }}</span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage >= totalPages\"\r\n @click=\"changePage('next')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-right\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale <= 0.5\"\r\n @click=\"adjustZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ Math.round(scale * 100) }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale >= 3\"\r\n @click=\"adjustZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n @click=\"adjustZoom('reset')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 适应\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-viewer\">\r\n <iframe\r\n v-if=\"pdfUrl\"\r\n :src=\"pdfUrl\"\r\n class=\"w-full h-full border-0\"\r\n title=\"PDF预览\"\r\n frameborder=\"0\"\r\n allowfullscreen\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref } from 'vue'\r\n import { NButton, NInputNumber } from 'naive-ui'\r\n import { createZoomHandler, ZOOM_CONFIGS } from '../../data'\r\n\r\n const props = defineProps<{\r\n pdfUrl: string\r\n totalPages: number\r\n }>()\r\n\r\n const currentPage = ref(1)\r\n const scale = ref(1)\r\n\r\n const adjustZoom = createZoomHandler(scale, ZOOM_CONFIGS.pdf)\r\n\r\n const changePage = (action: 'prev' | 'next' | number) => {\r\n if (typeof action === 'number') {\r\n currentPage.value = Math.max(1, Math.min(action, props.totalPages))\r\n } else {\r\n const delta = action === 'prev' ? -1 : 1\r\n currentPage.value = Math.max(\r\n 1,\r\n Math.min(currentPage.value + delta, props.totalPages)\r\n )\r\n }\r\n }\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n PdfViewer — PDF 文件预览子组件\r\n 负责: 工具栏(翻页+缩放) + iframe 渲染\r\n-->\r\n<template>\r\n <div class=\"file-container pdf-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <!-- 翻页控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage <= 1\"\r\n @click=\"changePage('prev')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-left\" />\r\n </template>\r\n </NButton>\r\n <NInputNumber\r\n v-model:value=\"currentPage\"\r\n size=\"small\"\r\n :min=\"1\"\r\n :max=\"totalPages\"\r\n style=\"width: 80px\"\r\n @update:value=\"changePage as any\"\r\n />\r\n <span class=\"text-sm text-gray-600\">/ {{ totalPages }}</span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"currentPage >= totalPages\"\r\n @click=\"changePage('next')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-chevron-right\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n\r\n <!-- 缩放控制 -->\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale <= 0.5\"\r\n @click=\"adjustZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ Math.round(scale * 100) }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"scale >= 3\"\r\n @click=\"adjustZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n @click=\"adjustZoom('reset')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 适应\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-viewer\">\r\n <iframe\r\n v-if=\"pdfUrl\"\r\n :src=\"pdfUrl\"\r\n class=\"w-full h-full border-0\"\r\n title=\"PDF预览\"\r\n frameborder=\"0\"\r\n allowfullscreen\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref } from 'vue'\r\n import { NButton, NInputNumber } from 'naive-ui'\r\n import { createZoomHandler, ZOOM_CONFIGS } from '../../data'\r\n\r\n const props = defineProps<{\r\n pdfUrl: string\r\n totalPages: number\r\n }>()\r\n\r\n const currentPage = ref(1)\r\n const scale = ref(1)\r\n\r\n const adjustZoom = createZoomHandler(scale, ZOOM_CONFIGS.pdf)\r\n\r\n const changePage = (action: 'prev' | 'next' | number) => {\r\n if (typeof action === 'number') {\r\n currentPage.value = Math.max(1, Math.min(action, props.totalPages))\r\n } else {\r\n const delta = action === 'prev' ? -1 : 1\r\n currentPage.value = Math.max(\r\n 1,\r\n Math.min(currentPage.value + delta, props.totalPages)\r\n )\r\n }\r\n }\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n WordViewer — Word 文档预览子组件\r\n 负责: 目录导航 + 缩放 + 文档内容渲染\r\n-->\r\n<template>\r\n <div class=\"file-container word-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showOutline = !showOutline\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-list\" />\r\n </template>\r\n {{ showOutline ? \"隐藏\" : \"显示\" }}目录\r\n </NButton>\r\n <NDivider vertical />\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom <= 50\"\r\n @click=\"adjustWordZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ wordZoom }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom >= 200\"\r\n @click=\"adjustWordZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton size=\"small\" @click=\"adjustWordZoom('reset')\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 重置\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div class=\"word-layout\">\r\n <div class=\"word-main\">\r\n <!-- 侧边栏目录 -->\r\n <div v-if=\"showOutline\" class=\"word-outline\">\r\n <div class=\"outline-header\">\r\n <h3 class=\"text-sm font-semibold\">文档目录</h3>\r\n </div>\r\n <div class=\"outline-content\">\r\n <div\r\n v-for=\"(heading, index) in headings\"\r\n :key=\"index\"\r\n class=\"outline-item\"\r\n :class=\"`level-${heading.level}`\"\r\n @click=\"scrollToHeading(heading.id)\"\r\n >\r\n {{ heading.text }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主要内容区域 -->\r\n <div class=\"word-content\">\r\n <div\r\n class=\"word-document\"\r\n :style=\"{\r\n transform: `scale(${wordZoom / 100})`,\r\n transformOrigin: 'top center',\r\n }\"\r\n v-html=\"content\"\r\n ></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\nimport { NButton, NDivider } from \"naive-ui\";\r\nimport { createZoomHandler, ZOOM_CONFIGS } from \"../../data\";\r\nimport type { DocHeading } from \"../../types\";\r\n\r\ndefineProps<{\r\n content: string;\r\n headings: DocHeading[];\r\n}>();\r\n\r\nconst showOutline = ref(true);\r\nconst wordZoom = ref(100);\r\n\r\nconst adjustWordZoom = createZoomHandler(wordZoom, ZOOM_CONFIGS.word);\r\n\r\nconst scrollToHeading = (headingId: string) => {\r\n document\r\n .getElementById(headingId)\r\n ?.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n WordViewer — Word 文档预览子组件\r\n 负责: 目录导航 + 缩放 + 文档内容渲染\r\n-->\r\n<template>\r\n <div class=\"file-container word-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showOutline = !showOutline\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-list\" />\r\n </template>\r\n {{ showOutline ? \"隐藏\" : \"显示\" }}目录\r\n </NButton>\r\n <NDivider vertical />\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom <= 50\"\r\n @click=\"adjustWordZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ wordZoom }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom >= 200\"\r\n @click=\"adjustWordZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton size=\"small\" @click=\"adjustWordZoom('reset')\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 重置\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div class=\"word-layout\">\r\n <div class=\"word-main\">\r\n <!-- 侧边栏目录 -->\r\n <div v-if=\"showOutline\" class=\"word-outline\">\r\n <div class=\"outline-header\">\r\n <h3 class=\"text-sm font-semibold\">文档目录</h3>\r\n </div>\r\n <div class=\"outline-content\">\r\n <div\r\n v-for=\"(heading, index) in headings\"\r\n :key=\"index\"\r\n class=\"outline-item\"\r\n :class=\"`level-${heading.level}`\"\r\n @click=\"scrollToHeading(heading.id)\"\r\n >\r\n {{ heading.text }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主要内容区域 -->\r\n <div class=\"word-content\">\r\n <div\r\n class=\"word-document\"\r\n :style=\"{\r\n transform: `scale(${wordZoom / 100})`,\r\n transformOrigin: 'top center',\r\n }\"\r\n v-html=\"content\"\r\n ></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\nimport { NButton, NDivider } from \"naive-ui\";\r\nimport { createZoomHandler, ZOOM_CONFIGS } from \"../../data\";\r\nimport type { DocHeading } from \"../../types\";\r\n\r\ndefineProps<{\r\n content: string;\r\n headings: DocHeading[];\r\n}>();\r\n\r\nconst showOutline = ref(true);\r\nconst wordZoom = ref(100);\r\n\r\nconst adjustWordZoom = createZoomHandler(wordZoom, ZOOM_CONFIGS.word);\r\n\r\nconst scrollToHeading = (headingId: string) => {\r\n document\r\n .getElementById(headingId)\r\n ?.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n WordViewer — Word 文档预览子组件\r\n 负责: 目录导航 + 缩放 + 文档内容渲染\r\n-->\r\n<template>\r\n <div class=\"file-container word-container\">\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showOutline = !showOutline\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-list\" />\r\n </template>\r\n {{ showOutline ? \"隐藏\" : \"显示\" }}目录\r\n </NButton>\r\n <NDivider vertical />\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom <= 50\"\r\n @click=\"adjustWordZoom('out')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-out\" />\r\n </template>\r\n </NButton>\r\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\r\n {{ wordZoom }}%\r\n </span>\r\n <NButton\r\n size=\"small\"\r\n :disabled=\"wordZoom >= 200\"\r\n @click=\"adjustWordZoom('in')\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-zoom-in\" />\r\n </template>\r\n </NButton>\r\n <NButton size=\"small\" @click=\"adjustWordZoom('reset')\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-fit-screen\" />\r\n </template>\r\n 重置\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div class=\"word-layout\">\r\n <div class=\"word-main\">\r\n <!-- 侧边栏目录 -->\r\n <div v-if=\"showOutline\" class=\"word-outline\">\r\n <div class=\"outline-header\">\r\n <h3 class=\"text-sm font-semibold\">文档目录</h3>\r\n </div>\r\n <div class=\"outline-content\">\r\n <div\r\n v-for=\"(heading, index) in headings\"\r\n :key=\"index\"\r\n class=\"outline-item\"\r\n :class=\"`level-${heading.level}`\"\r\n @click=\"scrollToHeading(heading.id)\"\r\n >\r\n {{ heading.text }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主要内容区域 -->\r\n <div class=\"word-content\">\r\n <div\r\n class=\"word-document\"\r\n :style=\"{\r\n transform: `scale(${wordZoom / 100})`,\r\n transformOrigin: 'top center',\r\n }\"\r\n v-html=\"content\"\r\n ></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\nimport { NButton, NDivider } from \"naive-ui\";\r\nimport { createZoomHandler, ZOOM_CONFIGS } from \"../../data\";\r\nimport type { DocHeading } from \"../../types\";\r\n\r\ndefineProps<{\r\n content: string;\r\n headings: DocHeading[];\r\n}>();\r\n\r\nconst showOutline = ref(true);\r\nconst wordZoom = ref(100);\r\n\r\nconst adjustWordZoom = createZoomHandler(wordZoom, ZOOM_CONFIGS.word);\r\n\r\nconst scrollToHeading = (headingId: string) => {\r\n document\r\n .getElementById(headingId)\r\n ?.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n ExcelViewer — Excel 表格预览子组件\r\n 负责: 工作表切换 + 表格渲染(合并单元格) + 分页 + 格式切换\r\n-->\r\n<template>\r\n <div class=\"file-container excel-container\">\r\n <!-- 工具栏 -->\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NTabs\r\n v-if=\"sheets.length > 1\"\r\n v-model:value=\"activeSheet\"\r\n type=\"card\"\r\n size=\"small\"\r\n >\r\n <NTabPane\r\n v-for=\"sheet in sheets\"\r\n :key=\"sheet.name\"\r\n :name=\"sheet.name\"\r\n :tab=\"sheet.name\"\r\n />\r\n </NTabs>\r\n <span v-else class=\"text-sm text-gray-600\">\r\n 工作表: {{ activeSheet }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showExcelFormat = !showExcelFormat\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-format-paint\" />\r\n </template>\r\n {{ showExcelFormat ? \"紧凑视图\" : \"完整格式\" }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"excel-viewer\">\r\n <!-- 信息面板 -->\r\n <div v-if=\"currentData.length > 0\" class=\"excel-info\">\r\n <NText depth=\"3\" class=\"text-sm\">\r\n 当前工作表: {{ activeSheet }} | 总行数: {{ currentData.length }} |\r\n 总列数: {{ currentColumns.length }} | 当前页:\r\n {{ currentExcelPage }}/{{ totalExcelPages }}\r\n </NText>\r\n </div>\r\n\r\n <!-- 表格 -->\r\n <div class=\"excel-table-container\">\r\n <div\r\n class=\"excel-table-wrapper\"\r\n :class=\"{ 'simple-mode': !showExcelFormat }\"\r\n >\r\n <table v-if=\"currentData.length > 0\" class=\"excel-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"row-number\">行号</th>\r\n <th\r\n v-for=\"(col, index) in currentColumns\"\r\n :key=\"col.key\"\r\n class=\"excel-header\"\r\n :style=\"{ minWidth: col.width + 'px' }\"\r\n >\r\n <div class=\"header-content\">\r\n <span class=\"column-letter\">{{\r\n getColumnLetter(index)\r\n }}</span>\r\n <span class=\"column-title\">{{ col.title }}</span>\r\n </div>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n v-for=\"(row, rowIndex) in paginatedData\"\r\n :key=\"rowIndex\"\r\n class=\"excel-row\"\r\n >\r\n <td class=\"row-number\">\r\n {{ (currentExcelPage - 1) * pageSize + rowIndex + 1 }}\r\n </td>\r\n <td\r\n v-for=\"col in currentColumns\"\r\n :key=\"col.key\"\r\n v-show=\"!row[col.key]?.hidden\"\r\n class=\"excel-cell\"\r\n :class=\"[\r\n getCellClass(row[col.key]?.value),\r\n row[col.key]?.merged ? 'merged-cell' : '',\r\n !showExcelFormat ? 'compact-cell' : '',\r\n ]\"\r\n :rowspan=\"row[col.key]?.rowspan || 1\"\r\n :colspan=\"row[col.key]?.colspan || 1\"\r\n :title=\"row[col.key]?.value\"\r\n >\r\n {{ formatCellValue(row[col.key]?.value) }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div v-else class=\"excel-empty\">\r\n <NEmpty description=\"该工作表没有数据或解析失败\">\r\n <template #extra>\r\n <NButton size=\"small\" @click=\"$emit('reload')\">\r\n 重新解析\r\n </NButton>\r\n </template>\r\n </NEmpty>\r\n </div>\r\n </div>\r\n\r\n <!-- 分页 -->\r\n <div v-if=\"totalExcelPages > 1\" class=\"excel-pagination\">\r\n <NPagination\r\n v-model:page=\"currentExcelPage\"\r\n :page-count=\"totalExcelPages\"\r\n :page-size=\"pageSize\"\r\n show-size-picker\r\n :page-sizes=\"PAGE_SIZE_OPTIONS\"\r\n @update:page-size=\"handlePageSizeChange\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NButton, NTabs, NTabPane, NText, NEmpty, NPagination } from \"naive-ui\";\r\nimport {\r\n getColumnLetter,\r\n formatCellValue,\r\n getCellClass,\r\n PAGE_SIZE_OPTIONS,\r\n} from \"../../data\";\r\nimport type { ExcelSheet, ExcelRow, ExcelColumn } from \"../../types\";\r\n\r\nconst props = defineProps<{\r\n sheets: ExcelSheet[];\r\n}>();\r\n\r\ndefineEmits<{\r\n reload: [];\r\n}>();\r\n\r\n/* ==================== 内部状态 ==================== */\r\nconst activeSheet = ref(\"\");\r\nconst showExcelFormat = ref(false);\r\nconst currentExcelPage = ref(1);\r\nconst pageSize = ref(50);\r\n\r\n/* ==================== 当前工作表数据 ==================== */\r\nconst currentData = ref<ExcelRow[]>([]);\r\nconst currentColumns = ref<ExcelColumn[]>([]);\r\n\r\n/* ==================== 计算属性 ==================== */\r\nconst totalExcelPages = computed(() =>\r\n Math.ceil(currentData.value.length / pageSize.value),\r\n);\r\n\r\nconst paginatedData = computed(() => {\r\n const start = (currentExcelPage.value - 1) * pageSize.value;\r\n return currentData.value.slice(start, start + pageSize.value);\r\n});\r\n\r\n/* ==================== 方法 ==================== */\r\nconst handlePageSizeChange = (newPageSize: number) => {\r\n pageSize.value = newPageSize;\r\n currentExcelPage.value = 1;\r\n};\r\n\r\nconst syncSheetData = (sheetName: string) => {\r\n const sheet = props.sheets.find((s) => s.name === sheetName);\r\n if (sheet) {\r\n currentData.value = sheet.data;\r\n currentColumns.value = sheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n};\r\n\r\n/* ==================== 监听器 ==================== */\r\nwatch(activeSheet, (newSheet) => {\r\n syncSheetData(newSheet);\r\n});\r\n\r\n/* sheets 变化时初始化 */\r\nwatch(\r\n () => props.sheets,\r\n (newSheets) => {\r\n if (newSheets.length > 0) {\r\n const [firstSheet] = newSheets;\r\n activeSheet.value = firstSheet.name;\r\n currentData.value = firstSheet.data;\r\n currentColumns.value = firstSheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n ExcelViewer — Excel 表格预览子组件\r\n 负责: 工作表切换 + 表格渲染(合并单元格) + 分页 + 格式切换\r\n-->\r\n<template>\r\n <div class=\"file-container excel-container\">\r\n <!-- 工具栏 -->\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NTabs\r\n v-if=\"sheets.length > 1\"\r\n v-model:value=\"activeSheet\"\r\n type=\"card\"\r\n size=\"small\"\r\n >\r\n <NTabPane\r\n v-for=\"sheet in sheets\"\r\n :key=\"sheet.name\"\r\n :name=\"sheet.name\"\r\n :tab=\"sheet.name\"\r\n />\r\n </NTabs>\r\n <span v-else class=\"text-sm text-gray-600\">\r\n 工作表: {{ activeSheet }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showExcelFormat = !showExcelFormat\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-format-paint\" />\r\n </template>\r\n {{ showExcelFormat ? \"紧凑视图\" : \"完整格式\" }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"excel-viewer\">\r\n <!-- 信息面板 -->\r\n <div v-if=\"currentData.length > 0\" class=\"excel-info\">\r\n <NText depth=\"3\" class=\"text-sm\">\r\n 当前工作表: {{ activeSheet }} | 总行数: {{ currentData.length }} |\r\n 总列数: {{ currentColumns.length }} | 当前页:\r\n {{ currentExcelPage }}/{{ totalExcelPages }}\r\n </NText>\r\n </div>\r\n\r\n <!-- 表格 -->\r\n <div class=\"excel-table-container\">\r\n <div\r\n class=\"excel-table-wrapper\"\r\n :class=\"{ 'simple-mode': !showExcelFormat }\"\r\n >\r\n <table v-if=\"currentData.length > 0\" class=\"excel-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"row-number\">行号</th>\r\n <th\r\n v-for=\"(col, index) in currentColumns\"\r\n :key=\"col.key\"\r\n class=\"excel-header\"\r\n :style=\"{ minWidth: col.width + 'px' }\"\r\n >\r\n <div class=\"header-content\">\r\n <span class=\"column-letter\">{{\r\n getColumnLetter(index)\r\n }}</span>\r\n <span class=\"column-title\">{{ col.title }}</span>\r\n </div>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n v-for=\"(row, rowIndex) in paginatedData\"\r\n :key=\"rowIndex\"\r\n class=\"excel-row\"\r\n >\r\n <td class=\"row-number\">\r\n {{ (currentExcelPage - 1) * pageSize + rowIndex + 1 }}\r\n </td>\r\n <td\r\n v-for=\"col in currentColumns\"\r\n :key=\"col.key\"\r\n v-show=\"!row[col.key]?.hidden\"\r\n class=\"excel-cell\"\r\n :class=\"[\r\n getCellClass(row[col.key]?.value),\r\n row[col.key]?.merged ? 'merged-cell' : '',\r\n !showExcelFormat ? 'compact-cell' : '',\r\n ]\"\r\n :rowspan=\"row[col.key]?.rowspan || 1\"\r\n :colspan=\"row[col.key]?.colspan || 1\"\r\n :title=\"row[col.key]?.value\"\r\n >\r\n {{ formatCellValue(row[col.key]?.value) }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div v-else class=\"excel-empty\">\r\n <NEmpty description=\"该工作表没有数据或解析失败\">\r\n <template #extra>\r\n <NButton size=\"small\" @click=\"$emit('reload')\">\r\n 重新解析\r\n </NButton>\r\n </template>\r\n </NEmpty>\r\n </div>\r\n </div>\r\n\r\n <!-- 分页 -->\r\n <div v-if=\"totalExcelPages > 1\" class=\"excel-pagination\">\r\n <NPagination\r\n v-model:page=\"currentExcelPage\"\r\n :page-count=\"totalExcelPages\"\r\n :page-size=\"pageSize\"\r\n show-size-picker\r\n :page-sizes=\"PAGE_SIZE_OPTIONS\"\r\n @update:page-size=\"handlePageSizeChange\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NButton, NTabs, NTabPane, NText, NEmpty, NPagination } from \"naive-ui\";\r\nimport {\r\n getColumnLetter,\r\n formatCellValue,\r\n getCellClass,\r\n PAGE_SIZE_OPTIONS,\r\n} from \"../../data\";\r\nimport type { ExcelSheet, ExcelRow, ExcelColumn } from \"../../types\";\r\n\r\nconst props = defineProps<{\r\n sheets: ExcelSheet[];\r\n}>();\r\n\r\ndefineEmits<{\r\n reload: [];\r\n}>();\r\n\r\n/* ==================== 内部状态 ==================== */\r\nconst activeSheet = ref(\"\");\r\nconst showExcelFormat = ref(false);\r\nconst currentExcelPage = ref(1);\r\nconst pageSize = ref(50);\r\n\r\n/* ==================== 当前工作表数据 ==================== */\r\nconst currentData = ref<ExcelRow[]>([]);\r\nconst currentColumns = ref<ExcelColumn[]>([]);\r\n\r\n/* ==================== 计算属性 ==================== */\r\nconst totalExcelPages = computed(() =>\r\n Math.ceil(currentData.value.length / pageSize.value),\r\n);\r\n\r\nconst paginatedData = computed(() => {\r\n const start = (currentExcelPage.value - 1) * pageSize.value;\r\n return currentData.value.slice(start, start + pageSize.value);\r\n});\r\n\r\n/* ==================== 方法 ==================== */\r\nconst handlePageSizeChange = (newPageSize: number) => {\r\n pageSize.value = newPageSize;\r\n currentExcelPage.value = 1;\r\n};\r\n\r\nconst syncSheetData = (sheetName: string) => {\r\n const sheet = props.sheets.find((s) => s.name === sheetName);\r\n if (sheet) {\r\n currentData.value = sheet.data;\r\n currentColumns.value = sheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n};\r\n\r\n/* ==================== 监听器 ==================== */\r\nwatch(activeSheet, (newSheet) => {\r\n syncSheetData(newSheet);\r\n});\r\n\r\n/* sheets 变化时初始化 */\r\nwatch(\r\n () => props.sheets,\r\n (newSheets) => {\r\n if (newSheets.length > 0) {\r\n const [firstSheet] = newSheets;\r\n activeSheet.value = firstSheet.name;\r\n currentData.value = firstSheet.data;\r\n currentColumns.value = firstSheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n ExcelViewer — Excel 表格预览子组件\r\n 负责: 工作表切换 + 表格渲染(合并单元格) + 分页 + 格式切换\r\n-->\r\n<template>\r\n <div class=\"file-container excel-container\">\r\n <!-- 工具栏 -->\r\n <div class=\"file-toolbar\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex gap-2 items-center\">\r\n <NTabs\r\n v-if=\"sheets.length > 1\"\r\n v-model:value=\"activeSheet\"\r\n type=\"card\"\r\n size=\"small\"\r\n >\r\n <NTabPane\r\n v-for=\"sheet in sheets\"\r\n :key=\"sheet.name\"\r\n :name=\"sheet.name\"\r\n :tab=\"sheet.name\"\r\n />\r\n </NTabs>\r\n <span v-else class=\"text-sm text-gray-600\">\r\n 工作表: {{ activeSheet }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"flex gap-2 items-center\">\r\n <NButton size=\"small\" @click=\"showExcelFormat = !showExcelFormat\">\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-format-paint\" />\r\n </template>\r\n {{ showExcelFormat ? \"紧凑视图\" : \"完整格式\" }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"excel-viewer\">\r\n <!-- 信息面板 -->\r\n <div v-if=\"currentData.length > 0\" class=\"excel-info\">\r\n <NText depth=\"3\" class=\"text-sm\">\r\n 当前工作表: {{ activeSheet }} | 总行数: {{ currentData.length }} |\r\n 总列数: {{ currentColumns.length }} | 当前页:\r\n {{ currentExcelPage }}/{{ totalExcelPages }}\r\n </NText>\r\n </div>\r\n\r\n <!-- 表格 -->\r\n <div class=\"excel-table-container\">\r\n <div\r\n class=\"excel-table-wrapper\"\r\n :class=\"{ 'simple-mode': !showExcelFormat }\"\r\n >\r\n <table v-if=\"currentData.length > 0\" class=\"excel-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"row-number\">行号</th>\r\n <th\r\n v-for=\"(col, index) in currentColumns\"\r\n :key=\"col.key\"\r\n class=\"excel-header\"\r\n :style=\"{ minWidth: col.width + 'px' }\"\r\n >\r\n <div class=\"header-content\">\r\n <span class=\"column-letter\">{{\r\n getColumnLetter(index)\r\n }}</span>\r\n <span class=\"column-title\">{{ col.title }}</span>\r\n </div>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n v-for=\"(row, rowIndex) in paginatedData\"\r\n :key=\"rowIndex\"\r\n class=\"excel-row\"\r\n >\r\n <td class=\"row-number\">\r\n {{ (currentExcelPage - 1) * pageSize + rowIndex + 1 }}\r\n </td>\r\n <td\r\n v-for=\"col in currentColumns\"\r\n :key=\"col.key\"\r\n v-show=\"!row[col.key]?.hidden\"\r\n class=\"excel-cell\"\r\n :class=\"[\r\n getCellClass(row[col.key]?.value),\r\n row[col.key]?.merged ? 'merged-cell' : '',\r\n !showExcelFormat ? 'compact-cell' : '',\r\n ]\"\r\n :rowspan=\"row[col.key]?.rowspan || 1\"\r\n :colspan=\"row[col.key]?.colspan || 1\"\r\n :title=\"row[col.key]?.value\"\r\n >\r\n {{ formatCellValue(row[col.key]?.value) }}\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div v-else class=\"excel-empty\">\r\n <NEmpty description=\"该工作表没有数据或解析失败\">\r\n <template #extra>\r\n <NButton size=\"small\" @click=\"$emit('reload')\">\r\n 重新解析\r\n </NButton>\r\n </template>\r\n </NEmpty>\r\n </div>\r\n </div>\r\n\r\n <!-- 分页 -->\r\n <div v-if=\"totalExcelPages > 1\" class=\"excel-pagination\">\r\n <NPagination\r\n v-model:page=\"currentExcelPage\"\r\n :page-count=\"totalExcelPages\"\r\n :page-size=\"pageSize\"\r\n show-size-picker\r\n :page-sizes=\"PAGE_SIZE_OPTIONS\"\r\n @update:page-size=\"handlePageSizeChange\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from \"vue\";\r\nimport { NButton, NTabs, NTabPane, NText, NEmpty, NPagination } from \"naive-ui\";\r\nimport {\r\n getColumnLetter,\r\n formatCellValue,\r\n getCellClass,\r\n PAGE_SIZE_OPTIONS,\r\n} from \"../../data\";\r\nimport type { ExcelSheet, ExcelRow, ExcelColumn } from \"../../types\";\r\n\r\nconst props = defineProps<{\r\n sheets: ExcelSheet[];\r\n}>();\r\n\r\ndefineEmits<{\r\n reload: [];\r\n}>();\r\n\r\n/* ==================== 内部状态 ==================== */\r\nconst activeSheet = ref(\"\");\r\nconst showExcelFormat = ref(false);\r\nconst currentExcelPage = ref(1);\r\nconst pageSize = ref(50);\r\n\r\n/* ==================== 当前工作表数据 ==================== */\r\nconst currentData = ref<ExcelRow[]>([]);\r\nconst currentColumns = ref<ExcelColumn[]>([]);\r\n\r\n/* ==================== 计算属性 ==================== */\r\nconst totalExcelPages = computed(() =>\r\n Math.ceil(currentData.value.length / pageSize.value),\r\n);\r\n\r\nconst paginatedData = computed(() => {\r\n const start = (currentExcelPage.value - 1) * pageSize.value;\r\n return currentData.value.slice(start, start + pageSize.value);\r\n});\r\n\r\n/* ==================== 方法 ==================== */\r\nconst handlePageSizeChange = (newPageSize: number) => {\r\n pageSize.value = newPageSize;\r\n currentExcelPage.value = 1;\r\n};\r\n\r\nconst syncSheetData = (sheetName: string) => {\r\n const sheet = props.sheets.find((s) => s.name === sheetName);\r\n if (sheet) {\r\n currentData.value = sheet.data;\r\n currentColumns.value = sheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n};\r\n\r\n/* ==================== 监听器 ==================== */\r\nwatch(activeSheet, (newSheet) => {\r\n syncSheetData(newSheet);\r\n});\r\n\r\n/* sheets 变化时初始化 */\r\nwatch(\r\n () => props.sheets,\r\n (newSheets) => {\r\n if (newSheets.length > 0) {\r\n const [firstSheet] = newSheets;\r\n activeSheet.value = firstSheet.name;\r\n currentData.value = firstSheet.data;\r\n currentColumns.value = firstSheet.columns;\r\n currentExcelPage.value = 1;\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/**\r\n * useFilePreview — 文件预览核心 composable\r\n * 管理:文件状态、加载、类型检测、下载\r\n */\r\nimport { ref, computed, watch, onUnmounted, type Ref } from \"vue\";\r\nimport {\r\n extractFileNameFromUrl,\r\n getFileType,\r\n getFileConfig,\r\n loadPdf,\r\n loadWord,\r\n loadExcel,\r\n} from \"../data\";\r\nimport type { FilePreviewType, DocHeading, ExcelSheet } from \"../types\";\r\n\r\nexport interface UseFilePreviewOptions {\r\n file: Ref<File | undefined>;\r\n url: Ref<string | undefined>;\r\n fileName: Ref<string>;\r\n}\r\n\r\n/**\r\n * 文件预览核心 composable — 管理文件状态、加载、类型检测、下载\r\n * @param options - 文件源配置(file / url / fileName)\r\n * @param emit - 组件事件发射器\r\n */\r\nexport function useFilePreview(\r\n options: UseFilePreviewOptions,\r\n emit: {\r\n (e: \"preview\", file: File | string): void;\r\n (e: \"download\", file: File | string): void;\r\n },\r\n) {\r\n const { file, url, fileName } = options;\r\n\r\n /* ==================== 基础状态 ==================== */\r\n const loading = ref(false);\r\n const error = ref(\"\");\r\n const fileSize = ref(0);\r\n const showModal = ref(false);\r\n\r\n /* ==================== 解析后的数据 ==================== */\r\n const pdfUrl = ref(\"\");\r\n const pdfTotalPages = ref(0);\r\n\r\n const wordContent = ref(\"\");\r\n const wordHeadings = ref<DocHeading[]>([]);\r\n\r\n const excelSheets = ref<ExcelSheet[]>([]);\r\n\r\n /* ==================== 计算属性 ==================== */\r\n const displayFileName = computed(() => {\r\n if (fileName.value && fileName.value !== \"未知文件\") return fileName.value;\r\n if (file.value?.name) return file.value.name;\r\n if (url.value) return extractFileNameFromUrl(url.value);\r\n return \"未知文件\";\r\n });\r\n\r\n const fileType = computed<FilePreviewType>(() =>\r\n getFileType(displayFileName.value),\r\n );\r\n const fileConfig = computed(() => getFileConfig(fileType.value));\r\n\r\n /* ==================== 内部方法 ==================== */\r\n const clearState = () => {\r\n error.value = \"\";\r\n loading.value = false;\r\n pdfUrl.value = \"\";\r\n pdfTotalPages.value = 0;\r\n wordContent.value = \"\";\r\n wordHeadings.value = [];\r\n excelSheets.value = [];\r\n };\r\n\r\n const setError = (msg: string) => {\r\n error.value = msg;\r\n loading.value = false;\r\n };\r\n\r\n /* ==================== 文件解析 ==================== */\r\n const resolveFile = async (): Promise<File> => {\r\n if (file.value) {\r\n fileSize.value = file.value.size;\r\n return file.value;\r\n }\r\n if (url.value) {\r\n const response = await fetch(url.value);\r\n if (!response.ok)\r\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n\r\n const blob = await response.blob();\r\n const resolved = new File([blob], displayFileName.value, {\r\n type: blob.type,\r\n });\r\n fileSize.value = resolved.size;\r\n return resolved;\r\n }\r\n throw new Error(\"未提供文件或URL\");\r\n };\r\n\r\n const loadByType = async (\r\n currentFile: File,\r\n type: FilePreviewType,\r\n ): Promise<void> => {\r\n switch (type) {\r\n case \"pdf\": {\r\n const result = await loadPdf(currentFile);\r\n pdfUrl.value = result.url;\r\n pdfTotalPages.value = result.totalPages;\r\n break;\r\n }\r\n case \"word\": {\r\n const result = await loadWord(currentFile);\r\n wordContent.value = result.content;\r\n wordHeadings.value = result.headings;\r\n break;\r\n }\r\n case \"excel\": {\r\n const result = await loadExcel(currentFile);\r\n excelSheets.value = result.sheets;\r\n break;\r\n }\r\n default:\r\n throw new Error(\"不支持的文件格式\");\r\n }\r\n };\r\n\r\n /* ==================== 核心方法 ==================== */\r\n const loadFile = async () => {\r\n if (!file.value && !url.value) {\r\n setError(\"未提供文件或URL\");\r\n return;\r\n }\r\n\r\n clearState();\r\n loading.value = true;\r\n\r\n try {\r\n const currentFile = await resolveFile();\r\n await loadByType(currentFile, fileType.value);\r\n loading.value = false;\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : \"未知错误\";\r\n setError(`${fileType.value.toUpperCase()}文件加载失败: ${errorMessage}`);\r\n }\r\n };\r\n\r\n const openPreview = async () => {\r\n showModal.value = true;\r\n await loadFile();\r\n emit(\"preview\", file.value || url.value!);\r\n };\r\n\r\n const downloadFile = () => {\r\n if (file.value) {\r\n const downloadUrl = URL.createObjectURL(file.value);\r\n const a = Object.assign(document.createElement(\"a\"), {\r\n href: downloadUrl,\r\n download: displayFileName.value,\r\n });\r\n a.click();\r\n URL.revokeObjectURL(downloadUrl);\r\n } else if (url.value) {\r\n window.open(url.value, \"_blank\");\r\n }\r\n emit(\"download\", file.value || url.value!);\r\n };\r\n\r\n /* ==================== 副作用 ==================== */\r\n watch(\r\n () => file.value?.size,\r\n (newSize) => {\r\n fileSize.value = newSize || 0;\r\n },\r\n { immediate: true },\r\n );\r\n\r\n onUnmounted(() => {\r\n if (pdfUrl.value?.startsWith(\"blob:\")) {\r\n URL.revokeObjectURL(pdfUrl.value.split(\"#\")[0]);\r\n }\r\n });\r\n\r\n return {\r\n /* 状态 */\r\n loading,\r\n error,\r\n fileSize,\r\n showModal,\r\n /* 解析数据 */\r\n pdfUrl,\r\n pdfTotalPages,\r\n wordContent,\r\n wordHeadings,\r\n excelSheets,\r\n /* 计算属性 */\r\n displayFileName,\r\n fileType,\r\n fileConfig,\r\n /* 方法 */\r\n loadFile,\r\n openPreview,\r\n downloadFile,\r\n };\r\n}\r\n","/**\r\n * useFullscreen — 全屏切换 composable\r\n */\r\nimport { ref, onMounted, onUnmounted, type Ref } from \"vue\";\r\nimport { FULLSCREEN_EVENTS } from \"../data\";\r\n\r\n/**\r\n * 全屏切换 composable — 管理全屏状态与跨浏览器兼容\r\n * @param containerRef - 需要全屏的容器元素引用\r\n */\r\nexport function useFullscreen(containerRef: Ref<HTMLElement | undefined>) {\r\n const isFullscreen = ref(false);\r\n\r\n const handleFullscreenChange = () => {\r\n isFullscreen.value = !!document.fullscreenElement;\r\n };\r\n\r\n const tryMethods = (\r\n methods: Array<() => Promise<void>>,\r\n index = 0,\r\n ): Promise<void> => {\r\n if (index >= methods.length) {\r\n console.warn(\"无法切换全屏状态\");\r\n return Promise.resolve();\r\n }\r\n return methods[index]().catch(() => tryMethods(methods, index + 1));\r\n };\r\n\r\n const toggleFullscreen = async () => {\r\n const element = containerRef.value;\r\n if (!element) return;\r\n\r\n const isCurrentlyFullscreen = !!document.fullscreenElement;\r\n\r\n const methods = isCurrentlyFullscreen\r\n ? [\r\n () => document.exitFullscreen(),\r\n () => (document as any).webkitExitFullscreen(),\r\n () => (document as any).mozCancelFullScreen(),\r\n () => (document as any).msExitFullscreen(),\r\n ]\r\n : [\r\n () => element.requestFullscreen(),\r\n () => (element as any).webkitRequestFullscreen(),\r\n () => (element as any).mozRequestFullScreen(),\r\n () => (element as any).msRequestFullscreen(),\r\n ];\r\n\r\n await tryMethods(methods);\r\n };\r\n\r\n const exitFullscreen = async () => {\r\n if (document.fullscreenElement) {\r\n try {\r\n await document.exitFullscreen();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n isFullscreen.value = false;\r\n };\r\n\r\n onMounted(() => {\r\n FULLSCREEN_EVENTS.forEach((event) =>\r\n document.addEventListener(event, handleFullscreenChange),\r\n );\r\n });\r\n\r\n onUnmounted(() => {\r\n FULLSCREEN_EVENTS.forEach((event) =>\r\n document.removeEventListener(event, handleFullscreenChange),\r\n );\r\n });\r\n\r\n return { isFullscreen, toggleFullscreen, exitFullscreen };\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-01\r\n * @Description: 文件预览组件(PDF/Word/Excel)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-file-preview-wrapper\">\r\n <!-- 文件信息卡片模式 -->\r\n <div\r\n v-if=\"!autoPreview\"\r\n class=\"file-info-card\"\r\n >\r\n <div class=\"file-info\">\r\n <div class=\"file-icon\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"40\"\r\n :color=\"fileConfig.color\"\r\n />\r\n </div>\r\n\r\n <div class=\"file-details\">\r\n <div class=\"file-name\">\r\n <NEllipsis style=\"max-width: 250px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n </div>\r\n\r\n <div class=\"file-meta\">\r\n <span class=\"file-size\">{{ formatFileSize(fileSize) }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-actions\">\r\n <NButton\r\n type=\"primary\"\r\n @click=\"openPreview\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-visibility\" />\r\n </template>\r\n 预览\r\n </NButton>\r\n\r\n <NButton\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 模态框预览 -->\r\n <NModal\r\n v-model:show=\"showModal\"\r\n :mask-closable=\"false\"\r\n :closable=\"false\"\r\n :auto-focus=\"false\"\r\n transform-origin=\"center\"\r\n style=\"\r\n width: 85vw;\r\n max-width: 1200px;\r\n min-width: 800px;\r\n height: 75vh;\r\n max-height: 700px;\r\n min-height: 500px;\r\n \"\r\n >\r\n <div\r\n ref=\"modalContainer\"\r\n class=\"modal-container\"\r\n >\r\n <!-- 自定义头部 -->\r\n <div class=\"modal-header\">\r\n <div class=\"modal-title\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"20\"\r\n :color=\"fileConfig.color\"\r\n />\r\n <span>{{ displayFileName }}</span>\r\n </div>\r\n <div class=\"modal-actions\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"showModal = false\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容 -->\r\n <div class=\"modal-content\">\r\n <!-- 文件信息头部 -->\r\n <div class=\"preview-header\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex items-center gap-3\">\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n <template #icon>\r\n <C_Icon :name=\"fileConfig.icon\" />\r\n </template>\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n <NEllipsis style=\"max-width: 300px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <span class=\"text-sm text-gray-500\">{{\r\n formatFileSize(fileSize)\r\n }}</span>\r\n </div>\r\n\r\n <div class=\"flex gap-2\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n :disabled=\"loading\"\r\n @click=\"loadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-refresh\" />\r\n </template>\r\n 刷新\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"primary\"\r\n @click=\"toggleFullscreen\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen\r\n ? 'ic:outline-fullscreen-exit'\r\n : 'ic:outline-fullscreen'\r\n \"\r\n />\r\n </template>\r\n {{ isFullscreen ? '退出全屏' : '全屏' }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容区域 -->\r\n <div class=\"preview-content\">\r\n <!-- 加载和错误状态 -->\r\n <template v-if=\"loading || error\">\r\n <div class=\"status-container\">\r\n <NSpin\r\n v-if=\"loading\"\r\n size=\"large\"\r\n >\r\n <template #description>\r\n 正在加载{{ fileType.toUpperCase() }}文件...\r\n </template>\r\n </NSpin>\r\n <NResult\r\n v-else\r\n status=\"error\"\r\n title=\"预览失败\"\r\n :description=\"error\"\r\n >\r\n <template #footer>\r\n <NButton @click=\"loadFile\">重试</NButton>\r\n </template>\r\n </NResult>\r\n </div>\r\n </template>\r\n\r\n <!-- 文件预览 — 委托给子组件 -->\r\n <template v-else>\r\n <PdfViewer\r\n v-if=\"fileType === 'pdf'\"\r\n :pdf-url=\"pdfUrl\"\r\n :total-pages=\"pdfTotalPages\"\r\n />\r\n\r\n <WordViewer\r\n v-else-if=\"fileType === 'word'\"\r\n :content=\"wordContent\"\r\n :headings=\"wordHeadings\"\r\n />\r\n\r\n <ExcelViewer\r\n v-else-if=\"fileType === 'excel'\"\r\n :sheets=\"excelSheets\"\r\n @reload=\"loadFile\"\r\n />\r\n\r\n <!-- 不支持的文件类型 -->\r\n <NResult\r\n v-else\r\n status=\"warning\"\r\n title=\"不支持的文件格式\"\r\n :description=\"`暂不支持预览 ${fileType.toUpperCase()} 格式文件`\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRefs, watch } from 'vue'\r\n import { NButton, NEllipsis, NTag, NModal, NSpin, NResult } from 'naive-ui'\r\n import { formatFileSize } from './data'\r\n import PdfViewer from './components/PdfViewer/index.vue'\r\n import WordViewer from './components/WordViewer/index.vue'\r\n import ExcelViewer from './components/ExcelViewer/index.vue'\r\n import { useFilePreview } from './composables/useFilePreview'\r\n import { useFullscreen } from './composables/useFullscreen'\r\n\r\n defineOptions({ name: 'C_FilePreview' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n file?: File\r\n url?: string\r\n fileName?: string\r\n autoPreview?: boolean\r\n }>(),\r\n {\r\n fileName: '未知文件',\r\n autoPreview: false,\r\n }\r\n )\r\n\r\n const { file, url, fileName: propFileName, autoPreview } = toRefs(props)\r\n\r\n const emit = defineEmits<{\r\n preview: [file: File | string]\r\n download: [file: File | string]\r\n }>()\r\n\r\n /* ==================== Composables ==================== */\r\n const {\r\n loading,\r\n error,\r\n fileSize,\r\n showModal,\r\n pdfUrl,\r\n pdfTotalPages,\r\n wordContent,\r\n wordHeadings,\r\n excelSheets,\r\n displayFileName,\r\n fileType,\r\n fileConfig,\r\n loadFile,\r\n openPreview,\r\n downloadFile,\r\n } = useFilePreview({ file, url, fileName: propFileName }, emit)\r\n\r\n const modalContainer = ref<HTMLElement>()\r\n const { isFullscreen, toggleFullscreen, exitFullscreen } =\r\n useFullscreen(modalContainer)\r\n\r\n /* ==================== Modal 关闭时退出全屏 ==================== */\r\n watch(showModal, isShow => {\r\n if (!isShow) exitFullscreen()\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-01\r\n * @Description: 文件预览组件(PDF/Word/Excel)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-file-preview-wrapper\">\r\n <!-- 文件信息卡片模式 -->\r\n <div\r\n v-if=\"!autoPreview\"\r\n class=\"file-info-card\"\r\n >\r\n <div class=\"file-info\">\r\n <div class=\"file-icon\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"40\"\r\n :color=\"fileConfig.color\"\r\n />\r\n </div>\r\n\r\n <div class=\"file-details\">\r\n <div class=\"file-name\">\r\n <NEllipsis style=\"max-width: 250px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n </div>\r\n\r\n <div class=\"file-meta\">\r\n <span class=\"file-size\">{{ formatFileSize(fileSize) }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-actions\">\r\n <NButton\r\n type=\"primary\"\r\n @click=\"openPreview\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-visibility\" />\r\n </template>\r\n 预览\r\n </NButton>\r\n\r\n <NButton\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 模态框预览 -->\r\n <NModal\r\n v-model:show=\"showModal\"\r\n :mask-closable=\"false\"\r\n :closable=\"false\"\r\n :auto-focus=\"false\"\r\n transform-origin=\"center\"\r\n style=\"\r\n width: 85vw;\r\n max-width: 1200px;\r\n min-width: 800px;\r\n height: 75vh;\r\n max-height: 700px;\r\n min-height: 500px;\r\n \"\r\n >\r\n <div\r\n ref=\"modalContainer\"\r\n class=\"modal-container\"\r\n >\r\n <!-- 自定义头部 -->\r\n <div class=\"modal-header\">\r\n <div class=\"modal-title\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"20\"\r\n :color=\"fileConfig.color\"\r\n />\r\n <span>{{ displayFileName }}</span>\r\n </div>\r\n <div class=\"modal-actions\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"showModal = false\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容 -->\r\n <div class=\"modal-content\">\r\n <!-- 文件信息头部 -->\r\n <div class=\"preview-header\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex items-center gap-3\">\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n <template #icon>\r\n <C_Icon :name=\"fileConfig.icon\" />\r\n </template>\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n <NEllipsis style=\"max-width: 300px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <span class=\"text-sm text-gray-500\">{{\r\n formatFileSize(fileSize)\r\n }}</span>\r\n </div>\r\n\r\n <div class=\"flex gap-2\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n :disabled=\"loading\"\r\n @click=\"loadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-refresh\" />\r\n </template>\r\n 刷新\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"primary\"\r\n @click=\"toggleFullscreen\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen\r\n ? 'ic:outline-fullscreen-exit'\r\n : 'ic:outline-fullscreen'\r\n \"\r\n />\r\n </template>\r\n {{ isFullscreen ? '退出全屏' : '全屏' }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容区域 -->\r\n <div class=\"preview-content\">\r\n <!-- 加载和错误状态 -->\r\n <template v-if=\"loading || error\">\r\n <div class=\"status-container\">\r\n <NSpin\r\n v-if=\"loading\"\r\n size=\"large\"\r\n >\r\n <template #description>\r\n 正在加载{{ fileType.toUpperCase() }}文件...\r\n </template>\r\n </NSpin>\r\n <NResult\r\n v-else\r\n status=\"error\"\r\n title=\"预览失败\"\r\n :description=\"error\"\r\n >\r\n <template #footer>\r\n <NButton @click=\"loadFile\">重试</NButton>\r\n </template>\r\n </NResult>\r\n </div>\r\n </template>\r\n\r\n <!-- 文件预览 — 委托给子组件 -->\r\n <template v-else>\r\n <PdfViewer\r\n v-if=\"fileType === 'pdf'\"\r\n :pdf-url=\"pdfUrl\"\r\n :total-pages=\"pdfTotalPages\"\r\n />\r\n\r\n <WordViewer\r\n v-else-if=\"fileType === 'word'\"\r\n :content=\"wordContent\"\r\n :headings=\"wordHeadings\"\r\n />\r\n\r\n <ExcelViewer\r\n v-else-if=\"fileType === 'excel'\"\r\n :sheets=\"excelSheets\"\r\n @reload=\"loadFile\"\r\n />\r\n\r\n <!-- 不支持的文件类型 -->\r\n <NResult\r\n v-else\r\n status=\"warning\"\r\n title=\"不支持的文件格式\"\r\n :description=\"`暂不支持预览 ${fileType.toUpperCase()} 格式文件`\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRefs, watch } from 'vue'\r\n import { NButton, NEllipsis, NTag, NModal, NSpin, NResult } from 'naive-ui'\r\n import { formatFileSize } from './data'\r\n import PdfViewer from './components/PdfViewer/index.vue'\r\n import WordViewer from './components/WordViewer/index.vue'\r\n import ExcelViewer from './components/ExcelViewer/index.vue'\r\n import { useFilePreview } from './composables/useFilePreview'\r\n import { useFullscreen } from './composables/useFullscreen'\r\n\r\n defineOptions({ name: 'C_FilePreview' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n file?: File\r\n url?: string\r\n fileName?: string\r\n autoPreview?: boolean\r\n }>(),\r\n {\r\n fileName: '未知文件',\r\n autoPreview: false,\r\n }\r\n )\r\n\r\n const { file, url, fileName: propFileName, autoPreview } = toRefs(props)\r\n\r\n const emit = defineEmits<{\r\n preview: [file: File | string]\r\n download: [file: File | string]\r\n }>()\r\n\r\n /* ==================== Composables ==================== */\r\n const {\r\n loading,\r\n error,\r\n fileSize,\r\n showModal,\r\n pdfUrl,\r\n pdfTotalPages,\r\n wordContent,\r\n wordHeadings,\r\n excelSheets,\r\n displayFileName,\r\n fileType,\r\n fileConfig,\r\n loadFile,\r\n openPreview,\r\n downloadFile,\r\n } = useFilePreview({ file, url, fileName: propFileName }, emit)\r\n\r\n const modalContainer = ref<HTMLElement>()\r\n const { isFullscreen, toggleFullscreen, exitFullscreen } =\r\n useFullscreen(modalContainer)\r\n\r\n /* ==================== Modal 关闭时退出全屏 ==================== */\r\n watch(showModal, isShow => {\r\n if (!isShow) exitFullscreen()\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-07-01\r\n * @Description: 文件预览组件(PDF/Word/Excel)\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-file-preview-wrapper\">\r\n <!-- 文件信息卡片模式 -->\r\n <div\r\n v-if=\"!autoPreview\"\r\n class=\"file-info-card\"\r\n >\r\n <div class=\"file-info\">\r\n <div class=\"file-icon\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"40\"\r\n :color=\"fileConfig.color\"\r\n />\r\n </div>\r\n\r\n <div class=\"file-details\">\r\n <div class=\"file-name\">\r\n <NEllipsis style=\"max-width: 250px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n </div>\r\n\r\n <div class=\"file-meta\">\r\n <span class=\"file-size\">{{ formatFileSize(fileSize) }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"file-actions\">\r\n <NButton\r\n type=\"primary\"\r\n @click=\"openPreview\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-visibility\" />\r\n </template>\r\n 预览\r\n </NButton>\r\n\r\n <NButton\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 模态框预览 -->\r\n <NModal\r\n v-model:show=\"showModal\"\r\n :mask-closable=\"false\"\r\n :closable=\"false\"\r\n :auto-focus=\"false\"\r\n transform-origin=\"center\"\r\n style=\"\r\n width: 85vw;\r\n max-width: 1200px;\r\n min-width: 800px;\r\n height: 75vh;\r\n max-height: 700px;\r\n min-height: 500px;\r\n \"\r\n >\r\n <div\r\n ref=\"modalContainer\"\r\n class=\"modal-container\"\r\n >\r\n <!-- 自定义头部 -->\r\n <div class=\"modal-header\">\r\n <div class=\"modal-title\">\r\n <C_Icon\r\n :name=\"fileConfig.icon\"\r\n :size=\"20\"\r\n :color=\"fileConfig.color\"\r\n />\r\n <span>{{ displayFileName }}</span>\r\n </div>\r\n <div class=\"modal-actions\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"downloadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-download\" />\r\n </template>\r\n 下载\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n @click=\"showModal = false\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-close\" />\r\n </template>\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容 -->\r\n <div class=\"modal-content\">\r\n <!-- 文件信息头部 -->\r\n <div class=\"preview-header\">\r\n <div class=\"flex justify-between items-center\">\r\n <div class=\"flex items-center gap-3\">\r\n <NTag\r\n :type=\"fileConfig.tagType as any\"\r\n size=\"small\"\r\n >\r\n <template #icon>\r\n <C_Icon :name=\"fileConfig.icon\" />\r\n </template>\r\n {{ fileType.toUpperCase() }}\r\n </NTag>\r\n <NEllipsis style=\"max-width: 300px\">{{\r\n displayFileName\r\n }}</NEllipsis>\r\n <span class=\"text-sm text-gray-500\">{{\r\n formatFileSize(fileSize)\r\n }}</span>\r\n </div>\r\n\r\n <div class=\"flex gap-2\">\r\n <NButton\r\n size=\"small\"\r\n type=\"tertiary\"\r\n :disabled=\"loading\"\r\n @click=\"loadFile\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"ic:outline-refresh\" />\r\n </template>\r\n 刷新\r\n </NButton>\r\n <NButton\r\n size=\"small\"\r\n type=\"primary\"\r\n @click=\"toggleFullscreen\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"\r\n isFullscreen\r\n ? 'ic:outline-fullscreen-exit'\r\n : 'ic:outline-fullscreen'\r\n \"\r\n />\r\n </template>\r\n {{ isFullscreen ? '退出全屏' : '全屏' }}\r\n </NButton>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 预览内容区域 -->\r\n <div class=\"preview-content\">\r\n <!-- 加载和错误状态 -->\r\n <template v-if=\"loading || error\">\r\n <div class=\"status-container\">\r\n <NSpin\r\n v-if=\"loading\"\r\n size=\"large\"\r\n >\r\n <template #description>\r\n 正在加载{{ fileType.toUpperCase() }}文件...\r\n </template>\r\n </NSpin>\r\n <NResult\r\n v-else\r\n status=\"error\"\r\n title=\"预览失败\"\r\n :description=\"error\"\r\n >\r\n <template #footer>\r\n <NButton @click=\"loadFile\">重试</NButton>\r\n </template>\r\n </NResult>\r\n </div>\r\n </template>\r\n\r\n <!-- 文件预览 — 委托给子组件 -->\r\n <template v-else>\r\n <PdfViewer\r\n v-if=\"fileType === 'pdf'\"\r\n :pdf-url=\"pdfUrl\"\r\n :total-pages=\"pdfTotalPages\"\r\n />\r\n\r\n <WordViewer\r\n v-else-if=\"fileType === 'word'\"\r\n :content=\"wordContent\"\r\n :headings=\"wordHeadings\"\r\n />\r\n\r\n <ExcelViewer\r\n v-else-if=\"fileType === 'excel'\"\r\n :sheets=\"excelSheets\"\r\n @reload=\"loadFile\"\r\n />\r\n\r\n <!-- 不支持的文件类型 -->\r\n <NResult\r\n v-else\r\n status=\"warning\"\r\n title=\"不支持的文件格式\"\r\n :description=\"`暂不支持预览 ${fileType.toUpperCase()} 格式文件`\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </NModal>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { ref, toRefs, watch } from 'vue'\r\n import { NButton, NEllipsis, NTag, NModal, NSpin, NResult } from 'naive-ui'\r\n import { formatFileSize } from './data'\r\n import PdfViewer from './components/PdfViewer/index.vue'\r\n import WordViewer from './components/WordViewer/index.vue'\r\n import ExcelViewer from './components/ExcelViewer/index.vue'\r\n import { useFilePreview } from './composables/useFilePreview'\r\n import { useFullscreen } from './composables/useFullscreen'\r\n\r\n defineOptions({ name: 'C_FilePreview' })\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n file?: File\r\n url?: string\r\n fileName?: string\r\n autoPreview?: boolean\r\n }>(),\r\n {\r\n fileName: '未知文件',\r\n autoPreview: false,\r\n }\r\n )\r\n\r\n const { file, url, fileName: propFileName, autoPreview } = toRefs(props)\r\n\r\n const emit = defineEmits<{\r\n preview: [file: File | string]\r\n download: [file: File | string]\r\n }>()\r\n\r\n /* ==================== Composables ==================== */\r\n const {\r\n loading,\r\n error,\r\n fileSize,\r\n showModal,\r\n pdfUrl,\r\n pdfTotalPages,\r\n wordContent,\r\n wordHeadings,\r\n excelSheets,\r\n displayFileName,\r\n fileType,\r\n fileConfig,\r\n loadFile,\r\n openPreview,\r\n downloadFile,\r\n } = useFilePreview({ file, url, fileName: propFileName }, emit)\r\n\r\n const modalContainer = ref<HTMLElement>()\r\n const { isFullscreen, toggleFullscreen, exitFullscreen } =\r\n useFullscreen(modalContainer)\r\n\r\n /* ==================== Modal 关闭时退出全屏 ==================== */\r\n watch(showModal, isShow => {\r\n if (!isShow) exitFullscreen()\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"C_FilePreview2.js","names":[],"sources":["../src/components/C_FilePreview/data.ts","../src/components/C_FilePreview/components/PdfViewer/index.vue","../src/components/C_FilePreview/components/WordViewer/index.vue","../src/components/C_FilePreview/components/ExcelViewer/index.vue","../src/components/C_FilePreview/composables/useFilePreview.ts","../src/components/C_FilePreview/composables/useFullscreen.ts","../src/components/C_FilePreview/index.vue"],"sourcesContent":["/**\r\n * C_FilePreview 常量配置与工具函数\r\n * 类型定义统一在 ./types.ts\r\n */\r\nimport { type Ref } from \"vue\";\r\nimport * as XLSX from \"xlsx\";\r\nimport mammoth from \"mammoth\";\r\nimport type {\r\n FilePreviewType,\r\n FileConfig,\r\n ZoomConfig,\r\n ExcelRow,\r\n ExcelColumn,\r\n ExcelSheet,\r\n DocHeading,\r\n PdfLoadResult,\r\n WordLoadResult,\r\n ExcelLoadResult,\r\n} from \"./types\";\r\n\r\n/* ==================== 常量配置 ==================== */\r\n\r\nexport const FILE_TYPE_MAP: Record<string, FilePreviewType> = {\r\n pdf: \"pdf\",\r\n doc: \"word\",\r\n docx: \"word\",\r\n xls: \"excel\",\r\n xlsx: \"excel\",\r\n};\r\n\r\nexport const FILE_CONFIGS: Record<string, FileConfig> = {\r\n pdf: {\r\n tagType: \"error\",\r\n icon: \"ic:outline-picture-as-pdf\",\r\n color: \"#dc2626\",\r\n },\r\n word: { tagType: \"info\", icon: \"ic:outline-description\", color: \"#2563eb\" },\r\n excel: { tagType: \"success\", icon: \"ic:outline-grid-on\", color: \"#16a34a\" },\r\n unknown: {\r\n tagType: \"default\",\r\n icon: \"ic:outline-insert-drive-file\",\r\n color: \"#6b7280\",\r\n },\r\n};\r\n\r\nexport const ZOOM_CONFIGS: Record<string, ZoomConfig> = {\r\n pdf: { min: 0.5, max: 3, step: 0.25, default: 1 },\r\n word: { min: 50, max: 200, step: 10, default: 100 },\r\n};\r\n\r\nexport const PAGE_SIZE_OPTIONS = [20, 50, 100, 200];\r\n\r\nexport const FULLSCREEN_EVENTS = [\r\n \"fullscreenchange\",\r\n \"webkitfullscreenchange\",\r\n \"mozfullscreenchange\",\r\n \"MSFullscreenChange\",\r\n];\r\n\r\n/* ==================== 文件信息工具函数 ==================== */\r\n\r\nexport const extractFileNameFromUrl = (url: string): string => {\r\n try {\r\n const urlPath = url.split(\"/\").pop() || url.split(\"\\\\\").pop();\r\n if (urlPath?.includes(\".\")) {\r\n const decodedName = decodeURIComponent(urlPath.split(\"?\")[0]);\r\n if (decodedName && decodedName !== url) return decodedName;\r\n }\r\n } catch (error) {\r\n console.warn(\"解析URL文件名失败:\", error);\r\n }\r\n return \"未知文件\";\r\n};\r\n\r\nexport const formatFileSize = (bytes: number): string => {\r\n if (bytes === 0) return \"0 B\";\r\n const k = 1024;\r\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + \" \" + sizes[i];\r\n};\r\n\r\nexport const getFileType = (fileName: string): FilePreviewType => {\r\n if (!fileName || fileName === \"未知文件\") return \"unknown\";\r\n const ext = fileName.toLowerCase().split(\".\").pop();\r\n if (!ext) return \"unknown\";\r\n return FILE_TYPE_MAP[ext] || \"unknown\";\r\n};\r\n\r\nexport const getFileConfig = (fileType: string): FileConfig => {\r\n return FILE_CONFIGS[fileType] || FILE_CONFIGS.unknown;\r\n};\r\n\r\n/* ==================== 缩放工具 ==================== */\r\n\r\nexport const createZoomHandler = (\r\n valueRef: Ref<number>,\r\n config: ZoomConfig,\r\n) => {\r\n return (action: \"in\" | \"out\" | \"reset\") => {\r\n const { min, max, step, default: defaultValue } = config;\r\n switch (action) {\r\n case \"reset\":\r\n valueRef.value = defaultValue;\r\n break;\r\n case \"in\":\r\n if (valueRef.value < max) valueRef.value += step;\r\n break;\r\n case \"out\":\r\n if (valueRef.value > min) valueRef.value -= step;\r\n break;\r\n }\r\n };\r\n};\r\n\r\n/* ==================== Excel 工具函数 ==================== */\r\n\r\nexport const getColumnLetter = (index: number): string => {\r\n let result = \"\";\r\n while (index >= 0) {\r\n result = String.fromCharCode(65 + (index % 26)) + result;\r\n index = Math.floor(index / 26) - 1;\r\n }\r\n return result;\r\n};\r\n\r\nexport const formatCellValue = (value: any): string => {\r\n if (!value) return \"\";\r\n const strValue = String(value).trim();\r\n\r\n if (!isNaN(Number(strValue)) && strValue !== \"\" && strValue.length < 15) {\r\n const num = Number(strValue);\r\n return Number.isInteger(num)\r\n ? num.toLocaleString()\r\n : num.toLocaleString(undefined, { maximumFractionDigits: 2 });\r\n }\r\n return strValue;\r\n};\r\n\r\nexport const getCellClass = (value: any): string => {\r\n if (!value) return \"cell-empty\";\r\n const strValue = String(value).trim();\r\n\r\n if (!isNaN(Number(strValue)) && strValue !== \"\") return \"cell-number\";\r\n if (strValue.match(/[■▬▪▫─━]/)) return \"cell-gantt\";\r\n if (\r\n strValue.match(/^\\d{4}[-/]\\d{2}[-/]\\d{2}/) ||\r\n strValue.match(/^\\d{2}[-/]\\d{2}[-/]\\d{4}/)\r\n )\r\n return \"cell-date\";\r\n if ([\"true\", \"false\"].includes(strValue.toLowerCase())) return \"cell-boolean\";\r\n return strValue.length > 20 ? \"cell-text cell-long\" : \"cell-text\";\r\n};\r\n\r\nexport const processExcelSheet = (\r\n worksheet: any,\r\n merges: any[],\r\n): { data: ExcelRow[]; columns: ExcelColumn[] } => {\r\n const range = XLSX.utils.decode_range(worksheet[\"!ref\"] || \"A1:A1\");\r\n const { c: maxCol, r: maxRow } = range.e;\r\n\r\n const columns: ExcelColumn[] = Array.from({ length: maxCol + 1 }, (_, c) => {\r\n const cellAddress = XLSX.utils.encode_cell({ r: 0, c });\r\n const cell = worksheet[cellAddress];\r\n const columnName = cell ? String(cell.v || \"\").trim() : `列${c + 1}`;\r\n return {\r\n title: columnName || `列${c + 1}`,\r\n key: `col_${c}`,\r\n width: Math.min(Math.max(columnName.length * 12, 80), 200),\r\n };\r\n });\r\n\r\n const mergeMap = new Map();\r\n merges.forEach(({ s: { r: sRow, c: sCol }, e: { r: eRow, c: eCol } }) => {\r\n for (let r = sRow; r <= eRow; r++) {\r\n for (let c = sCol; c <= eCol; c++) {\r\n mergeMap.set(`${r}-${c}`, {\r\n isMain: r === sRow && c === sCol,\r\n rowspan: eRow - sRow + 1,\r\n colspan: eCol - sCol + 1,\r\n });\r\n }\r\n }\r\n });\r\n\r\n const data: ExcelRow[] = Array.from({ length: maxRow + 1 }, (_, r) => {\r\n const row: ExcelRow = {};\r\n for (let c = 0; c <= maxCol; c++) {\r\n const cellAddress = XLSX.utils.encode_cell({ r, c });\r\n const cell = worksheet[cellAddress];\r\n const mergeInfo = mergeMap.get(`${r}-${c}`);\r\n\r\n row[`col_${c}`] = {\r\n value: cell ? cell.v || \"\" : \"\",\r\n merged: !!mergeInfo,\r\n hidden: mergeInfo && !mergeInfo.isMain,\r\n rowspan: mergeInfo?.isMain ? mergeInfo.rowspan : 1,\r\n colspan: mergeInfo?.isMain ? mergeInfo.colspan : 1,\r\n };\r\n }\r\n return row;\r\n });\r\n\r\n return { data, columns };\r\n};\r\n\r\n/* ==================== 文件加载器 ==================== */\r\n\r\nexport async function loadPdf(file: File): Promise<PdfLoadResult> {\r\n const fileUrl = URL.createObjectURL(file);\r\n return {\r\n url: fileUrl + \"#toolbar=1&navpanes=1&scrollbar=1&view=FitH\",\r\n totalPages: 1,\r\n };\r\n}\r\n\r\nexport async function loadWord(file: File): Promise<WordLoadResult> {\r\n const arrayBuffer = await file.arrayBuffer();\r\n const result = await mammoth.convertToHtml({\r\n arrayBuffer,\r\n styleMap: [\r\n \"p[style-name='Heading 1'] => h1:fresh\",\r\n \"p[style-name='Heading 2'] => h2:fresh\",\r\n \"p[style-name='Heading 3'] => h3:fresh\",\r\n \"p[style-name='Title'] => h1.title:fresh\",\r\n ],\r\n } as any);\r\n\r\n let content = result.value;\r\n const headings: DocHeading[] = [];\r\n\r\n /* 提取标题并注入 id */\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.innerHTML = content;\r\n const headingElements = tempDiv.querySelectorAll(\"h1, h2, h3, h4, h5, h6\");\r\n\r\n Array.from(headingElements).forEach((el, index) => {\r\n const id = `heading-${index}`;\r\n const level = parseInt(el.tagName.charAt(1));\r\n const text = el.textContent || \"\";\r\n\r\n content = content.replace(\r\n el.outerHTML,\r\n el.outerHTML.replace(\r\n el.tagName.toLowerCase(),\r\n `${el.tagName.toLowerCase()} id=\"${id}\"`,\r\n ),\r\n );\r\n\r\n headings.push({ id, text, level });\r\n });\r\n\r\n return { content, headings };\r\n}\r\n\r\nexport async function loadExcel(file: File): Promise<ExcelLoadResult> {\r\n const arrayBuffer = await file.arrayBuffer();\r\n const workbook = XLSX.read(arrayBuffer, {\r\n type: \"array\",\r\n cellStyles: true,\r\n cellFormula: true,\r\n cellDates: true,\r\n });\r\n\r\n if (!workbook.SheetNames.length) {\r\n throw new Error(\"Excel文件中没有找到工作表\");\r\n }\r\n\r\n const sheets: ExcelSheet[] = workbook.SheetNames.map((name) => {\r\n const worksheet = workbook.Sheets[name];\r\n const merges = worksheet[\"!merges\"] || [];\r\n const { data, columns } = processExcelSheet(worksheet, merges);\r\n return { name, data, merges, columns };\r\n });\r\n\r\n return { sheets };\r\n}\r\n","<!--\n PdfViewer — PDF 文件预览子组件\n 负责: 工具栏(翻页+缩放) + iframe 渲染\n-->\n<template>\n <div class=\"file-container pdf-container\">\n <div class=\"file-toolbar\">\n <div class=\"flex justify-between items-center\">\n <!-- 翻页控制 -->\n <div class=\"flex gap-2 items-center\">\n <NButton\n size=\"small\"\n :disabled=\"currentPage <= 1\"\n @click=\"changePage('prev')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-chevron-left\" />\n </template>\n </NButton>\n <NInputNumber\n v-model:value=\"currentPage\"\n size=\"small\"\n :min=\"1\"\n :max=\"totalPages\"\n style=\"width: 80px\"\n @update:value=\"changePage as any\"\n />\n <span class=\"text-sm text-gray-600\">/ {{ totalPages }}</span>\n <NButton\n size=\"small\"\n :disabled=\"currentPage >= totalPages\"\n @click=\"changePage('next')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-chevron-right\" />\n </template>\n </NButton>\n </div>\n\n <!-- 缩放控制 -->\n <div class=\"flex gap-2 items-center\">\n <NButton\n size=\"small\"\n :disabled=\"scale <= 0.5\"\n @click=\"adjustZoom('out')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-zoom-out\" />\n </template>\n </NButton>\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\n {{ Math.round(scale * 100) }}%\n </span>\n <NButton\n size=\"small\"\n :disabled=\"scale >= 3\"\n @click=\"adjustZoom('in')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-zoom-in\" />\n </template>\n </NButton>\n <NButton\n size=\"small\"\n @click=\"adjustZoom('reset')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-fit-screen\" />\n </template>\n 适应\n </NButton>\n </div>\n </div>\n </div>\n\n <div class=\"file-viewer\">\n <iframe\n v-if=\"pdfUrl\"\n :src=\"pdfUrl\"\n class=\"w-full h-full border-0\"\n title=\"PDF预览\"\n frameborder=\"0\"\n allowfullscreen\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref } from 'vue'\n import { NButton, NInputNumber } from 'naive-ui'\n import { createZoomHandler, ZOOM_CONFIGS } from '../../data'\n\n const props = defineProps<{\n pdfUrl: string\n totalPages: number\n }>()\n\n const currentPage = ref(1)\n const scale = ref(1)\n\n const adjustZoom = createZoomHandler(scale, ZOOM_CONFIGS.pdf)\n\n const changePage = (action: 'prev' | 'next' | number) => {\n if (typeof action === 'number') {\n currentPage.value = Math.max(1, Math.min(action, props.totalPages))\n } else {\n const delta = action === 'prev' ? -1 : 1\n currentPage.value = Math.max(\n 1,\n Math.min(currentPage.value + delta, props.totalPages)\n )\n }\n }\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n WordViewer — Word 文档预览子组件\n 负责: 目录导航 + 缩放 + 文档内容渲染\n-->\n<template>\n <div class=\"file-container word-container\">\n <div class=\"file-toolbar\">\n <div class=\"flex gap-2 items-center\">\n <NButton size=\"small\" @click=\"showOutline = !showOutline\">\n <template #icon>\n <C_Icon name=\"ic:outline-list\" />\n </template>\n {{ showOutline ? \"隐藏\" : \"显示\" }}目录\n </NButton>\n <NDivider vertical />\n <NButton\n size=\"small\"\n :disabled=\"wordZoom <= 50\"\n @click=\"adjustWordZoom('out')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-zoom-out\" />\n </template>\n </NButton>\n <span class=\"text-sm text-gray-600 min-w-12 text-center\">\n {{ wordZoom }}%\n </span>\n <NButton\n size=\"small\"\n :disabled=\"wordZoom >= 200\"\n @click=\"adjustWordZoom('in')\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-zoom-in\" />\n </template>\n </NButton>\n <NButton size=\"small\" @click=\"adjustWordZoom('reset')\">\n <template #icon>\n <C_Icon name=\"ic:outline-fit-screen\" />\n </template>\n 重置\n </NButton>\n </div>\n </div>\n\n <div class=\"word-layout\">\n <div class=\"word-main\">\n <!-- 侧边栏目录 -->\n <div v-if=\"showOutline\" class=\"word-outline\">\n <div class=\"outline-header\">\n <h3 class=\"text-sm font-semibold\">文档目录</h3>\n </div>\n <div class=\"outline-content\">\n <div\n v-for=\"(heading, index) in headings\"\n :key=\"index\"\n class=\"outline-item\"\n :class=\"`level-${heading.level}`\"\n @click=\"scrollToHeading(heading.id)\"\n >\n {{ heading.text }}\n </div>\n </div>\n </div>\n\n <!-- 主要内容区域 -->\n <div class=\"word-content\">\n <div\n class=\"word-document\"\n :style=\"{\n transform: `scale(${wordZoom / 100})`,\n transformOrigin: 'top center',\n }\"\n v-html=\"content\"\n ></div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from \"vue\";\nimport { NButton, NDivider } from \"naive-ui\";\nimport { createZoomHandler, ZOOM_CONFIGS } from \"../../data\";\nimport type { DocHeading } from \"../../types\";\n\ndefineProps<{\n content: string;\n headings: DocHeading[];\n}>();\n\nconst showOutline = ref(true);\nconst wordZoom = ref(100);\n\nconst adjustWordZoom = createZoomHandler(wordZoom, ZOOM_CONFIGS.word);\n\nconst scrollToHeading = (headingId: string) => {\n document\n .getElementById(headingId)\n ?.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n};\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n ExcelViewer — Excel 表格预览子组件\n 负责: 工作表切换 + 表格渲染(合并单元格) + 分页 + 格式切换\n-->\n<template>\n <div class=\"file-container excel-container\">\n <!-- 工具栏 -->\n <div class=\"file-toolbar\">\n <div class=\"flex justify-between items-center\">\n <div class=\"flex gap-2 items-center\">\n <NTabs\n v-if=\"sheets.length > 1\"\n v-model:value=\"activeSheet\"\n type=\"card\"\n size=\"small\"\n >\n <NTabPane\n v-for=\"sheet in sheets\"\n :key=\"sheet.name\"\n :name=\"sheet.name\"\n :tab=\"sheet.name\"\n />\n </NTabs>\n <span v-else class=\"text-sm text-gray-600\">\n 工作表: {{ activeSheet }}\n </span>\n </div>\n\n <div class=\"flex gap-2 items-center\">\n <NButton size=\"small\" @click=\"showExcelFormat = !showExcelFormat\">\n <template #icon>\n <C_Icon name=\"ic:outline-format-paint\" />\n </template>\n {{ showExcelFormat ? \"紧凑视图\" : \"完整格式\" }}\n </NButton>\n </div>\n </div>\n </div>\n\n <div class=\"excel-viewer\">\n <!-- 信息面板 -->\n <div v-if=\"currentData.length > 0\" class=\"excel-info\">\n <NText depth=\"3\" class=\"text-sm\">\n 当前工作表: {{ activeSheet }} | 总行数: {{ currentData.length }} |\n 总列数: {{ currentColumns.length }} | 当前页:\n {{ currentExcelPage }}/{{ totalExcelPages }}\n </NText>\n </div>\n\n <!-- 表格 -->\n <div class=\"excel-table-container\">\n <div\n class=\"excel-table-wrapper\"\n :class=\"{ 'simple-mode': !showExcelFormat }\"\n >\n <table v-if=\"currentData.length > 0\" class=\"excel-table\">\n <thead>\n <tr>\n <th class=\"row-number\">行号</th>\n <th\n v-for=\"(col, index) in currentColumns\"\n :key=\"col.key\"\n class=\"excel-header\"\n :style=\"{ minWidth: col.width + 'px' }\"\n >\n <div class=\"header-content\">\n <span class=\"column-letter\">{{\n getColumnLetter(index)\n }}</span>\n <span class=\"column-title\">{{ col.title }}</span>\n </div>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, rowIndex) in paginatedData\"\n :key=\"rowIndex\"\n class=\"excel-row\"\n >\n <td class=\"row-number\">\n {{ (currentExcelPage - 1) * pageSize + rowIndex + 1 }}\n </td>\n <td\n v-for=\"col in currentColumns\"\n :key=\"col.key\"\n v-show=\"!row[col.key]?.hidden\"\n class=\"excel-cell\"\n :class=\"[\n getCellClass(row[col.key]?.value),\n row[col.key]?.merged ? 'merged-cell' : '',\n !showExcelFormat ? 'compact-cell' : '',\n ]\"\n :rowspan=\"row[col.key]?.rowspan || 1\"\n :colspan=\"row[col.key]?.colspan || 1\"\n :title=\"row[col.key]?.value\"\n >\n {{ formatCellValue(row[col.key]?.value) }}\n </td>\n </tr>\n </tbody>\n </table>\n\n <div v-else class=\"excel-empty\">\n <NEmpty description=\"该工作表没有数据或解析失败\">\n <template #extra>\n <NButton size=\"small\" @click=\"$emit('reload')\">\n 重新解析\n </NButton>\n </template>\n </NEmpty>\n </div>\n </div>\n\n <!-- 分页 -->\n <div v-if=\"totalExcelPages > 1\" class=\"excel-pagination\">\n <NPagination\n v-model:page=\"currentExcelPage\"\n :page-count=\"totalExcelPages\"\n :page-size=\"pageSize\"\n show-size-picker\n :page-sizes=\"PAGE_SIZE_OPTIONS\"\n @update:page-size=\"handlePageSizeChange\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch } from \"vue\";\nimport { NButton, NTabs, NTabPane, NText, NEmpty, NPagination } from \"naive-ui\";\nimport {\n getColumnLetter,\n formatCellValue,\n getCellClass,\n PAGE_SIZE_OPTIONS,\n} from \"../../data\";\nimport type { ExcelSheet, ExcelRow, ExcelColumn } from \"../../types\";\n\nconst props = defineProps<{\n sheets: ExcelSheet[];\n}>();\n\ndefineEmits<{\n reload: [];\n}>();\n\n/* ==================== 内部状态 ==================== */\nconst activeSheet = ref(\"\");\nconst showExcelFormat = ref(false);\nconst currentExcelPage = ref(1);\nconst pageSize = ref(50);\n\n/* ==================== 当前工作表数据 ==================== */\nconst currentData = ref<ExcelRow[]>([]);\nconst currentColumns = ref<ExcelColumn[]>([]);\n\n/* ==================== 计算属性 ==================== */\nconst totalExcelPages = computed(() =>\n Math.ceil(currentData.value.length / pageSize.value),\n);\n\nconst paginatedData = computed(() => {\n const start = (currentExcelPage.value - 1) * pageSize.value;\n return currentData.value.slice(start, start + pageSize.value);\n});\n\n/* ==================== 方法 ==================== */\nconst handlePageSizeChange = (newPageSize: number) => {\n pageSize.value = newPageSize;\n currentExcelPage.value = 1;\n};\n\nconst syncSheetData = (sheetName: string) => {\n const sheet = props.sheets.find((s) => s.name === sheetName);\n if (sheet) {\n currentData.value = sheet.data;\n currentColumns.value = sheet.columns;\n currentExcelPage.value = 1;\n }\n};\n\n/* ==================== 监听器 ==================== */\nwatch(activeSheet, (newSheet) => {\n syncSheetData(newSheet);\n});\n\n/* sheets 变化时初始化 */\nwatch(\n () => props.sheets,\n (newSheets) => {\n if (newSheets.length > 0) {\n const [firstSheet] = newSheets;\n activeSheet.value = firstSheet.name;\n currentData.value = firstSheet.data;\n currentColumns.value = firstSheet.columns;\n currentExcelPage.value = 1;\n }\n },\n { immediate: true },\n);\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","/**\r\n * useFilePreview — 文件预览核心 composable\r\n * 管理:文件状态、加载、类型检测、下载\r\n */\r\nimport { ref, computed, watch, onUnmounted, type Ref } from \"vue\";\r\nimport {\r\n extractFileNameFromUrl,\r\n getFileType,\r\n getFileConfig,\r\n loadPdf,\r\n loadWord,\r\n loadExcel,\r\n} from \"../data\";\r\nimport type { FilePreviewType, DocHeading, ExcelSheet } from \"../types\";\r\n\r\nexport interface UseFilePreviewOptions {\r\n file: Ref<File | undefined>;\r\n url: Ref<string | undefined>;\r\n fileName: Ref<string>;\r\n}\r\n\r\n/**\r\n * 文件预览核心 composable — 管理文件状态、加载、类型检测、下载\r\n * @param options - 文件源配置(file / url / fileName)\r\n * @param emit - 组件事件发射器\r\n */\r\nexport function useFilePreview(\r\n options: UseFilePreviewOptions,\r\n emit: {\r\n (e: \"preview\", file: File | string): void;\r\n (e: \"download\", file: File | string): void;\r\n },\r\n) {\r\n const { file, url, fileName } = options;\r\n\r\n /* ==================== 基础状态 ==================== */\r\n const loading = ref(false);\r\n const error = ref(\"\");\r\n const fileSize = ref(0);\r\n const showModal = ref(false);\r\n\r\n /* ==================== 解析后的数据 ==================== */\r\n const pdfUrl = ref(\"\");\r\n const pdfTotalPages = ref(0);\r\n\r\n const wordContent = ref(\"\");\r\n const wordHeadings = ref<DocHeading[]>([]);\r\n\r\n const excelSheets = ref<ExcelSheet[]>([]);\r\n\r\n /* ==================== 计算属性 ==================== */\r\n const displayFileName = computed(() => {\r\n if (fileName.value && fileName.value !== \"未知文件\") return fileName.value;\r\n if (file.value?.name) return file.value.name;\r\n if (url.value) return extractFileNameFromUrl(url.value);\r\n return \"未知文件\";\r\n });\r\n\r\n const fileType = computed<FilePreviewType>(() =>\r\n getFileType(displayFileName.value),\r\n );\r\n const fileConfig = computed(() => getFileConfig(fileType.value));\r\n\r\n /* ==================== 内部方法 ==================== */\r\n const clearState = () => {\r\n error.value = \"\";\r\n loading.value = false;\r\n pdfUrl.value = \"\";\r\n pdfTotalPages.value = 0;\r\n wordContent.value = \"\";\r\n wordHeadings.value = [];\r\n excelSheets.value = [];\r\n };\r\n\r\n const setError = (msg: string) => {\r\n error.value = msg;\r\n loading.value = false;\r\n };\r\n\r\n /* ==================== 文件解析 ==================== */\r\n const resolveFile = async (): Promise<File> => {\r\n if (file.value) {\r\n fileSize.value = file.value.size;\r\n return file.value;\r\n }\r\n if (url.value) {\r\n const response = await fetch(url.value);\r\n if (!response.ok)\r\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n\r\n const blob = await response.blob();\r\n const resolved = new File([blob], displayFileName.value, {\r\n type: blob.type,\r\n });\r\n fileSize.value = resolved.size;\r\n return resolved;\r\n }\r\n throw new Error(\"未提供文件或URL\");\r\n };\r\n\r\n const loadByType = async (\r\n currentFile: File,\r\n type: FilePreviewType,\r\n ): Promise<void> => {\r\n switch (type) {\r\n case \"pdf\": {\r\n const result = await loadPdf(currentFile);\r\n pdfUrl.value = result.url;\r\n pdfTotalPages.value = result.totalPages;\r\n break;\r\n }\r\n case \"word\": {\r\n const result = await loadWord(currentFile);\r\n wordContent.value = result.content;\r\n wordHeadings.value = result.headings;\r\n break;\r\n }\r\n case \"excel\": {\r\n const result = await loadExcel(currentFile);\r\n excelSheets.value = result.sheets;\r\n break;\r\n }\r\n default:\r\n throw new Error(\"不支持的文件格式\");\r\n }\r\n };\r\n\r\n /* ==================== 核心方法 ==================== */\r\n const loadFile = async () => {\r\n if (!file.value && !url.value) {\r\n setError(\"未提供文件或URL\");\r\n return;\r\n }\r\n\r\n clearState();\r\n loading.value = true;\r\n\r\n try {\r\n const currentFile = await resolveFile();\r\n await loadByType(currentFile, fileType.value);\r\n loading.value = false;\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : \"未知错误\";\r\n setError(`${fileType.value.toUpperCase()}文件加载失败: ${errorMessage}`);\r\n }\r\n };\r\n\r\n const openPreview = async () => {\r\n showModal.value = true;\r\n await loadFile();\r\n emit(\"preview\", file.value || url.value!);\r\n };\r\n\r\n const downloadFile = () => {\r\n if (file.value) {\r\n const downloadUrl = URL.createObjectURL(file.value);\r\n const a = Object.assign(document.createElement(\"a\"), {\r\n href: downloadUrl,\r\n download: displayFileName.value,\r\n });\r\n a.click();\r\n URL.revokeObjectURL(downloadUrl);\r\n } else if (url.value) {\r\n window.open(url.value, \"_blank\");\r\n }\r\n emit(\"download\", file.value || url.value!);\r\n };\r\n\r\n /* ==================== 副作用 ==================== */\r\n watch(\r\n () => file.value?.size,\r\n (newSize) => {\r\n fileSize.value = newSize || 0;\r\n },\r\n { immediate: true },\r\n );\r\n\r\n onUnmounted(() => {\r\n if (pdfUrl.value?.startsWith(\"blob:\")) {\r\n URL.revokeObjectURL(pdfUrl.value.split(\"#\")[0]);\r\n }\r\n });\r\n\r\n return {\r\n /* 状态 */\r\n loading,\r\n error,\r\n fileSize,\r\n showModal,\r\n /* 解析数据 */\r\n pdfUrl,\r\n pdfTotalPages,\r\n wordContent,\r\n wordHeadings,\r\n excelSheets,\r\n /* 计算属性 */\r\n displayFileName,\r\n fileType,\r\n fileConfig,\r\n /* 方法 */\r\n loadFile,\r\n openPreview,\r\n downloadFile,\r\n };\r\n}\r\n","/**\r\n * useFullscreen — 全屏切换 composable\r\n */\r\nimport { ref, onMounted, onUnmounted, type Ref } from \"vue\";\r\nimport { FULLSCREEN_EVENTS } from \"../data\";\r\n\r\n/**\r\n * 全屏切换 composable — 管理全屏状态与跨浏览器兼容\r\n * @param containerRef - 需要全屏的容器元素引用\r\n */\r\nexport function useFullscreen(containerRef: Ref<HTMLElement | undefined>) {\r\n const isFullscreen = ref(false);\r\n\r\n const handleFullscreenChange = () => {\r\n isFullscreen.value = !!document.fullscreenElement;\r\n };\r\n\r\n const tryMethods = (\r\n methods: Array<() => Promise<void>>,\r\n index = 0,\r\n ): Promise<void> => {\r\n if (index >= methods.length) {\r\n console.warn(\"无法切换全屏状态\");\r\n return Promise.resolve();\r\n }\r\n return methods[index]().catch(() => tryMethods(methods, index + 1));\r\n };\r\n\r\n const toggleFullscreen = async () => {\r\n const element = containerRef.value;\r\n if (!element) return;\r\n\r\n const isCurrentlyFullscreen = !!document.fullscreenElement;\r\n\r\n const methods = isCurrentlyFullscreen\r\n ? [\r\n () => document.exitFullscreen(),\r\n () => (document as any).webkitExitFullscreen(),\r\n () => (document as any).mozCancelFullScreen(),\r\n () => (document as any).msExitFullscreen(),\r\n ]\r\n : [\r\n () => element.requestFullscreen(),\r\n () => (element as any).webkitRequestFullscreen(),\r\n () => (element as any).mozRequestFullScreen(),\r\n () => (element as any).msRequestFullscreen(),\r\n ];\r\n\r\n await tryMethods(methods);\r\n };\r\n\r\n const exitFullscreen = async () => {\r\n if (document.fullscreenElement) {\r\n try {\r\n await document.exitFullscreen();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n isFullscreen.value = false;\r\n };\r\n\r\n onMounted(() => {\r\n FULLSCREEN_EVENTS.forEach((event) =>\r\n document.addEventListener(event, handleFullscreenChange),\r\n );\r\n });\r\n\r\n onUnmounted(() => {\r\n FULLSCREEN_EVENTS.forEach((event) =>\r\n document.removeEventListener(event, handleFullscreenChange),\r\n );\r\n });\r\n\r\n return { isFullscreen, toggleFullscreen, exitFullscreen };\r\n}\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-07-01\n * @Description: 文件预览组件(PDF/Word/Excel)\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-file-preview-wrapper\">\n <!-- 文件信息卡片模式 -->\n <div\n v-if=\"!autoPreview\"\n class=\"file-info-card\"\n >\n <div class=\"file-info\">\n <div class=\"file-icon\">\n <C_Icon\n :name=\"fileConfig.icon\"\n :size=\"40\"\n :color=\"fileConfig.color\"\n />\n </div>\n\n <div class=\"file-details\">\n <div class=\"file-name\">\n <NEllipsis style=\"max-width: 250px\">{{\n displayFileName\n }}</NEllipsis>\n <NTag\n :type=\"fileConfig.tagType as any\"\n size=\"small\"\n >\n {{ fileType.toUpperCase() }}\n </NTag>\n </div>\n\n <div class=\"file-meta\">\n <span class=\"file-size\">{{ formatFileSize(fileSize) }}</span>\n </div>\n </div>\n\n <div class=\"file-actions\">\n <NButton\n type=\"primary\"\n @click=\"openPreview\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-visibility\" />\n </template>\n 预览\n </NButton>\n\n <NButton\n type=\"tertiary\"\n @click=\"downloadFile\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-download\" />\n </template>\n 下载\n </NButton>\n </div>\n </div>\n </div>\n\n <!-- 模态框预览 -->\n <NModal\n v-model:show=\"showModal\"\n :mask-closable=\"false\"\n :closable=\"false\"\n :auto-focus=\"false\"\n transform-origin=\"center\"\n style=\"\n width: 85vw;\n max-width: 1200px;\n min-width: 800px;\n height: 75vh;\n max-height: 700px;\n min-height: 500px;\n \"\n >\n <div\n ref=\"modalContainer\"\n class=\"modal-container\"\n >\n <!-- 自定义头部 -->\n <div class=\"modal-header\">\n <div class=\"modal-title\">\n <C_Icon\n :name=\"fileConfig.icon\"\n :size=\"20\"\n :color=\"fileConfig.color\"\n />\n <span>{{ displayFileName }}</span>\n </div>\n <div class=\"modal-actions\">\n <NButton\n size=\"small\"\n type=\"tertiary\"\n @click=\"downloadFile\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-download\" />\n </template>\n 下载\n </NButton>\n <NButton\n size=\"small\"\n type=\"tertiary\"\n @click=\"showModal = false\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-close\" />\n </template>\n </NButton>\n </div>\n </div>\n\n <!-- 预览内容 -->\n <div class=\"modal-content\">\n <!-- 文件信息头部 -->\n <div class=\"preview-header\">\n <div class=\"flex justify-between items-center\">\n <div class=\"flex items-center gap-3\">\n <NTag\n :type=\"fileConfig.tagType as any\"\n size=\"small\"\n >\n <template #icon>\n <C_Icon :name=\"fileConfig.icon\" />\n </template>\n {{ fileType.toUpperCase() }}\n </NTag>\n <NEllipsis style=\"max-width: 300px\">{{\n displayFileName\n }}</NEllipsis>\n <span class=\"text-sm text-gray-500\">{{\n formatFileSize(fileSize)\n }}</span>\n </div>\n\n <div class=\"flex gap-2\">\n <NButton\n size=\"small\"\n type=\"tertiary\"\n :disabled=\"loading\"\n @click=\"loadFile\"\n >\n <template #icon>\n <C_Icon name=\"ic:outline-refresh\" />\n </template>\n 刷新\n </NButton>\n <NButton\n size=\"small\"\n type=\"primary\"\n @click=\"toggleFullscreen\"\n >\n <template #icon>\n <C_Icon\n :name=\"\n isFullscreen\n ? 'ic:outline-fullscreen-exit'\n : 'ic:outline-fullscreen'\n \"\n />\n </template>\n {{ isFullscreen ? '退出全屏' : '全屏' }}\n </NButton>\n </div>\n </div>\n </div>\n\n <!-- 预览内容区域 -->\n <div class=\"preview-content\">\n <!-- 加载和错误状态 -->\n <template v-if=\"loading || error\">\n <div class=\"status-container\">\n <NSpin\n v-if=\"loading\"\n size=\"large\"\n >\n <template #description>\n 正在加载{{ fileType.toUpperCase() }}文件...\n </template>\n </NSpin>\n <NResult\n v-else\n status=\"error\"\n title=\"预览失败\"\n :description=\"error\"\n >\n <template #footer>\n <NButton @click=\"loadFile\">重试</NButton>\n </template>\n </NResult>\n </div>\n </template>\n\n <!-- 文件预览 — 委托给子组件 -->\n <template v-else>\n <PdfViewer\n v-if=\"fileType === 'pdf'\"\n :pdf-url=\"pdfUrl\"\n :total-pages=\"pdfTotalPages\"\n />\n\n <WordViewer\n v-else-if=\"fileType === 'word'\"\n :content=\"wordContent\"\n :headings=\"wordHeadings\"\n />\n\n <ExcelViewer\n v-else-if=\"fileType === 'excel'\"\n :sheets=\"excelSheets\"\n @reload=\"loadFile\"\n />\n\n <!-- 不支持的文件类型 -->\n <NResult\n v-else\n status=\"warning\"\n title=\"不支持的文件格式\"\n :description=\"`暂不支持预览 ${fileType.toUpperCase()} 格式文件`\"\n />\n </template>\n </div>\n </div>\n </div>\n </NModal>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, toRefs, watch } from 'vue'\n import { NButton, NEllipsis, NTag, NModal, NSpin, NResult } from 'naive-ui'\n import { formatFileSize } from './data'\n import PdfViewer from './components/PdfViewer/index.vue'\n import WordViewer from './components/WordViewer/index.vue'\n import ExcelViewer from './components/ExcelViewer/index.vue'\n import { useFilePreview } from './composables/useFilePreview'\n import { useFullscreen } from './composables/useFullscreen'\n\n defineOptions({ name: 'C_FilePreview' })\n\n const props = withDefaults(\n defineProps<{\n file?: File\n url?: string\n fileName?: string\n autoPreview?: boolean\n }>(),\n {\n fileName: '未知文件',\n autoPreview: false,\n }\n )\n\n const { file, url, fileName: propFileName, autoPreview } = toRefs(props)\n\n const emit = defineEmits<{\n preview: [file: File | string]\n download: [file: File | string]\n }>()\n\n /* ==================== Composables ==================== */\n const {\n loading,\n error,\n fileSize,\n showModal,\n pdfUrl,\n pdfTotalPages,\n wordContent,\n wordHeadings,\n excelSheets,\n displayFileName,\n fileType,\n fileConfig,\n loadFile,\n openPreview,\n downloadFile,\n } = useFilePreview({ file, url, fileName: propFileName }, emit)\n\n const modalContainer = ref<HTMLElement>()\n const { isFullscreen, toggleFullscreen, exitFullscreen } =\n useFullscreen(modalContainer)\n\n /* ==================== Modal 关闭时退出全屏 ==================== */\n watch(showModal, isShow => {\n if (!isShow) exitFullscreen()\n })\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n"],"mappings":"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"}