@robot-admin/naive-ui-components 0.10.3 → 0.11.1

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 (659) hide show
  1. package/CHANGELOG.md +117 -100
  2. package/LICENSE +21 -21
  3. package/README.md +463 -318
  4. package/README_EN.md +404 -0
  5. package/SECURITY.md +23 -0
  6. package/dist/C_ActionBar.cjs +1 -1
  7. package/dist/C_ActionBar.css +46 -48
  8. package/dist/C_ActionBar.d.cts +1 -1
  9. package/dist/C_ActionBar.js +1 -1
  10. package/dist/C_ActionBar2.cjs +1 -0
  11. package/dist/C_ActionBar2.js +1 -2
  12. package/dist/C_AntV.cjs +1 -1
  13. package/dist/C_AntV.css +3 -3
  14. package/dist/C_AntV.d.cts +1 -1
  15. package/dist/C_AntV.js +1 -1
  16. package/dist/C_AntV2.cjs +4 -0
  17. package/dist/C_AntV2.js +3 -4
  18. package/dist/C_AudioPlayer.cjs +1 -1
  19. package/dist/C_AudioPlayer.css +15 -7
  20. package/dist/C_AudioPlayer.d.cts +1 -1
  21. package/dist/C_AudioPlayer.js +1 -1
  22. package/dist/C_AudioPlayer2.cjs +1 -0
  23. package/dist/C_AudioPlayer2.js +1 -2
  24. package/dist/C_AvatarGroup.cjs +1 -1
  25. package/dist/C_AvatarGroup.css +15 -7
  26. package/dist/C_AvatarGroup.d.cts +1 -1
  27. package/dist/C_AvatarGroup2.cjs +1 -0
  28. package/dist/C_AvatarGroup2.js +1 -2
  29. package/dist/C_Barcode.cjs +1 -1
  30. package/dist/C_Barcode.css +0 -2
  31. package/dist/C_Barcode.d.cts +1 -1
  32. package/dist/C_Barcode2.cjs +1 -0
  33. package/dist/C_Barcode2.js +1 -2
  34. package/dist/C_Breadcrumb.cjs +1 -1
  35. package/dist/C_Breadcrumb.css +0 -2
  36. package/dist/C_Breadcrumb.d.cts +2 -2
  37. package/dist/C_Breadcrumb.d.ts +1 -2
  38. package/dist/C_Breadcrumb.js +1 -1
  39. package/dist/C_Breadcrumb2.cjs +1 -0
  40. package/dist/C_Breadcrumb2.js +1 -2
  41. package/dist/C_Captcha.cjs +1 -1
  42. package/dist/C_Captcha.css +46 -21
  43. package/dist/C_Captcha.d.cts +3 -2
  44. package/dist/C_Captcha.d.ts +3 -2
  45. package/dist/C_Captcha.js +1 -1
  46. package/dist/C_Captcha2.cjs +1 -0
  47. package/dist/C_Captcha2.js +1 -2
  48. package/dist/C_Cascade.cjs +1 -1
  49. package/dist/C_Cascade.css +0 -2
  50. package/dist/C_Cascade.d.cts +1 -1
  51. package/dist/C_Cascade.d.ts +1 -1
  52. package/dist/C_Cascade2.cjs +1 -0
  53. package/dist/C_Cascade2.js +1 -2
  54. package/dist/C_Chat.cjs +1 -1
  55. package/dist/C_Chat.css +0 -2
  56. package/dist/C_Chat.d.cts +1 -1
  57. package/dist/C_Chat.d.ts +1 -1
  58. package/dist/C_Chat.js +1 -1
  59. package/dist/C_Chat2.cjs +1 -0
  60. package/dist/C_Chat2.js +1 -2
  61. package/dist/C_City.cjs +1 -1
  62. package/dist/C_City.css +28 -30
  63. package/dist/C_City.d.cts +1 -1
  64. package/dist/C_City.d.ts +1 -1
  65. package/dist/C_City2.cjs +1 -0
  66. package/dist/C_City2.js +1 -2
  67. package/dist/C_Code.cjs +1 -1
  68. package/dist/C_Code.css +241 -4
  69. package/dist/C_Code.d.cts +1 -1
  70. package/dist/C_Code.d.ts +1 -1
  71. package/dist/C_Code.js +1 -1
  72. package/dist/C_Code2.cjs +1 -0
  73. package/dist/C_Code2.js +1 -2
  74. package/dist/C_CollapsePanel.cjs +1 -1
  75. package/dist/C_CollapsePanel.css +12 -6
  76. package/dist/C_CollapsePanel.d.cts +1 -1
  77. package/dist/C_CollapsePanel.js +1 -1
  78. package/dist/C_CollapsePanel2.cjs +1 -0
  79. package/dist/C_CollapsePanel2.js +1 -2
  80. package/dist/C_ContextMenu.cjs +1 -1
  81. package/dist/C_ContextMenu.css +16 -18
  82. package/dist/C_ContextMenu.d.cts +1 -1
  83. package/dist/C_ContextMenu.d.ts +1 -1
  84. package/dist/C_ContextMenu.js +1 -1
  85. package/dist/C_ContextMenu2.cjs +1 -0
  86. package/dist/C_ContextMenu2.js +1 -2
  87. package/dist/C_Cron.cjs +1 -1
  88. package/dist/C_Cron.css +18 -8
  89. package/dist/C_Cron.d.cts +1 -1
  90. package/dist/C_Cron.js +1 -1
  91. package/dist/C_Cron2.cjs +1 -0
  92. package/dist/C_Cron2.js +1 -2
  93. package/dist/C_Date.cjs +1 -1
  94. package/dist/C_Date.css +1 -0
  95. package/dist/C_Date.d.cts +2 -2
  96. package/dist/C_Date.d.ts +2 -2
  97. package/dist/C_Date2.cjs +1 -0
  98. package/dist/C_Date2.js +1 -2
  99. package/dist/C_Draggable.cjs +1 -1
  100. package/dist/C_Draggable.css +9 -5
  101. package/dist/C_Draggable.d.cts +1 -1
  102. package/dist/C_Draggable2.cjs +1 -0
  103. package/dist/C_Draggable2.js +1 -2
  104. package/dist/C_Editor.cjs +1 -1
  105. package/dist/C_Editor.css +80 -67
  106. package/dist/C_Editor.d.cts +1 -1
  107. package/dist/C_Editor.d.ts +1 -1
  108. package/dist/C_Editor2.cjs +1 -0
  109. package/dist/C_Editor2.js +1 -2
  110. package/dist/C_FilePreview.cjs +1 -1
  111. package/dist/C_FilePreview.css +0 -2
  112. package/dist/C_FilePreview.d.cts +1 -1
  113. package/dist/C_FilePreview.js +1 -1
  114. package/dist/C_FilePreview2.cjs +1 -0
  115. package/dist/C_FilePreview2.js +1 -2
  116. package/dist/C_Form.base.css +980 -0
  117. package/dist/C_Form.cjs +1 -1
  118. package/dist/C_Form.css +256 -155
  119. package/dist/C_Form.d.cts +2 -2
  120. package/dist/C_Form.d.ts +2 -2
  121. package/dist/C_Form.js +1 -1
  122. package/dist/C_Form2.cjs +1 -0
  123. package/dist/C_Form2.js +1 -2
  124. package/dist/C_FormSearch.cjs +1 -1
  125. package/dist/C_FormSearch.css +47 -47
  126. package/dist/C_FormSearch.d.cts +2 -2
  127. package/dist/C_FormSearch.d.ts +2 -2
  128. package/dist/C_FormSearch2.cjs +1 -0
  129. package/dist/C_FormSearch2.js +1 -2
  130. package/dist/C_FormulaEditor.cjs +1 -1
  131. package/dist/C_FormulaEditor.css +64 -38
  132. package/dist/C_FormulaEditor.d.cts +1 -1
  133. package/dist/C_FormulaEditor.js +1 -1
  134. package/dist/C_FormulaEditor2.cjs +2 -0
  135. package/dist/C_FormulaEditor2.js +2 -2
  136. package/dist/C_FullCalendar.cjs +1 -1
  137. package/dist/C_FullCalendar.css +0 -2
  138. package/dist/C_FullCalendar.d.cts +1 -1
  139. package/dist/C_FullCalendar2.cjs +1 -0
  140. package/dist/C_FullCalendar2.js +1 -2
  141. package/dist/C_GlobalSearch.cjs +1 -1
  142. package/dist/C_GlobalSearch.css +111 -113
  143. package/dist/C_GlobalSearch.d.cts +1 -1
  144. package/dist/C_GlobalSearch2.cjs +1 -0
  145. package/dist/C_GlobalSearch2.js +1 -2
  146. package/dist/C_Guide.cjs +1 -1
  147. package/dist/C_Guide.css +1 -0
  148. package/dist/C_Guide.d.cts +1 -1
  149. package/dist/C_Guide.d.ts +1 -1
  150. package/dist/C_Guide.js +1 -1
  151. package/dist/C_Guide2.cjs +1 -0
  152. package/dist/C_Guide2.js +1 -2
  153. package/dist/C_Icon.cjs +1 -1
  154. package/dist/C_Icon.css +58 -0
  155. package/dist/C_Icon.d.cts +1 -1
  156. package/dist/C_Icon.d.ts +1 -1
  157. package/dist/C_Icon2.cjs +1 -0
  158. package/dist/C_Icon2.js +1 -2
  159. package/dist/C_ImageCropper.cjs +1 -1
  160. package/dist/C_ImageCropper.css +0 -2
  161. package/dist/C_ImageCropper.d.cts +1 -1
  162. package/dist/C_ImageCropper.js +1 -1
  163. package/dist/C_ImageCropper2.cjs +1 -0
  164. package/dist/C_ImageCropper2.js +1 -2
  165. package/dist/C_Language.cjs +1 -1
  166. package/dist/C_Language.css +1 -0
  167. package/dist/C_Language.d.cts +1 -1
  168. package/dist/C_Language.d.ts +1 -1
  169. package/dist/C_Language.js +1 -1
  170. package/dist/C_Language2.cjs +1 -0
  171. package/dist/C_Language2.js +1 -2
  172. package/dist/C_Login.cjs +1 -1
  173. package/dist/C_Login.css +92 -76
  174. package/dist/C_Login.d.cts +1 -1
  175. package/dist/C_Login.d.ts +1 -1
  176. package/dist/C_Login.js +1 -1
  177. package/dist/C_Login2.cjs +1 -0
  178. package/dist/C_Login2.js +1 -2
  179. package/dist/C_Map.cjs +1 -1
  180. package/dist/C_Map.css +665 -5
  181. package/dist/C_Map.d.cts +1 -1
  182. package/dist/C_Map2.cjs +1 -0
  183. package/dist/C_Map2.js +1 -2
  184. package/dist/C_Markdown.cjs +1 -1
  185. package/dist/C_Markdown.css +940 -35
  186. package/dist/C_Markdown.d.cts +1 -1
  187. package/dist/C_Markdown.d.ts +1 -1
  188. package/dist/C_Markdown2.cjs +1 -0
  189. package/dist/C_Markdown2.js +1 -2
  190. package/dist/C_Menu.cjs +1 -1
  191. package/dist/C_Menu.css +1 -0
  192. package/dist/C_Menu.d.cts +3 -3
  193. package/dist/C_Menu.d.ts +3 -4
  194. package/dist/C_Menu.js +1 -1
  195. package/dist/C_Menu2.cjs +1 -0
  196. package/dist/C_Menu2.js +1 -2
  197. package/dist/C_NotificationCenter.cjs +1 -1
  198. package/dist/C_NotificationCenter.css +95 -47
  199. package/dist/C_NotificationCenter.d.cts +1 -1
  200. package/dist/C_NotificationCenter.js +1 -1
  201. package/dist/C_NotificationCenter2.cjs +1 -0
  202. package/dist/C_NotificationCenter2.js +1 -2
  203. package/dist/C_OrgChart.cjs +1 -1
  204. package/dist/C_OrgChart.css +6 -4
  205. package/dist/C_OrgChart.d.cts +1 -1
  206. package/dist/C_OrgChart.d.ts +1 -1
  207. package/dist/C_OrgChart2.cjs +1 -0
  208. package/dist/C_OrgChart2.js +1 -2
  209. package/dist/C_Progress.cjs +1 -1
  210. package/dist/C_Progress.css +1 -0
  211. package/dist/C_Progress.d.cts +1 -1
  212. package/dist/C_Progress.d.ts +1 -1
  213. package/dist/C_Progress2.cjs +1 -0
  214. package/dist/C_Progress2.js +1 -2
  215. package/dist/C_QRCode.cjs +1 -1
  216. package/dist/C_QRCode.css +8 -10
  217. package/dist/C_QRCode.d.cts +1 -1
  218. package/dist/C_QRCode2.cjs +1 -0
  219. package/dist/C_QRCode2.js +1 -2
  220. package/dist/C_Signature.cjs +1 -1
  221. package/dist/C_Signature.css +0 -2
  222. package/dist/C_Signature.d.cts +1 -1
  223. package/dist/C_Signature.js +1 -1
  224. package/dist/C_Signature2.cjs +1 -0
  225. package/dist/C_Signature2.js +1 -2
  226. package/dist/C_Skeleton.cjs +1 -1
  227. package/dist/C_Skeleton.css +0 -2
  228. package/dist/C_Skeleton.d.cts +1 -1
  229. package/dist/C_Skeleton.d.ts +1 -1
  230. package/dist/C_Skeleton2.cjs +1 -0
  231. package/dist/C_Skeleton2.js +1 -2
  232. package/dist/C_SplitPane.cjs +1 -1
  233. package/dist/C_SplitPane.css +27 -11
  234. package/dist/C_SplitPane.d.cts +1 -1
  235. package/dist/C_SplitPane.js +1 -1
  236. package/dist/C_SplitPane2.cjs +1 -0
  237. package/dist/C_SplitPane2.js +1 -2
  238. package/dist/C_Steps.cjs +1 -1
  239. package/dist/C_Steps.css +37 -39
  240. package/dist/C_Steps.d.cts +1 -1
  241. package/dist/C_Steps.d.ts +1 -1
  242. package/dist/C_Steps2.cjs +1 -0
  243. package/dist/C_Steps2.js +1 -2
  244. package/dist/C_Table.base.css +1588 -0
  245. package/dist/C_Table.cjs +1 -1
  246. package/dist/C_Table.css +1202 -112
  247. package/dist/C_Table.d.cts +2 -2
  248. package/dist/C_Table.d.ts +11 -2
  249. package/dist/C_Table.js +1 -1
  250. package/dist/C_TagsView.cjs +1 -1
  251. package/dist/C_TagsView.css +44 -40
  252. package/dist/C_TagsView.d.cts +2 -2
  253. package/dist/C_TagsView.d.ts +2 -3
  254. package/dist/C_TagsView.js +1 -1
  255. package/dist/C_TagsView2.cjs +1 -0
  256. package/dist/C_TagsView2.js +1 -2
  257. package/dist/C_Theme.cjs +1 -1
  258. package/dist/C_Theme.css +1 -0
  259. package/dist/C_Theme.d.cts +1 -1
  260. package/dist/C_Theme.d.ts +1 -1
  261. package/dist/C_Theme.js +1 -1
  262. package/dist/C_Theme2.cjs +1 -0
  263. package/dist/C_Theme2.js +1 -2
  264. package/dist/C_Time.cjs +1 -1
  265. package/dist/C_Time.css +0 -2
  266. package/dist/C_Time.d.cts +2 -2
  267. package/dist/C_Time.d.ts +2 -2
  268. package/dist/C_Time2.cjs +1 -0
  269. package/dist/C_Time2.js +1 -2
  270. package/dist/C_Timeline.cjs +1 -1
  271. package/dist/C_Timeline.css +44 -46
  272. package/dist/C_Timeline.d.cts +1 -1
  273. package/dist/C_Timeline.js +1 -1
  274. package/dist/C_Timeline2.cjs +1 -0
  275. package/dist/C_Timeline2.js +1 -2
  276. package/dist/C_Transfer.cjs +1 -1
  277. package/dist/C_Transfer.css +21 -9
  278. package/dist/C_Transfer.d.cts +1 -1
  279. package/dist/C_Transfer.js +1 -1
  280. package/dist/C_Transfer2.cjs +1 -0
  281. package/dist/C_Transfer2.js +1 -2
  282. package/dist/C_Tree.cjs +1 -1
  283. package/dist/C_Tree.css +0 -2
  284. package/dist/C_Tree.d.cts +1 -1
  285. package/dist/C_Tree.js +1 -1
  286. package/dist/C_Tree2.cjs +1 -0
  287. package/dist/C_Tree2.js +1 -2
  288. package/dist/C_Upload.cjs +1 -1
  289. package/dist/C_Upload.css +17 -17
  290. package/dist/C_Upload.d.cts +1 -1
  291. package/dist/C_Upload.js +1 -1
  292. package/dist/C_Upload2.cjs +1 -0
  293. package/dist/C_Upload2.js +1 -25
  294. package/dist/C_VideoPlayer.cjs +1 -1
  295. package/dist/C_VideoPlayer.css +35 -24
  296. package/dist/C_VideoPlayer.d.cts +2 -2
  297. package/dist/C_VideoPlayer.d.ts +2 -2
  298. package/dist/C_VideoPlayer.js +1 -1
  299. package/dist/C_VideoPlayer2.cjs +3 -0
  300. package/dist/C_VideoPlayer2.js +3 -4
  301. package/dist/C_VtableGantt.cjs +1 -1
  302. package/dist/C_VtableGantt.css +15 -7
  303. package/dist/C_VtableGantt.d.cts +1 -1
  304. package/dist/C_VtableGantt.d.ts +1 -1
  305. package/dist/C_VtableGantt.js +1 -1
  306. package/dist/C_VtableGantt2.cjs +1 -0
  307. package/dist/C_VtableGantt2.js +1 -2
  308. package/dist/C_WaterFall.cjs +1 -1
  309. package/dist/C_WaterFall.css +15 -17
  310. package/dist/C_WaterFall.d.cts +1 -1
  311. package/dist/C_WaterFall2.cjs +1 -0
  312. package/dist/C_WaterFall2.js +1 -2
  313. package/dist/C_WorkFlow.cjs +1 -1
  314. package/dist/C_WorkFlow.css +257 -197
  315. package/dist/C_WorkFlow.d.cts +1 -1
  316. package/dist/C_WorkFlow.js +1 -1
  317. package/dist/C_WorkFlow2.cjs +1 -0
  318. package/dist/C_WorkFlow2.js +1 -2
  319. package/dist/city.cjs +1 -0
  320. package/dist/city.js +1 -2
  321. package/dist/config.cjs +1 -0
  322. package/dist/config.d.cts +33 -0
  323. package/dist/config.d.ts +33 -0
  324. package/dist/config.js +1 -0
  325. package/dist/constants.d.cts +272 -0
  326. package/dist/constants.d.ts +1 -2
  327. package/dist/constants2.d.cts +177 -0
  328. package/dist/constants2.d.ts +3 -4
  329. package/dist/constants3.d.cts +479 -0
  330. package/dist/constants3.d.ts +15 -11
  331. package/dist/constants4.d.cts +420 -0
  332. package/dist/constants4.d.ts +30 -40
  333. package/dist/constants5.d.cts +491 -0
  334. package/dist/constants5.d.ts +22 -6
  335. package/dist/data.cjs +1 -0
  336. package/dist/data.d.cts +67 -0
  337. package/dist/data.d.ts +11 -11
  338. package/dist/data.js +1 -0
  339. package/dist/export-helper.cjs +1 -0
  340. package/dist/helpers.cjs +1 -0
  341. package/dist/helpers.js +1 -0
  342. package/dist/html.cjs +1 -0
  343. package/dist/html.js +1 -0
  344. package/dist/images/marker-icon-2x.png +0 -0
  345. package/dist/images/marker-icon.png +0 -0
  346. package/dist/images/marker-shadow.png +0 -0
  347. package/dist/index.cjs +1 -2
  348. package/dist/index.d.cts +60 -99
  349. package/dist/index.d.ts +41 -83
  350. package/dist/index.js +1 -2
  351. package/dist/index.vue.d.cts +79 -0
  352. package/dist/index.vue.d.ts +3 -4
  353. package/dist/index10.vue.d.cts +47 -0
  354. package/dist/index10.vue.d.ts +80 -40
  355. package/dist/index11.vue.d.cts +88 -0
  356. package/dist/index11.vue.d.ts +68 -78
  357. package/dist/index12.vue.d.cts +79 -0
  358. package/dist/index12.vue.d.ts +50 -46
  359. package/dist/index13.vue.d.cts +64 -0
  360. package/dist/index13.vue.d.ts +99 -34
  361. package/dist/index14.vue.d.cts +106 -0
  362. package/dist/index14.vue.d.ts +82 -99
  363. package/dist/index15.vue.d.cts +91 -0
  364. package/dist/index15.vue.d.ts +25 -83
  365. package/dist/index16.vue.d.cts +34 -0
  366. package/dist/index16.vue.d.ts +113 -24
  367. package/dist/index17.vue.d.cts +124 -0
  368. package/dist/index17.vue.d.ts +76 -110
  369. package/dist/index18.vue.d.cts +83 -0
  370. package/dist/index18.vue.d.ts +67 -73
  371. package/dist/index19.vue.d.cts +101 -0
  372. package/dist/index19.vue.d.ts +93 -59
  373. package/dist/index2.vue.d.cts +82 -0
  374. package/dist/index2.vue.d.ts +6 -7
  375. package/dist/index20.vue.d.cts +54 -0
  376. package/dist/index20.vue.d.ts +40 -88
  377. package/dist/index21.vue.d.cts +103 -0
  378. package/dist/index21.vue.d.ts +89 -41
  379. package/dist/index22.vue.d.cts +45 -0
  380. package/dist/index22.vue.d.ts +37 -96
  381. package/dist/index23.vue.d.cts +19 -0
  382. package/dist/index23.vue.d.ts +8 -35
  383. package/dist/{index28.vue.d.ts → index24.vue.d.cts} +2 -3
  384. package/dist/index24.vue.d.ts +650 -86
  385. package/dist/index25.vue.d.cts +96 -0
  386. package/dist/index25.vue.d.ts +86 -10
  387. package/dist/index26.vue.d.cts +111 -0
  388. package/dist/index26.vue.d.ts +4 -5
  389. package/dist/index27.vue.d.cts +80 -0
  390. package/dist/index27.vue.d.ts +4 -5
  391. package/dist/index3.vue.d.cts +87 -0
  392. package/dist/index3.vue.d.ts +4 -5
  393. package/dist/index4.vue.d.cts +37 -0
  394. package/dist/index4.vue.d.ts +4 -5
  395. package/dist/index5.vue.d.cts +133 -0
  396. package/dist/index5.vue.d.ts +2 -3
  397. package/dist/index6.vue.d.cts +29 -0
  398. package/dist/index6.vue.d.ts +25 -38
  399. package/dist/index7.vue.d.cts +32 -0
  400. package/dist/index7.vue.d.ts +117 -23
  401. package/dist/index8.vue.d.cts +127 -0
  402. package/dist/index8.vue.d.ts +17 -111
  403. package/dist/index9.vue.d.cts +34 -0
  404. package/dist/index9.vue.d.ts +38 -26
  405. package/dist/{menuAdapter.d.ts → public.d.ts} +2 -3
  406. package/dist/resolver.cjs +1 -2
  407. package/dist/resolver.d.cts +6 -4
  408. package/dist/resolver.d.ts +6 -4
  409. package/dist/resolver.js +1 -2
  410. package/dist/storage.cjs +1 -0
  411. package/dist/storage.js +1 -2
  412. package/dist/style.css +9864 -7702
  413. package/dist/types.d.cts +107 -0
  414. package/dist/types.d.ts +58 -0
  415. package/dist/types2.d.cts +58 -0
  416. package/dist/useCalendarEvents.d.cts +150 -0
  417. package/dist/useCalendarEvents.d.ts +2 -3
  418. package/dist/useCollapsePanel.d.cts +133 -0
  419. package/dist/useCollapsePanel.d.ts +7 -8
  420. package/dist/useCropperCore.d.cts +104 -0
  421. package/dist/useCropperCore.d.ts +8 -6
  422. package/dist/useDraggableLayout.d.cts +196 -0
  423. package/dist/useDraggableLayout.d.ts +17 -15
  424. package/dist/useDynamicFormState.d.cts +749 -0
  425. package/dist/useDynamicFormState.d.ts +234 -112
  426. package/dist/useEdgeInteraction.d.cts +324 -0
  427. package/dist/useEdgeInteraction.d.ts +5 -6
  428. package/dist/useFullscreen.d.cts +165 -0
  429. package/dist/useFullscreen.d.ts +3 -4
  430. package/dist/useGlobalSearch.d.cts +110 -0
  431. package/dist/useGlobalSearch.d.ts +17 -9
  432. package/dist/useInfiniteScroll.d.cts +177 -0
  433. package/dist/useInfiniteScroll.d.ts +11 -3
  434. package/dist/useQRCode.d.cts +89 -0
  435. package/dist/useQRCode.d.ts +7 -5
  436. package/dist/useSearchState.d.cts +871 -0
  437. package/dist/useSearchState.d.ts +828 -28
  438. package/dist/useSignatureHistory.d.cts +197 -0
  439. package/dist/useSignatureHistory.d.ts +9 -4
  440. package/dist/useSplitResize.d.cts +157 -0
  441. package/dist/useSplitResize.d.ts +6 -7
  442. package/dist/useTableQuery.cjs +3 -0
  443. package/dist/useTableQuery.d.cts +1684 -0
  444. package/dist/useTableQuery.d.ts +1684 -0
  445. package/dist/useTableQuery.js +3 -0
  446. package/dist/useTimeSelection.d.cts +116 -0
  447. package/dist/useTimeSelection.d.ts +19 -8
  448. package/dist/useTreeOperations.d.cts +185 -0
  449. package/dist/useTreeOperations.d.ts +10 -8
  450. package/dist/useWorkflowValidation.d.cts +1051 -0
  451. package/dist/useWorkflowValidation.d.ts +62 -63
  452. package/dist/verification.d.cts +58 -0
  453. package/dist/verification.d.ts +58 -0
  454. package/package.json +102 -69
  455. package/dist/C_ActionBar-BAcfOfRw.css.map +0 -1
  456. package/dist/C_ActionBar-DG2HW7t5.css.map +0 -1
  457. package/dist/C_ActionBar.js.map +0 -1
  458. package/dist/C_ActionBar2.js.map +0 -1
  459. package/dist/C_AntV-D_jTK8oZ.css.map +0 -1
  460. package/dist/C_AntV-DanTAq22.css.map +0 -1
  461. package/dist/C_AntV.js.map +0 -1
  462. package/dist/C_AntV2.js.map +0 -1
  463. package/dist/C_AudioPlayer-BnYIJXPD.css.map +0 -1
  464. package/dist/C_AudioPlayer-ldTy9Y34.css.map +0 -1
  465. package/dist/C_AudioPlayer.js.map +0 -1
  466. package/dist/C_AudioPlayer2.js.map +0 -1
  467. package/dist/C_AvatarGroup-B9d-GJ9c.css.map +0 -1
  468. package/dist/C_AvatarGroup-SIzxuuZr.css.map +0 -1
  469. package/dist/C_AvatarGroup.js.map +0 -1
  470. package/dist/C_AvatarGroup2.js.map +0 -1
  471. package/dist/C_Barcode-CAU2mFcx.css.map +0 -1
  472. package/dist/C_Barcode-D2oJaEg3.css.map +0 -1
  473. package/dist/C_Barcode.js.map +0 -1
  474. package/dist/C_Barcode2.js.map +0 -1
  475. package/dist/C_Breadcrumb-BiH0d9AI.css.map +0 -1
  476. package/dist/C_Breadcrumb-Bqqrl8nX.css.map +0 -1
  477. package/dist/C_Breadcrumb.js.map +0 -1
  478. package/dist/C_Breadcrumb2.js.map +0 -1
  479. package/dist/C_Captcha-B3yrtG7t.css.map +0 -1
  480. package/dist/C_Captcha-D4hDdWDu.css.map +0 -1
  481. package/dist/C_Captcha.js.map +0 -1
  482. package/dist/C_Captcha2.js.map +0 -1
  483. package/dist/C_Cascade-CmCrLVft.css.map +0 -1
  484. package/dist/C_Cascade-U6A5AJJb.css.map +0 -1
  485. package/dist/C_Cascade.js.map +0 -1
  486. package/dist/C_Cascade2.js.map +0 -1
  487. package/dist/C_Chat-CF1SU7mc.css.map +0 -1
  488. package/dist/C_Chat-DeUv6uuI.css.map +0 -1
  489. package/dist/C_Chat.js.map +0 -1
  490. package/dist/C_Chat2.js.map +0 -1
  491. package/dist/C_City-DdkX6u64.css.map +0 -1
  492. package/dist/C_City-iP-dIvui.css.map +0 -1
  493. package/dist/C_City.js.map +0 -1
  494. package/dist/C_City2.js.map +0 -1
  495. package/dist/C_Code-BWmJMNS7.css.map +0 -1
  496. package/dist/C_Code-k14vjgVl.css.map +0 -1
  497. package/dist/C_Code.js.map +0 -1
  498. package/dist/C_Code2.js.map +0 -1
  499. package/dist/C_CollapsePanel-BSKcWSmY.css.map +0 -1
  500. package/dist/C_CollapsePanel-DRvRq8tB.css.map +0 -1
  501. package/dist/C_CollapsePanel.js.map +0 -1
  502. package/dist/C_CollapsePanel2.js.map +0 -1
  503. package/dist/C_ContextMenu-Bn_uhJSo.css.map +0 -1
  504. package/dist/C_ContextMenu-C9iuxG2n.css.map +0 -1
  505. package/dist/C_ContextMenu.js.map +0 -1
  506. package/dist/C_ContextMenu2.js.map +0 -1
  507. package/dist/C_Cron-BIQ2By9v.css.map +0 -1
  508. package/dist/C_Cron-BNSAGD6A.css.map +0 -1
  509. package/dist/C_Cron.js.map +0 -1
  510. package/dist/C_Cron2.js.map +0 -1
  511. package/dist/C_Date.js.map +0 -1
  512. package/dist/C_Date2.js.map +0 -1
  513. package/dist/C_Draggable-BDAbk4s5.css.map +0 -1
  514. package/dist/C_Draggable-UhfDLXop.css.map +0 -1
  515. package/dist/C_Draggable.js.map +0 -1
  516. package/dist/C_Draggable2.js.map +0 -1
  517. package/dist/C_Editor-CZOaChru.css.map +0 -1
  518. package/dist/C_Editor-kJAQq5z6.css.map +0 -1
  519. package/dist/C_Editor.js.map +0 -1
  520. package/dist/C_Editor2.js.map +0 -1
  521. package/dist/C_FilePreview-Bs_omgJS.css.map +0 -1
  522. package/dist/C_FilePreview-DbwoyF2j.css.map +0 -1
  523. package/dist/C_FilePreview.js.map +0 -1
  524. package/dist/C_FilePreview2.js.map +0 -1
  525. package/dist/C_Form-B_2ql62V.css.map +0 -1
  526. package/dist/C_Form-CX-7xsz3.css.map +0 -1
  527. package/dist/C_Form.js.map +0 -1
  528. package/dist/C_Form2.js.map +0 -1
  529. package/dist/C_FormSearch-C3F8peAY.css.map +0 -1
  530. package/dist/C_FormSearch-qW56bJPo.css.map +0 -1
  531. package/dist/C_FormSearch.js.map +0 -1
  532. package/dist/C_FormSearch2.js.map +0 -1
  533. package/dist/C_FormulaEditor-ChOvDbsZ.css.map +0 -1
  534. package/dist/C_FormulaEditor-mfiIUDY4.css.map +0 -1
  535. package/dist/C_FormulaEditor.js.map +0 -1
  536. package/dist/C_FormulaEditor2.js.map +0 -1
  537. package/dist/C_FullCalendar-C2nsqrgS.css.map +0 -1
  538. package/dist/C_FullCalendar-DdFtXVhy.css.map +0 -1
  539. package/dist/C_FullCalendar.js.map +0 -1
  540. package/dist/C_FullCalendar2.js.map +0 -1
  541. package/dist/C_GlobalSearch-Dq4Wo01K.css.map +0 -1
  542. package/dist/C_GlobalSearch-RB7J43gu.css.map +0 -1
  543. package/dist/C_GlobalSearch.js.map +0 -1
  544. package/dist/C_GlobalSearch2.js.map +0 -1
  545. package/dist/C_Guide.js.map +0 -1
  546. package/dist/C_Guide2.js.map +0 -1
  547. package/dist/C_Icon.js.map +0 -1
  548. package/dist/C_Icon2.js.map +0 -1
  549. package/dist/C_ImageCropper-CdTX2nxU.css.map +0 -1
  550. package/dist/C_ImageCropper-ilOqPklJ.css.map +0 -1
  551. package/dist/C_ImageCropper.js.map +0 -1
  552. package/dist/C_ImageCropper2.js.map +0 -1
  553. package/dist/C_Language.js.map +0 -1
  554. package/dist/C_Language2.js.map +0 -1
  555. package/dist/C_Login-B3qYkLrN.css.map +0 -1
  556. package/dist/C_Login-xMI1_ojE.css.map +0 -1
  557. package/dist/C_Login.js.map +0 -1
  558. package/dist/C_Login2.js.map +0 -1
  559. package/dist/C_Map-CWMMN58_.css.map +0 -1
  560. package/dist/C_Map-xSR2H-9o.css.map +0 -1
  561. package/dist/C_Map.js.map +0 -1
  562. package/dist/C_Map2.js.map +0 -1
  563. package/dist/C_Markdown-C7lTVJ1S.css.map +0 -1
  564. package/dist/C_Markdown-CZDm_baQ.css.map +0 -1
  565. package/dist/C_Markdown.js.map +0 -1
  566. package/dist/C_Markdown2.js.map +0 -1
  567. package/dist/C_Menu.js.map +0 -1
  568. package/dist/C_Menu2.js.map +0 -1
  569. package/dist/C_NotificationCenter-D7GGGWg7.css.map +0 -1
  570. package/dist/C_NotificationCenter-SSmeHA45.css.map +0 -1
  571. package/dist/C_NotificationCenter.js.map +0 -1
  572. package/dist/C_NotificationCenter2.js.map +0 -1
  573. package/dist/C_OrgChart-ChZu346B.css.map +0 -1
  574. package/dist/C_OrgChart-DqBufOv5.css.map +0 -1
  575. package/dist/C_OrgChart.js.map +0 -1
  576. package/dist/C_OrgChart2.js.map +0 -1
  577. package/dist/C_Progress.js.map +0 -1
  578. package/dist/C_Progress2.js.map +0 -1
  579. package/dist/C_QRCode-B_1lHUdx.css.map +0 -1
  580. package/dist/C_QRCode-CuQRYu0s.css.map +0 -1
  581. package/dist/C_QRCode.js.map +0 -1
  582. package/dist/C_QRCode2.js.map +0 -1
  583. package/dist/C_Signature-Bp-RBpAl.css.map +0 -1
  584. package/dist/C_Signature-Cb2VW1ok.css.map +0 -1
  585. package/dist/C_Signature.js.map +0 -1
  586. package/dist/C_Signature2.js.map +0 -1
  587. package/dist/C_Skeleton-BNPbaut7.css.map +0 -1
  588. package/dist/C_Skeleton-Djsjw8XY.css.map +0 -1
  589. package/dist/C_Skeleton.js.map +0 -1
  590. package/dist/C_Skeleton2.js.map +0 -1
  591. package/dist/C_SplitPane-CgGWYsRE.css.map +0 -1
  592. package/dist/C_SplitPane-DGf6WEeR.css.map +0 -1
  593. package/dist/C_SplitPane.js.map +0 -1
  594. package/dist/C_SplitPane2.js.map +0 -1
  595. package/dist/C_Steps-27Exh7PM.css.map +0 -1
  596. package/dist/C_Steps-DU9ZsFrs.css.map +0 -1
  597. package/dist/C_Steps.js.map +0 -1
  598. package/dist/C_Steps2.js.map +0 -1
  599. package/dist/C_Table--kbQaaBv.css.map +0 -1
  600. package/dist/C_Table-D631kdXC.css.map +0 -1
  601. package/dist/C_Table.js.map +0 -1
  602. package/dist/C_Table2.js +0 -4
  603. package/dist/C_Table2.js.map +0 -1
  604. package/dist/C_TagsView-BN8vMRsY.css.map +0 -1
  605. package/dist/C_TagsView-s1dnSJAV.css.map +0 -1
  606. package/dist/C_TagsView.js.map +0 -1
  607. package/dist/C_TagsView2.js.map +0 -1
  608. package/dist/C_Theme.js.map +0 -1
  609. package/dist/C_Theme2.js.map +0 -1
  610. package/dist/C_Time-BQ9PGy8B.css.map +0 -1
  611. package/dist/C_Time-CO73krC6.css.map +0 -1
  612. package/dist/C_Time.js.map +0 -1
  613. package/dist/C_Time2.js.map +0 -1
  614. package/dist/C_Timeline-4rk0Dzgn.css.map +0 -1
  615. package/dist/C_Timeline-DdESmqwL.css.map +0 -1
  616. package/dist/C_Timeline.js.map +0 -1
  617. package/dist/C_Timeline2.js.map +0 -1
  618. package/dist/C_Transfer-B-vjvhjI.css.map +0 -1
  619. package/dist/C_Transfer-EzdHzZNv.css.map +0 -1
  620. package/dist/C_Transfer.js.map +0 -1
  621. package/dist/C_Transfer2.js.map +0 -1
  622. package/dist/C_Tree-CsXgGfhn.css.map +0 -1
  623. package/dist/C_Tree-P7eRpnOa.css.map +0 -1
  624. package/dist/C_Tree.js.map +0 -1
  625. package/dist/C_Tree2.js.map +0 -1
  626. package/dist/C_Upload-CHjiVVh7.css.map +0 -1
  627. package/dist/C_Upload-DE3OLsZD.css.map +0 -1
  628. package/dist/C_Upload.js.map +0 -1
  629. package/dist/C_Upload2.js.map +0 -1
  630. package/dist/C_VideoPlayer-CnaNOFtW.css.map +0 -1
  631. package/dist/C_VideoPlayer-cnP88zNV.css.map +0 -1
  632. package/dist/C_VideoPlayer.js.map +0 -1
  633. package/dist/C_VideoPlayer2.js.map +0 -1
  634. package/dist/C_VtableGantt-CZlJgvpC.css.map +0 -1
  635. package/dist/C_VtableGantt-DKfQkql0.css.map +0 -1
  636. package/dist/C_VtableGantt.js.map +0 -1
  637. package/dist/C_VtableGantt2.js.map +0 -1
  638. package/dist/C_WaterFall-BJ_39ext.css.map +0 -1
  639. package/dist/C_WaterFall-cYc1vntE.css.map +0 -1
  640. package/dist/C_WaterFall.js.map +0 -1
  641. package/dist/C_WaterFall2.js.map +0 -1
  642. package/dist/C_WorkFlow-BFzRGGhJ.css.map +0 -1
  643. package/dist/C_WorkFlow-DSyCOvRp.css.map +0 -1
  644. package/dist/C_WorkFlow.js.map +0 -1
  645. package/dist/C_WorkFlow2.js.map +0 -1
  646. package/dist/_shared.cjs +0 -1
  647. package/dist/_shared.d.cts +0 -2
  648. package/dist/_shared.d.ts +0 -2
  649. package/dist/_shared.js +0 -1
  650. package/dist/city.js.map +0 -1
  651. package/dist/index.cjs.map +0 -1
  652. package/dist/index.js.map +0 -1
  653. package/dist/menuAdapter.js +0 -2
  654. package/dist/menuAdapter.js.map +0 -1
  655. package/dist/resolver.cjs.map +0 -1
  656. package/dist/resolver.js.map +0 -1
  657. package/dist/storage.js.map +0 -1
  658. package/dist/useModalEdit.d.ts +0 -1308
  659. /package/dist/{chunk.js → chunk.cjs} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_QRCode2.js","names":["showBorder","mode","size","showLabel","label"],"sources":["../src/components/C_QRCode/composables/useQRCode.ts","../src/components/C_QRCode/index.vue","../src/components/C_QRCode/index.vue"],"sourcesContent":["import { ref, computed, watch } from \"vue\";\r\nimport QRCode from \"qrcode\";\r\nimport type { Ref } from \"vue\";\r\nimport type {\r\n ErrorCorrectionLevel,\r\n ExportType,\r\n LogoOptions,\r\n RenderMode,\r\n} from \"../types\";\r\n\r\ninterface UseQRCodeOptions {\r\n value: Ref<string>;\r\n size: Ref<number>;\r\n color: Ref<string>;\r\n bgColor: Ref<string>;\r\n errorCorrectionLevel: Ref<ErrorCorrectionLevel>;\r\n margin: Ref<number>;\r\n mode: Ref<RenderMode>;\r\n logo: Ref<LogoOptions | undefined>;\r\n}\r\n\r\nfunction drawLogo(\r\n canvas: HTMLCanvasElement,\r\n logo: LogoOptions,\r\n qrSize: number,\r\n): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const ctx = canvas.getContext(\"2d\");\r\n if (!ctx) return reject(new Error(\"Canvas context 不可用\"));\r\n\r\n const img = new Image();\r\n img.crossOrigin = \"anonymous\";\r\n img.onload = () => {\r\n const ratio = logo.size ?? 0.2;\r\n const logoSize = Math.floor(qrSize * ratio);\r\n const padding = logo.padding ?? 4;\r\n const borderRadius = logo.borderRadius ?? 4;\r\n\r\n const x = (canvas.width - logoSize) / 2;\r\n const y = (canvas.height - logoSize) / 2;\r\n\r\n ctx.save();\r\n const bgX = x - padding;\r\n const bgY = y - padding;\r\n const bgSize = logoSize + padding * 2;\r\n const r = borderRadius + padding;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(bgX + r, bgY);\r\n ctx.arcTo(bgX + bgSize, bgY, bgX + bgSize, bgY + bgSize, r);\r\n ctx.arcTo(bgX + bgSize, bgY + bgSize, bgX, bgY + bgSize, r);\r\n ctx.arcTo(bgX, bgY + bgSize, bgX, bgY, r);\r\n ctx.arcTo(bgX, bgY, bgX + bgSize, bgY, r);\r\n ctx.closePath();\r\n ctx.fillStyle = logo.bgColor ?? \"#ffffff\";\r\n ctx.fill();\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(x + borderRadius, y);\r\n ctx.arcTo(x + logoSize, y, x + logoSize, y + logoSize, borderRadius);\r\n ctx.arcTo(x + logoSize, y + logoSize, x, y + logoSize, borderRadius);\r\n ctx.arcTo(x, y + logoSize, x, y, borderRadius);\r\n ctx.arcTo(x, y, x + logoSize, y, borderRadius);\r\n ctx.closePath();\r\n ctx.clip();\r\n ctx.drawImage(img, x, y, logoSize, logoSize);\r\n ctx.restore();\r\n\r\n resolve();\r\n };\r\n img.onerror = () => reject(new Error(`Logo 加载失败: ${logo.src}`));\r\n img.src = logo.src;\r\n });\r\n}\r\n\r\nexport function useQRCode(\r\n canvasRef: Ref<HTMLCanvasElement | null>,\r\n options: UseQRCodeOptions,\r\n) {\r\n const svgHtml = ref(\"\");\r\n const error = ref<Error | null>(null);\r\n const loading = ref(false);\r\n\r\n const effectiveLevel = computed<ErrorCorrectionLevel>(() => {\r\n if (options.logo.value) {\r\n const level = options.errorCorrectionLevel.value;\r\n if (level === \"L\" || level === \"M\") return \"Q\";\r\n return level;\r\n }\r\n return options.errorCorrectionLevel.value;\r\n });\r\n\r\n const qrOptions = computed(() => ({\r\n width: options.size.value,\r\n margin: options.margin.value,\r\n errorCorrectionLevel: effectiveLevel.value,\r\n color: {\r\n dark: options.color.value,\r\n light: options.bgColor.value,\r\n },\r\n }));\r\n\r\n async function renderCanvas() {\r\n const canvas = canvasRef.value;\r\n if (!canvas || !options.value.value) return;\r\n await QRCode.toCanvas(canvas, options.value.value, qrOptions.value);\r\n if (options.logo.value) {\r\n await drawLogo(canvas, options.logo.value, options.size.value);\r\n }\r\n }\r\n\r\n async function renderSvg() {\r\n if (!options.value.value) {\r\n svgHtml.value = \"\";\r\n return;\r\n }\r\n const svgString = await QRCode.toString(options.value.value, {\r\n ...qrOptions.value,\r\n type: \"svg\",\r\n });\r\n svgHtml.value = svgString;\r\n }\r\n\r\n async function render() {\r\n if (!options.value.value) return;\r\n loading.value = true;\r\n error.value = null;\r\n try {\r\n if (options.mode.value === \"canvas\") {\r\n await renderCanvas();\r\n } else {\r\n await renderSvg();\r\n }\r\n } catch (e) {\r\n error.value = e instanceof Error ? e : new Error(String(e));\r\n console.error(\"二维码渲染失败:\", e);\r\n } finally {\r\n loading.value = false;\r\n }\r\n }\r\n\r\n async function toDataURL(\r\n type: ExportType = \"png\",\r\n quality = 0.92,\r\n ): Promise<string> {\r\n if (type === \"svg\") {\r\n const svgStr = await QRCode.toString(options.value.value, {\r\n ...qrOptions.value,\r\n type: \"svg\",\r\n });\r\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgStr)}`;\r\n }\r\n const tempCanvas = document.createElement(\"canvas\");\r\n await QRCode.toCanvas(tempCanvas, options.value.value, qrOptions.value);\r\n if (options.logo.value) {\r\n await drawLogo(tempCanvas, options.logo.value, options.size.value);\r\n }\r\n const mimeType = type === \"jpeg\" ? \"image/jpeg\" : \"image/png\";\r\n return tempCanvas.toDataURL(mimeType, quality);\r\n }\r\n\r\n async function download(filename = \"qrcode\", type: ExportType = \"png\") {\r\n const dataUrl = await toDataURL(type);\r\n const link = document.createElement(\"a\");\r\n link.download = `${filename}.${type}`;\r\n link.href = dataUrl;\r\n link.click();\r\n }\r\n\r\n watch(\r\n [\r\n options.value,\r\n options.size,\r\n options.color,\r\n options.bgColor,\r\n options.errorCorrectionLevel,\r\n options.margin,\r\n options.mode,\r\n options.logo,\r\n ],\r\n () => render(),\r\n { deep: true },\r\n );\r\n\r\n return { svgHtml, error, loading, render, toDataURL, download };\r\n}\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-16\n * @Description: 二维码组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-qrcode\">\n <div class=\"qrcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\n <canvas v-show=\"mode === 'canvas'\" ref=\"canvasRef\" />\n <div\n v-if=\"mode === 'svg'\"\n class=\"qrcode-svg\"\n :style=\"{ width: `${size}px`, height: `${size}px` }\"\n v-html=\"svgHtml\"\n />\n </div>\n <div v-if=\"showLabel && label\" class=\"qrcode-label\">\n {{ label }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, toRef, watch, onMounted } from \"vue\";\nimport { useQRCode } from \"./composables/useQRCode\";\nimport type {\n ErrorCorrectionLevel,\n ExportType,\n LogoOptions,\n QRCodeExpose,\n RenderMode,\n} from \"./types\";\n\ndefineOptions({ name: \"C_QRCode\" });\n\ninterface Props {\n value: string;\n size?: number;\n color?: string;\n bgColor?: string;\n errorCorrectionLevel?: ErrorCorrectionLevel;\n margin?: number;\n mode?: RenderMode;\n logo?: LogoOptions;\n showBorder?: boolean;\n label?: string;\n showLabel?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 200,\n color: \"#000000\",\n bgColor: \"#FFFFFF\",\n errorCorrectionLevel: \"M\",\n margin: 2,\n mode: \"canvas\",\n logo: undefined,\n showBorder: true,\n label: \"\",\n showLabel: false,\n});\n\nconst emit = defineEmits<{\n error: [error: Error];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\n\nconst { svgHtml, error, render, toDataURL, download } = useQRCode(canvasRef, {\n value: toRef(props, \"value\"),\n size: toRef(props, \"size\"),\n color: toRef(props, \"color\"),\n bgColor: toRef(props, \"bgColor\"),\n errorCorrectionLevel: toRef(props, \"errorCorrectionLevel\"),\n margin: toRef(props, \"margin\"),\n mode: toRef(props, \"mode\"),\n logo: toRef(props, \"logo\"),\n});\n\nwatch(error, (e) => {\n if (e) emit(\"error\", e);\n});\n\nonMounted(() => render());\n\ndefineExpose<QRCodeExpose>({\n toDataURL: (type?: ExportType, quality?: number) => toDataURL(type, quality),\n download: (filename?: string, type?: ExportType) => download(filename, type),\n refresh: () => render(),\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-16\n * @Description: 二维码组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-qrcode\">\n <div class=\"qrcode-wrapper\" :class=\"{ 'with-border': showBorder }\">\n <canvas v-show=\"mode === 'canvas'\" ref=\"canvasRef\" />\n <div\n v-if=\"mode === 'svg'\"\n class=\"qrcode-svg\"\n :style=\"{ width: `${size}px`, height: `${size}px` }\"\n v-html=\"svgHtml\"\n />\n </div>\n <div v-if=\"showLabel && label\" class=\"qrcode-label\">\n {{ label }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, toRef, watch, onMounted } from \"vue\";\nimport { useQRCode } from \"./composables/useQRCode\";\nimport type {\n ErrorCorrectionLevel,\n ExportType,\n LogoOptions,\n QRCodeExpose,\n RenderMode,\n} from \"./types\";\n\ndefineOptions({ name: \"C_QRCode\" });\n\ninterface Props {\n value: string;\n size?: number;\n color?: string;\n bgColor?: string;\n errorCorrectionLevel?: ErrorCorrectionLevel;\n margin?: number;\n mode?: RenderMode;\n logo?: LogoOptions;\n showBorder?: boolean;\n label?: string;\n showLabel?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n size: 200,\n color: \"#000000\",\n bgColor: \"#FFFFFF\",\n errorCorrectionLevel: \"M\",\n margin: 2,\n mode: \"canvas\",\n logo: undefined,\n showBorder: true,\n label: \"\",\n showLabel: false,\n});\n\nconst emit = defineEmits<{\n error: [error: Error];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\n\nconst { svgHtml, error, render, toDataURL, download } = useQRCode(canvasRef, {\n value: toRef(props, \"value\"),\n size: toRef(props, \"size\"),\n color: toRef(props, \"color\"),\n bgColor: toRef(props, \"bgColor\"),\n errorCorrectionLevel: toRef(props, \"errorCorrectionLevel\"),\n margin: toRef(props, \"margin\"),\n mode: toRef(props, \"mode\"),\n logo: toRef(props, \"logo\"),\n});\n\nwatch(error, (e) => {\n if (e) emit(\"error\", e);\n});\n\nonMounted(() => render());\n\ndefineExpose<QRCodeExpose>({\n toDataURL: (type?: ExportType, quality?: number) => toDataURL(type, quality),\n download: (filename?: string, type?: ExportType) => download(filename, type),\n refresh: () => render(),\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Signature-Bp-RBpAl.css","names":[],"sources":["../src/components/C_Signature/index.vue?vue&type=style&index=0&scoped=d7438dde&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* 电子签名组件样式 */\n.c-signature[data-v-d7438dde] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n}\n.c-signature .signature-toolbar[data-v-d7438dde] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: var(--c-bg-card, #fff);\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: var(--c-radius, 6px);\n flex-wrap: wrap;\n}\n.c-signature .signature-toolbar .toolbar-section[data-v-d7438dde] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.c-signature .signature-toolbar .toolbar-section.divider[data-v-d7438dde] {\n width: 1px;\n height: 24px;\n background: var(--c-border, #e1e4e8);\n margin: 0 4px;\n}\n.c-signature .signature-toolbar .toolbar-section .section-label[data-v-d7438dde] {\n font-size: 13px;\n color: var(--c-text-3, #999);\n font-weight: 500;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.c-signature .signature-toolbar .toolbar-section .n-color-picker[data-v-d7438dde] {\n width: 90px !important;\n flex-shrink: 0;\n}\n.c-signature .signature-canvas-wrapper[data-v-d7438dde] {\n position: relative;\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: var(--c-radius, 6px);\n overflow: hidden;\n background: var(--c-bg, #fff);\n transition: border-color 0.3s;\n}\n.c-signature .signature-canvas-wrapper[data-v-d7438dde]:hover {\n border-color: var(--c-primary, #409eff);\n}\n.c-signature .signature-canvas-wrapper.disabled[data-v-d7438dde] {\n opacity: 0.6;\n cursor: not-allowed;\n border-color: var(--c-border, #e1e4e8);\n}\n.c-signature .signature-canvas-wrapper.readonly[data-v-d7438dde] {\n cursor: default;\n}\n.c-signature .signature-canvas-wrapper .signature-canvas[data-v-d7438dde] {\n display: block;\n width: 100%;\n height: 100%;\n cursor: crosshair;\n touch-action: none;\n}\n.c-signature .signature-canvas-wrapper .signature-canvas.disabled[data-v-d7438dde], .c-signature .signature-canvas-wrapper .signature-canvas.readonly[data-v-d7438dde] {\n cursor: not-allowed;\n}\n.c-signature .signature-canvas-wrapper .canvas-placeholder[data-v-d7438dde] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: var(--c-text-4, #ccc);\n font-size: 14px;\n pointer-events: none;\n user-select: none;\n}\n.c-signature .signature-actions[data-v-d7438dde] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Signature-Cb2VW1ok.css","names":[],"sources":["../src/components/C_Signature/index.vue?vue&type=style&index=0&scoped=d7438dde&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* 电子签名组件样式 */\n.c-signature[data-v-d7438dde] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n}\n.c-signature .signature-toolbar[data-v-d7438dde] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: var(--c-bg-card, #fff);\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: var(--c-radius, 6px);\n flex-wrap: wrap;\n}\n.c-signature .signature-toolbar .toolbar-section[data-v-d7438dde] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.c-signature .signature-toolbar .toolbar-section.divider[data-v-d7438dde] {\n width: 1px;\n height: 24px;\n background: var(--c-border, #e1e4e8);\n margin: 0 4px;\n}\n.c-signature .signature-toolbar .toolbar-section .section-label[data-v-d7438dde] {\n font-size: 13px;\n color: var(--c-text-3, #999);\n font-weight: 500;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.c-signature .signature-toolbar .toolbar-section .n-color-picker[data-v-d7438dde] {\n width: 90px !important;\n flex-shrink: 0;\n}\n.c-signature .signature-canvas-wrapper[data-v-d7438dde] {\n position: relative;\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: var(--c-radius, 6px);\n overflow: hidden;\n background: var(--c-bg, #fff);\n transition: border-color 0.3s;\n}\n.c-signature .signature-canvas-wrapper[data-v-d7438dde]:hover {\n border-color: var(--c-primary, #409eff);\n}\n.c-signature .signature-canvas-wrapper.disabled[data-v-d7438dde] {\n opacity: 0.6;\n cursor: not-allowed;\n border-color: var(--c-border, #e1e4e8);\n}\n.c-signature .signature-canvas-wrapper.readonly[data-v-d7438dde] {\n cursor: default;\n}\n.c-signature .signature-canvas-wrapper .signature-canvas[data-v-d7438dde] {\n display: block;\n width: 100%;\n height: 100%;\n cursor: crosshair;\n touch-action: none;\n}\n.c-signature .signature-canvas-wrapper .signature-canvas.disabled[data-v-d7438dde], .c-signature .signature-canvas-wrapper .signature-canvas.readonly[data-v-d7438dde] {\n cursor: not-allowed;\n}\n.c-signature .signature-canvas-wrapper .canvas-placeholder[data-v-d7438dde] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: var(--c-text-4, #ccc);\n font-size: 14px;\n pointer-events: none;\n user-select: none;\n}\n.c-signature .signature-actions[data-v-d7438dde] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Signature.js","names":["showToolbar","disabled","readonly","width","height","backgroundColor"],"sources":["../src/components/C_Signature/composables/useSignatureCanvas.ts","../src/components/C_Signature/composables/useSignatureHistory.ts","../src/components/C_Signature/composables/useSignatureExport.ts","../src/components/C_Signature/data.ts","../src/components/C_Signature/index.vue","../src/components/C_Signature/index.vue"],"sourcesContent":["import type { Ref } from \"vue\";\r\nimport { ref, readonly } from \"vue\";\r\nimport type {\r\n PenConfig,\r\n PenMode,\r\n SignaturePoint,\r\n SignatureStroke,\r\n} from \"../types\";\r\n\r\ninterface UseSignatureCanvasOptions {\r\n canvasRef: Ref<HTMLCanvasElement | null>;\r\n penConfig: Ref<PenConfig>;\r\n mode: Ref<PenMode>;\r\n disabled: Ref<boolean>;\r\n onStrokeComplete: (stroke: SignatureStroke) => void;\r\n onDrawStart: () => void;\r\n onDrawing: (point: SignaturePoint) => void;\r\n}\r\n\r\nexport function useSignatureCanvas(options: UseSignatureCanvasOptions) {\r\n const {\r\n canvasRef,\r\n penConfig,\r\n mode,\r\n disabled,\r\n onStrokeComplete,\r\n onDrawStart,\r\n onDrawing,\r\n } = options;\r\n\r\n const isDrawing = ref(false);\r\n const currentStroke = ref<SignaturePoint[]>([]);\r\n let ctx: CanvasRenderingContext2D | null = null;\r\n\r\n const initCanvas = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n ctx = canvas.getContext(\"2d\", { willReadFrequently: true });\r\n if (!ctx) return;\r\n const dpr = window.devicePixelRatio || 1;\r\n const rect = canvas.getBoundingClientRect();\r\n canvas.width = rect.width * dpr;\r\n canvas.height = rect.height * dpr;\r\n canvas.style.width = `${rect.width}px`;\r\n canvas.style.height = `${rect.height}px`;\r\n ctx.scale(dpr, dpr);\r\n ctx.lineCap = \"round\";\r\n ctx.lineJoin = \"round\";\r\n };\r\n\r\n const getPointFromEvent = (e: MouseEvent | TouchEvent): SignaturePoint => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return { x: 0, y: 0 };\r\n const rect = canvas.getBoundingClientRect();\r\n let clientX: number;\r\n let clientY: number;\r\n if (\"touches\" in e && e.touches.length > 0) {\r\n ({ clientX, clientY } = e.touches[0]);\r\n } else if (\"clientX\" in e) {\r\n ({ clientX, clientY } = e);\r\n } else {\r\n return { x: 0, y: 0 };\r\n }\r\n return {\r\n x: clientX - rect.left,\r\n y: clientY - rect.top,\r\n timestamp: Date.now(),\r\n };\r\n };\r\n\r\n const drawStroke = (\r\n from: SignaturePoint,\r\n to: SignaturePoint,\r\n config: PenConfig,\r\n eraserMode = false,\r\n ) => {\r\n if (!ctx) return;\r\n ctx.save();\r\n if (eraserMode) {\r\n ctx.globalCompositeOperation = \"destination-out\";\r\n ctx.lineWidth = 20;\r\n } else {\r\n ctx.globalCompositeOperation = \"source-over\";\r\n ctx.strokeStyle = config.color;\r\n ctx.lineWidth = config.width;\r\n ctx.globalAlpha = config.opacity;\r\n }\r\n ctx.beginPath();\r\n ctx.moveTo(from.x, from.y);\r\n ctx.lineTo(to.x, to.y);\r\n ctx.stroke();\r\n ctx.restore();\r\n };\r\n\r\n const startDrawing = (e: MouseEvent | TouchEvent) => {\r\n if (disabled.value) return;\r\n e.preventDefault();\r\n isDrawing.value = true;\r\n currentStroke.value = [];\r\n const point = getPointFromEvent(e);\r\n currentStroke.value.push(point);\r\n onDrawStart();\r\n };\r\n\r\n const draw = (e: MouseEvent | TouchEvent) => {\r\n if (!isDrawing.value || disabled.value) return;\r\n e.preventDefault();\r\n const point = getPointFromEvent(e);\r\n const lastPoint = currentStroke.value[currentStroke.value.length - 1];\r\n if (lastPoint) {\r\n drawStroke(lastPoint, point, penConfig.value, mode.value === \"eraser\");\r\n }\r\n currentStroke.value.push(point);\r\n onDrawing(point);\r\n };\r\n\r\n const endDrawing = (e: MouseEvent | TouchEvent) => {\r\n if (!isDrawing.value || disabled.value) return;\r\n e.preventDefault();\r\n isDrawing.value = false;\r\n if (currentStroke.value.length > 0) {\r\n const stroke: SignatureStroke = {\r\n points: [...currentStroke.value],\r\n color: penConfig.value.color,\r\n width: penConfig.value.width,\r\n opacity: penConfig.value.opacity,\r\n mode: mode.value,\r\n };\r\n onStrokeComplete(stroke);\r\n currentStroke.value = [];\r\n }\r\n };\r\n\r\n const redrawStrokes = (strokes: SignatureStroke[]) => {\r\n if (!ctx || !canvasRef.value) return;\r\n const canvas = canvasRef.value;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n strokes.forEach((stroke) => {\r\n for (let i = 1; i < stroke.points.length; i++) {\r\n drawStroke(\r\n stroke.points[i - 1],\r\n stroke.points[i],\r\n { color: stroke.color, width: stroke.width, opacity: stroke.opacity },\r\n stroke.mode === \"eraser\",\r\n );\r\n }\r\n });\r\n };\r\n\r\n const clearCanvas = () => {\r\n if (!ctx || !canvasRef.value) return;\r\n ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height);\r\n };\r\n\r\n const bindEvents = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n canvas.addEventListener(\"mousedown\", startDrawing);\r\n canvas.addEventListener(\"mousemove\", draw);\r\n canvas.addEventListener(\"mouseup\", endDrawing);\r\n canvas.addEventListener(\"mouseleave\", endDrawing);\r\n canvas.addEventListener(\"touchstart\", startDrawing, { passive: false });\r\n canvas.addEventListener(\"touchmove\", draw, { passive: false });\r\n canvas.addEventListener(\"touchend\", endDrawing);\r\n canvas.addEventListener(\"touchcancel\", endDrawing);\r\n };\r\n\r\n const unbindEvents = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n canvas.removeEventListener(\"mousedown\", startDrawing);\r\n canvas.removeEventListener(\"mousemove\", draw);\r\n canvas.removeEventListener(\"mouseup\", endDrawing);\r\n canvas.removeEventListener(\"mouseleave\", endDrawing);\r\n canvas.removeEventListener(\"touchstart\", startDrawing);\r\n canvas.removeEventListener(\"touchmove\", draw);\r\n canvas.removeEventListener(\"touchend\", endDrawing);\r\n canvas.removeEventListener(\"touchcancel\", endDrawing);\r\n };\r\n\r\n return {\r\n isDrawing: readonly(isDrawing),\r\n initCanvas,\r\n bindEvents,\r\n unbindEvents,\r\n redrawStrokes,\r\n clearCanvas,\r\n };\r\n}\r\n","import { ref, computed, readonly } from \"vue\";\r\nimport type { SignatureStroke } from \"../types\";\r\n\r\ninterface UseSignatureHistoryOptions {\r\n maxHistory?: number;\r\n onChange?: (strokes: SignatureStroke[]) => void;\r\n}\r\n\r\nexport function useSignatureHistory(options: UseSignatureHistoryOptions = {}) {\r\n const { maxHistory = 50, onChange } = options;\r\n\r\n const strokes = ref<SignatureStroke[]>([]);\r\n const historyStack = ref<SignatureStroke[][]>([]);\r\n const historyIndex = ref(-1);\r\n\r\n const canUndo = computed(() => historyIndex.value > 0);\r\n const canRedo = computed(\r\n () => historyIndex.value < historyStack.value.length - 1,\r\n );\r\n\r\n const addStroke = (stroke: SignatureStroke) => {\r\n strokes.value.push(stroke);\r\n saveToHistory();\r\n };\r\n\r\n const saveToHistory = () => {\r\n historyStack.value = historyStack.value.slice(0, historyIndex.value + 1);\r\n historyStack.value.push([...strokes.value]);\r\n historyIndex.value++;\r\n if (historyStack.value.length > maxHistory) {\r\n historyStack.value.shift();\r\n historyIndex.value--;\r\n }\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const undo = (): boolean => {\r\n if (!canUndo.value) return false;\r\n historyIndex.value--;\r\n strokes.value = [...historyStack.value[historyIndex.value]];\r\n onChange?.(strokes.value);\r\n return true;\r\n };\r\n\r\n const redo = (): boolean => {\r\n if (!canRedo.value) return false;\r\n historyIndex.value++;\r\n strokes.value = [...historyStack.value[historyIndex.value]];\r\n onChange?.(strokes.value);\r\n return true;\r\n };\r\n\r\n const clear = () => {\r\n strokes.value = [];\r\n historyStack.value = [[]];\r\n historyIndex.value = 0;\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const loadData = (data: SignatureStroke[]) => {\r\n strokes.value = [...data];\r\n historyStack.value = [[...data]];\r\n historyIndex.value = 0;\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const isEmpty = computed(() => strokes.value.length === 0);\r\n\r\n // 初始化历史栈\r\n historyStack.value = [[]];\r\n historyIndex.value = 0;\r\n\r\n return {\r\n strokes: readonly(strokes),\r\n canUndo: readonly(canUndo),\r\n canRedo: readonly(canRedo),\r\n isEmpty: readonly(isEmpty),\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n };\r\n}\r\n","import type { Ref } from 'vue'\nimport type { ExportOptions, WatermarkConfig } from '../types'\n\ninterface UseSignatureExportOptions {\n canvasRef: Ref<HTMLCanvasElement | null>\n watermark?: Ref<Partial<WatermarkConfig>>\n}\n\n/**\n *\n */\nexport function useSignatureExport(options: UseSignatureExportOptions) {\n const { canvasRef, watermark } = options\n\n const getWatermarkPosition = (\n canvas: HTMLCanvasElement,\n textWidth: number,\n fontSize: number,\n position: string\n ): { x: number; y: number } => {\n const padding = 10\n const positions = {\n 'top-left': { x: padding, y: fontSize + padding },\n 'top-right': {\n x: canvas.width - textWidth - padding,\n y: fontSize + padding,\n },\n 'bottom-left': { x: padding, y: canvas.height - padding },\n 'bottom-right': {\n x: canvas.width - textWidth - padding,\n y: canvas.height - padding,\n },\n }\n return (\n positions[position as keyof typeof positions] || positions['bottom-right']\n )\n }\n\n const drawWatermark = (canvas: HTMLCanvasElement, text: string): void => {\n const ctx = canvas.getContext('2d')\n if (!ctx || !watermark?.value?.show) return\n const config = {\n fontSize: watermark.value.fontSize || 12,\n color: watermark.value.color || '#999999',\n position: watermark.value.position || 'bottom-right',\n }\n ctx.save()\n ctx.font = `${config.fontSize}px Arial`\n ctx.fillStyle = config.color\n ctx.textBaseline = 'bottom'\n const textWidth = ctx.measureText(text).width\n const { x, y } = getWatermarkPosition(\n canvas,\n textWidth,\n config.fontSize,\n config.position\n )\n ctx.fillText(text, x, y)\n ctx.restore()\n }\n\n const createTempCanvas = (\n sourceCanvas: HTMLCanvasElement,\n includeBackground: boolean,\n backgroundColor: string\n ) => {\n const tempCanvas = document.createElement('canvas')\n tempCanvas.width = sourceCanvas.width\n tempCanvas.height = sourceCanvas.height\n const tempCtx = tempCanvas.getContext('2d')\n if (!tempCtx) throw new Error('无法创建临时 Canvas')\n if (includeBackground) {\n tempCtx.fillStyle = backgroundColor\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height)\n }\n tempCtx.drawImage(sourceCanvas, 0, 0)\n return { canvas: tempCanvas, ctx: tempCtx }\n }\n\n const prepareExportCanvas = (\n canvas: HTMLCanvasElement,\n options: ExportOptions\n ): HTMLCanvasElement => {\n const {\n includeBackground = false,\n backgroundColor = '#FFFFFF',\n includeWatermark = false,\n } = options\n const { canvas: tempCanvas } = createTempCanvas(\n canvas,\n includeBackground,\n backgroundColor\n )\n // includeWatermark 为 true 时才叠加水印,无视 watermark.show 的状态\n // 这样「不含水印导出」即使组件配置了水印也不会叠加\n if (includeWatermark && watermark?.value?.text) {\n drawWatermark(tempCanvas, watermark.value.text)\n }\n return tempCanvas\n }\n\n const exportToBlob = (\n canvas: HTMLCanvasElement,\n quality: number\n ): Promise<Blob> => {\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n blob => (blob ? resolve(blob) : reject(new Error('导出失败'))),\n 'image/png',\n quality\n )\n })\n }\n\n const isCanvasEmpty = (canvas: HTMLCanvasElement): boolean => {\n const ctx = canvas.getContext('2d')\n if (!ctx) return true\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height)\n return !data.some(v => v !== 0)\n }\n\n const exportSignature = async (\n options: ExportOptions = {}\n ): Promise<string | Blob> => {\n const canvas = canvasRef.value\n if (!canvas) throw new Error('Canvas 未初始化')\n if (isCanvasEmpty(canvas)) throw new Error('签名为空,请先签名后再导出')\n const { format = 'png', quality = 0.92 } = options\n if (format === 'svg') {\n return 'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\"><text>SVG export placeholder</text></svg>'\n }\n const tempCanvas = prepareExportCanvas(canvas, options)\n if (format === 'blob') return exportToBlob(tempCanvas, quality)\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'\n return tempCanvas.toDataURL(mimeType, quality)\n }\n\n const download = async (\n filename = 'signature',\n options: ExportOptions = {}\n ): Promise<void> => {\n const format = options.format || 'png'\n const result = await exportSignature({ ...options, format })\n if (result instanceof Blob) {\n const url = URL.createObjectURL(result)\n const link = document.createElement('a')\n link.href = url\n link.download = `${filename}.${format}`\n link.click()\n URL.revokeObjectURL(url)\n } else if (typeof result === 'string') {\n const link = document.createElement('a')\n link.href = result\n link.download = `${filename}.${format}`\n link.click()\n }\n }\n\n const loadImage = async (imageUrl: string): Promise<void> => {\n const canvas = canvasRef.value\n if (!canvas) throw new Error('Canvas 未初始化')\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法获取 Canvas 上下文')\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\n resolve()\n }\n img.onerror = () => reject(new Error(`图片加载失败: ${imageUrl}`))\n img.src = imageUrl\n })\n }\n\n return { exportSignature, download, loadImage }\n}\n","import type { EraserConfig, PenConfig, WatermarkConfig } from \"./types\";\r\n\r\nexport const DEFAULT_PEN_CONFIG: PenConfig = {\r\n color: \"#000000\",\r\n width: 2,\r\n opacity: 1,\r\n};\r\n\r\nexport const DEFAULT_ERASER_CONFIG: EraserConfig = { size: 20 };\r\n\r\nexport const DEFAULT_WATERMARK_CONFIG: WatermarkConfig = {\r\n show: false,\r\n text: \"\",\r\n fontSize: 12,\r\n color: \"#999999\",\r\n position: \"bottom-right\",\r\n};\r\n\r\nexport const PRESET_COLORS = [\r\n \"#000000\",\r\n \"#FF0000\",\r\n \"#0000FF\",\r\n \"#00AA00\",\r\n \"#FF6600\",\r\n \"#9900FF\",\r\n];\r\n\r\nexport const PRESET_WIDTHS = [1, 2, 3, 5, 8];\r\n\r\nexport const EXPORT_FORMAT_OPTIONS = [\r\n { label: \"PNG\", value: \"png\" },\r\n { label: \"JPEG\", value: \"jpeg\" },\r\n { label: \"SVG\", value: \"svg\" },\r\n { label: \"Blob\", value: \"blob\" },\r\n] as const;\r\n\r\nexport const WATERMARK_POSITION_OPTIONS = [\r\n { label: \"左上\", value: \"top-left\" },\r\n { label: \"右上\", value: \"top-right\" },\r\n { label: \"左下\", value: \"bottom-left\" },\r\n { label: \"右下\", value: \"bottom-right\" },\r\n] as const;\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 电子签名组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-signature\">\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\n <div class=\"toolbar-section\">\n <NButtonGroup>\n <NButton\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'pen'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\n </template>\n 画笔\n </NButton>\n <NButton\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'eraser'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\n </template>\n 橡皮擦\n </NButton>\n </NButtonGroup>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">颜色</span>\n <NColorPicker\n v-model:value=\"currentPenConfig.color\"\n :show-alpha=\"false\"\n size=\"small\"\n :swatches=\"PRESET_COLORS\"\n />\n </div>\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">粗细</span>\n <NInputNumber\n v-model:value=\"currentPenConfig.width\"\n :min=\"1\"\n :max=\"20\"\n size=\"small\"\n style=\"width: 80px\"\n />\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\n <template #icon>\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 撤销\n </NButton>\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\n <template #icon>\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 重做\n </NButton>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton\n size=\"small\"\n type=\"error\"\n :disabled=\"isEmpty\"\n @click=\"handleClear\"\n >\n <template #icon>\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\n </template>\n 清空\n </NButton>\n </div>\n </div>\n\n <div\n class=\"signature-canvas-wrapper\"\n :class=\"{ disabled, readonly }\"\n :style=\"{\n width: typeof width === 'number' ? `${width}px` : width,\n height: typeof height === 'number' ? `${height}px` : height,\n backgroundColor: backgroundColor || 'transparent',\n }\"\n >\n <canvas\n ref=\"canvasRef\"\n class=\"signature-canvas\"\n :class=\"{ disabled, readonly }\"\n />\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\n 请在此处签名\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\nimport {\n DEFAULT_PEN_CONFIG,\n DEFAULT_WATERMARK_CONFIG,\n PRESET_COLORS,\n} from \"./data\";\nimport type {\n ExportOptions,\n PenConfig,\n PenMode,\n SignatureExpose,\n SignaturePoint,\n SignatureProps,\n SignatureStroke,\n WatermarkConfig,\n} from \"./types\";\n\ndefineOptions({ name: \"C_Signature\" });\n\nconst props = withDefaults(defineProps<SignatureProps>(), {\n width: \"100%\",\n height: 300,\n disabled: false,\n readonly: false,\n showToolbar: true,\n maxHistory: 50,\n});\n\nconst emit = defineEmits<{\n \"start-draw\": [];\n drawing: [point: SignaturePoint];\n \"end-draw\": [stroke: SignatureStroke];\n clear: [];\n undo: [];\n redo: [];\n change: [data: SignatureStroke[]];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\nconst currentMode = ref<PenMode>(\"pen\");\nconst currentPenConfig = reactive<PenConfig>({\n ...DEFAULT_PEN_CONFIG,\n ...props.penConfig,\n});\nconst currentWatermark = reactive<WatermarkConfig>({\n ...DEFAULT_WATERMARK_CONFIG,\n ...props.watermark,\n});\n\nconst {\n strokes,\n canUndo,\n canRedo,\n isEmpty,\n addStroke,\n undo,\n redo,\n clear,\n loadData,\n} = useSignatureHistory({\n maxHistory: props.maxHistory,\n onChange: (data) => {\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\n emit(\"change\", data as SignatureStroke[]);\n },\n});\n\nconst canvasInstance = useSignatureCanvas({\n canvasRef,\n penConfig: toRef(currentPenConfig),\n mode: currentMode,\n disabled: toRef(props, \"disabled\"),\n onStrokeComplete: (stroke: SignatureStroke) => {\n addStroke(stroke);\n emit(\"end-draw\", stroke);\n },\n onDrawStart: () => emit(\"start-draw\"),\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\n});\n\nconst exportInstance = useSignatureExport({\n canvasRef,\n watermark: toRef(currentWatermark),\n});\n\nconst handleUndo = (): boolean => {\n const result = undo();\n if (result) emit(\"undo\");\n return result;\n};\n\nconst handleRedo = (): boolean => {\n const result = redo();\n if (result) emit(\"redo\");\n return result;\n};\n\nconst handleClear = () => {\n clear();\n canvasInstance.clearCanvas();\n emit(\"clear\");\n};\n\nconst exportSignature = async (\n options?: ExportOptions,\n): Promise<string | Blob> => {\n return exportInstance.exportSignature(options);\n};\n\nconst download = async (\n filename?: string,\n options?: ExportOptions,\n): Promise<void> => {\n return exportInstance.download(filename, options);\n};\n\nconst loadImage = async (imageUrl: string): Promise<void> => {\n await exportInstance.loadImage(imageUrl);\n clear();\n};\n\nconst getSignatureData = (): SignatureStroke[] =>\n strokes.value as SignatureStroke[];\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\nconst isSignatureEmpty = (): boolean => isEmpty.value;\n\nonMounted(() => {\n canvasInstance.initCanvas();\n canvasInstance.bindEvents();\n if (props.backgroundImage) loadImage(props.backgroundImage);\n});\n\nonUnmounted(() => canvasInstance.unbindEvents());\n\ndefineExpose<SignatureExpose>({\n clear: handleClear,\n undo: handleUndo,\n redo: handleRedo,\n export: exportSignature,\n download,\n loadImage,\n getSignatureData,\n loadSignatureData,\n isEmpty: isSignatureEmpty,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 电子签名组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-signature\">\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\n <div class=\"toolbar-section\">\n <NButtonGroup>\n <NButton\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'pen'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\n </template>\n 画笔\n </NButton>\n <NButton\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'eraser'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\n </template>\n 橡皮擦\n </NButton>\n </NButtonGroup>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">颜色</span>\n <NColorPicker\n v-model:value=\"currentPenConfig.color\"\n :show-alpha=\"false\"\n size=\"small\"\n :swatches=\"PRESET_COLORS\"\n />\n </div>\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">粗细</span>\n <NInputNumber\n v-model:value=\"currentPenConfig.width\"\n :min=\"1\"\n :max=\"20\"\n size=\"small\"\n style=\"width: 80px\"\n />\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\n <template #icon>\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 撤销\n </NButton>\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\n <template #icon>\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 重做\n </NButton>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton\n size=\"small\"\n type=\"error\"\n :disabled=\"isEmpty\"\n @click=\"handleClear\"\n >\n <template #icon>\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\n </template>\n 清空\n </NButton>\n </div>\n </div>\n\n <div\n class=\"signature-canvas-wrapper\"\n :class=\"{ disabled, readonly }\"\n :style=\"{\n width: typeof width === 'number' ? `${width}px` : width,\n height: typeof height === 'number' ? `${height}px` : height,\n backgroundColor: backgroundColor || 'transparent',\n }\"\n >\n <canvas\n ref=\"canvasRef\"\n class=\"signature-canvas\"\n :class=\"{ disabled, readonly }\"\n />\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\n 请在此处签名\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\nimport {\n DEFAULT_PEN_CONFIG,\n DEFAULT_WATERMARK_CONFIG,\n PRESET_COLORS,\n} from \"./data\";\nimport type {\n ExportOptions,\n PenConfig,\n PenMode,\n SignatureExpose,\n SignaturePoint,\n SignatureProps,\n SignatureStroke,\n WatermarkConfig,\n} from \"./types\";\n\ndefineOptions({ name: \"C_Signature\" });\n\nconst props = withDefaults(defineProps<SignatureProps>(), {\n width: \"100%\",\n height: 300,\n disabled: false,\n readonly: false,\n showToolbar: true,\n maxHistory: 50,\n});\n\nconst emit = defineEmits<{\n \"start-draw\": [];\n drawing: [point: SignaturePoint];\n \"end-draw\": [stroke: SignatureStroke];\n clear: [];\n undo: [];\n redo: [];\n change: [data: SignatureStroke[]];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\nconst currentMode = ref<PenMode>(\"pen\");\nconst currentPenConfig = reactive<PenConfig>({\n ...DEFAULT_PEN_CONFIG,\n ...props.penConfig,\n});\nconst currentWatermark = reactive<WatermarkConfig>({\n ...DEFAULT_WATERMARK_CONFIG,\n ...props.watermark,\n});\n\nconst {\n strokes,\n canUndo,\n canRedo,\n isEmpty,\n addStroke,\n undo,\n redo,\n clear,\n loadData,\n} = useSignatureHistory({\n maxHistory: props.maxHistory,\n onChange: (data) => {\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\n emit(\"change\", data as SignatureStroke[]);\n },\n});\n\nconst canvasInstance = useSignatureCanvas({\n canvasRef,\n penConfig: toRef(currentPenConfig),\n mode: currentMode,\n disabled: toRef(props, \"disabled\"),\n onStrokeComplete: (stroke: SignatureStroke) => {\n addStroke(stroke);\n emit(\"end-draw\", stroke);\n },\n onDrawStart: () => emit(\"start-draw\"),\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\n});\n\nconst exportInstance = useSignatureExport({\n canvasRef,\n watermark: toRef(currentWatermark),\n});\n\nconst handleUndo = (): boolean => {\n const result = undo();\n if (result) emit(\"undo\");\n return result;\n};\n\nconst handleRedo = (): boolean => {\n const result = redo();\n if (result) emit(\"redo\");\n return result;\n};\n\nconst handleClear = () => {\n clear();\n canvasInstance.clearCanvas();\n emit(\"clear\");\n};\n\nconst exportSignature = async (\n options?: ExportOptions,\n): Promise<string | Blob> => {\n return exportInstance.exportSignature(options);\n};\n\nconst download = async (\n filename?: string,\n options?: ExportOptions,\n): Promise<void> => {\n return exportInstance.download(filename, options);\n};\n\nconst loadImage = async (imageUrl: string): Promise<void> => {\n await exportInstance.loadImage(imageUrl);\n clear();\n};\n\nconst getSignatureData = (): SignatureStroke[] =>\n strokes.value as SignatureStroke[];\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\nconst isSignatureEmpty = (): boolean => isEmpty.value;\n\nonMounted(() => {\n canvasInstance.initCanvas();\n canvasInstance.bindEvents();\n if (props.backgroundImage) loadImage(props.backgroundImage);\n});\n\nonUnmounted(() => canvasInstance.unbindEvents());\n\ndefineExpose<SignatureExpose>({\n clear: handleClear,\n undo: handleUndo,\n redo: handleRedo,\n export: exportSignature,\n download,\n loadImage,\n getSignatureData,\n loadSignatureData,\n isEmpty: isSignatureEmpty,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Signature2.js","names":["showToolbar","disabled","readonly","width","height","backgroundColor"],"sources":["../src/components/C_Signature/composables/useSignatureCanvas.ts","../src/components/C_Signature/composables/useSignatureHistory.ts","../src/components/C_Signature/composables/useSignatureExport.ts","../src/components/C_Signature/data.ts","../src/components/C_Signature/index.vue","../src/components/C_Signature/index.vue"],"sourcesContent":["import type { Ref } from \"vue\";\r\nimport { ref, readonly } from \"vue\";\r\nimport type {\r\n PenConfig,\r\n PenMode,\r\n SignaturePoint,\r\n SignatureStroke,\r\n} from \"../types\";\r\n\r\ninterface UseSignatureCanvasOptions {\r\n canvasRef: Ref<HTMLCanvasElement | null>;\r\n penConfig: Ref<PenConfig>;\r\n mode: Ref<PenMode>;\r\n disabled: Ref<boolean>;\r\n onStrokeComplete: (stroke: SignatureStroke) => void;\r\n onDrawStart: () => void;\r\n onDrawing: (point: SignaturePoint) => void;\r\n}\r\n\r\nexport function useSignatureCanvas(options: UseSignatureCanvasOptions) {\r\n const {\r\n canvasRef,\r\n penConfig,\r\n mode,\r\n disabled,\r\n onStrokeComplete,\r\n onDrawStart,\r\n onDrawing,\r\n } = options;\r\n\r\n const isDrawing = ref(false);\r\n const currentStroke = ref<SignaturePoint[]>([]);\r\n let ctx: CanvasRenderingContext2D | null = null;\r\n\r\n const initCanvas = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n ctx = canvas.getContext(\"2d\", { willReadFrequently: true });\r\n if (!ctx) return;\r\n const dpr = window.devicePixelRatio || 1;\r\n const rect = canvas.getBoundingClientRect();\r\n canvas.width = rect.width * dpr;\r\n canvas.height = rect.height * dpr;\r\n canvas.style.width = `${rect.width}px`;\r\n canvas.style.height = `${rect.height}px`;\r\n ctx.scale(dpr, dpr);\r\n ctx.lineCap = \"round\";\r\n ctx.lineJoin = \"round\";\r\n };\r\n\r\n const getPointFromEvent = (e: MouseEvent | TouchEvent): SignaturePoint => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return { x: 0, y: 0 };\r\n const rect = canvas.getBoundingClientRect();\r\n let clientX: number;\r\n let clientY: number;\r\n if (\"touches\" in e && e.touches.length > 0) {\r\n ({ clientX, clientY } = e.touches[0]);\r\n } else if (\"clientX\" in e) {\r\n ({ clientX, clientY } = e);\r\n } else {\r\n return { x: 0, y: 0 };\r\n }\r\n return {\r\n x: clientX - rect.left,\r\n y: clientY - rect.top,\r\n timestamp: Date.now(),\r\n };\r\n };\r\n\r\n const drawStroke = (\r\n from: SignaturePoint,\r\n to: SignaturePoint,\r\n config: PenConfig,\r\n eraserMode = false,\r\n ) => {\r\n if (!ctx) return;\r\n ctx.save();\r\n if (eraserMode) {\r\n ctx.globalCompositeOperation = \"destination-out\";\r\n ctx.lineWidth = 20;\r\n } else {\r\n ctx.globalCompositeOperation = \"source-over\";\r\n ctx.strokeStyle = config.color;\r\n ctx.lineWidth = config.width;\r\n ctx.globalAlpha = config.opacity;\r\n }\r\n ctx.beginPath();\r\n ctx.moveTo(from.x, from.y);\r\n ctx.lineTo(to.x, to.y);\r\n ctx.stroke();\r\n ctx.restore();\r\n };\r\n\r\n const startDrawing = (e: MouseEvent | TouchEvent) => {\r\n if (disabled.value) return;\r\n e.preventDefault();\r\n isDrawing.value = true;\r\n currentStroke.value = [];\r\n const point = getPointFromEvent(e);\r\n currentStroke.value.push(point);\r\n onDrawStart();\r\n };\r\n\r\n const draw = (e: MouseEvent | TouchEvent) => {\r\n if (!isDrawing.value || disabled.value) return;\r\n e.preventDefault();\r\n const point = getPointFromEvent(e);\r\n const lastPoint = currentStroke.value[currentStroke.value.length - 1];\r\n if (lastPoint) {\r\n drawStroke(lastPoint, point, penConfig.value, mode.value === \"eraser\");\r\n }\r\n currentStroke.value.push(point);\r\n onDrawing(point);\r\n };\r\n\r\n const endDrawing = (e: MouseEvent | TouchEvent) => {\r\n if (!isDrawing.value || disabled.value) return;\r\n e.preventDefault();\r\n isDrawing.value = false;\r\n if (currentStroke.value.length > 0) {\r\n const stroke: SignatureStroke = {\r\n points: [...currentStroke.value],\r\n color: penConfig.value.color,\r\n width: penConfig.value.width,\r\n opacity: penConfig.value.opacity,\r\n mode: mode.value,\r\n };\r\n onStrokeComplete(stroke);\r\n currentStroke.value = [];\r\n }\r\n };\r\n\r\n const redrawStrokes = (strokes: SignatureStroke[]) => {\r\n if (!ctx || !canvasRef.value) return;\r\n const canvas = canvasRef.value;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n strokes.forEach((stroke) => {\r\n for (let i = 1; i < stroke.points.length; i++) {\r\n drawStroke(\r\n stroke.points[i - 1],\r\n stroke.points[i],\r\n { color: stroke.color, width: stroke.width, opacity: stroke.opacity },\r\n stroke.mode === \"eraser\",\r\n );\r\n }\r\n });\r\n };\r\n\r\n const clearCanvas = () => {\r\n if (!ctx || !canvasRef.value) return;\r\n ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height);\r\n };\r\n\r\n const bindEvents = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n canvas.addEventListener(\"mousedown\", startDrawing);\r\n canvas.addEventListener(\"mousemove\", draw);\r\n canvas.addEventListener(\"mouseup\", endDrawing);\r\n canvas.addEventListener(\"mouseleave\", endDrawing);\r\n canvas.addEventListener(\"touchstart\", startDrawing, { passive: false });\r\n canvas.addEventListener(\"touchmove\", draw, { passive: false });\r\n canvas.addEventListener(\"touchend\", endDrawing);\r\n canvas.addEventListener(\"touchcancel\", endDrawing);\r\n };\r\n\r\n const unbindEvents = () => {\r\n const canvas = canvasRef.value;\r\n if (!canvas) return;\r\n canvas.removeEventListener(\"mousedown\", startDrawing);\r\n canvas.removeEventListener(\"mousemove\", draw);\r\n canvas.removeEventListener(\"mouseup\", endDrawing);\r\n canvas.removeEventListener(\"mouseleave\", endDrawing);\r\n canvas.removeEventListener(\"touchstart\", startDrawing);\r\n canvas.removeEventListener(\"touchmove\", draw);\r\n canvas.removeEventListener(\"touchend\", endDrawing);\r\n canvas.removeEventListener(\"touchcancel\", endDrawing);\r\n };\r\n\r\n return {\r\n isDrawing: readonly(isDrawing),\r\n initCanvas,\r\n bindEvents,\r\n unbindEvents,\r\n redrawStrokes,\r\n clearCanvas,\r\n };\r\n}\r\n","import { ref, computed, readonly } from \"vue\";\r\nimport type { SignatureStroke } from \"../types\";\r\n\r\ninterface UseSignatureHistoryOptions {\r\n maxHistory?: number;\r\n onChange?: (strokes: SignatureStroke[]) => void;\r\n}\r\n\r\nexport function useSignatureHistory(options: UseSignatureHistoryOptions = {}) {\r\n const { maxHistory = 50, onChange } = options;\r\n\r\n const strokes = ref<SignatureStroke[]>([]);\r\n const historyStack = ref<SignatureStroke[][]>([]);\r\n const historyIndex = ref(-1);\r\n\r\n const canUndo = computed(() => historyIndex.value > 0);\r\n const canRedo = computed(\r\n () => historyIndex.value < historyStack.value.length - 1,\r\n );\r\n\r\n const addStroke = (stroke: SignatureStroke) => {\r\n strokes.value.push(stroke);\r\n saveToHistory();\r\n };\r\n\r\n const saveToHistory = () => {\r\n historyStack.value = historyStack.value.slice(0, historyIndex.value + 1);\r\n historyStack.value.push([...strokes.value]);\r\n historyIndex.value++;\r\n if (historyStack.value.length > maxHistory) {\r\n historyStack.value.shift();\r\n historyIndex.value--;\r\n }\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const undo = (): boolean => {\r\n if (!canUndo.value) return false;\r\n historyIndex.value--;\r\n strokes.value = [...historyStack.value[historyIndex.value]];\r\n onChange?.(strokes.value);\r\n return true;\r\n };\r\n\r\n const redo = (): boolean => {\r\n if (!canRedo.value) return false;\r\n historyIndex.value++;\r\n strokes.value = [...historyStack.value[historyIndex.value]];\r\n onChange?.(strokes.value);\r\n return true;\r\n };\r\n\r\n const clear = () => {\r\n strokes.value = [];\r\n historyStack.value = [[]];\r\n historyIndex.value = 0;\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const loadData = (data: SignatureStroke[]) => {\r\n strokes.value = [...data];\r\n historyStack.value = [[...data]];\r\n historyIndex.value = 0;\r\n onChange?.(strokes.value);\r\n };\r\n\r\n const isEmpty = computed(() => strokes.value.length === 0);\r\n\r\n // 初始化历史栈\r\n historyStack.value = [[]];\r\n historyIndex.value = 0;\r\n\r\n return {\r\n strokes: readonly(strokes),\r\n canUndo: readonly(canUndo),\r\n canRedo: readonly(canRedo),\r\n isEmpty: readonly(isEmpty),\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n };\r\n}\r\n","import type { Ref } from 'vue'\nimport type { ExportOptions, WatermarkConfig } from '../types'\n\ninterface UseSignatureExportOptions {\n canvasRef: Ref<HTMLCanvasElement | null>\n watermark?: Ref<Partial<WatermarkConfig>>\n}\n\n/**\n *\n */\nexport function useSignatureExport(options: UseSignatureExportOptions) {\n const { canvasRef, watermark } = options\n\n const getWatermarkPosition = (\n canvas: HTMLCanvasElement,\n textWidth: number,\n fontSize: number,\n position: string\n ): { x: number; y: number } => {\n const padding = 10\n const positions = {\n 'top-left': { x: padding, y: fontSize + padding },\n 'top-right': {\n x: canvas.width - textWidth - padding,\n y: fontSize + padding,\n },\n 'bottom-left': { x: padding, y: canvas.height - padding },\n 'bottom-right': {\n x: canvas.width - textWidth - padding,\n y: canvas.height - padding,\n },\n }\n return (\n positions[position as keyof typeof positions] || positions['bottom-right']\n )\n }\n\n const drawWatermark = (canvas: HTMLCanvasElement, text: string): void => {\n const ctx = canvas.getContext('2d')\n if (!ctx || !watermark?.value?.show) return\n const config = {\n fontSize: watermark.value.fontSize || 12,\n color: watermark.value.color || '#999999',\n position: watermark.value.position || 'bottom-right',\n }\n ctx.save()\n ctx.font = `${config.fontSize}px Arial`\n ctx.fillStyle = config.color\n ctx.textBaseline = 'bottom'\n const textWidth = ctx.measureText(text).width\n const { x, y } = getWatermarkPosition(\n canvas,\n textWidth,\n config.fontSize,\n config.position\n )\n ctx.fillText(text, x, y)\n ctx.restore()\n }\n\n const createTempCanvas = (\n sourceCanvas: HTMLCanvasElement,\n includeBackground: boolean,\n backgroundColor: string\n ) => {\n const tempCanvas = document.createElement('canvas')\n tempCanvas.width = sourceCanvas.width\n tempCanvas.height = sourceCanvas.height\n const tempCtx = tempCanvas.getContext('2d')\n if (!tempCtx) throw new Error('无法创建临时 Canvas')\n if (includeBackground) {\n tempCtx.fillStyle = backgroundColor\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height)\n }\n tempCtx.drawImage(sourceCanvas, 0, 0)\n return { canvas: tempCanvas, ctx: tempCtx }\n }\n\n const prepareExportCanvas = (\n canvas: HTMLCanvasElement,\n options: ExportOptions\n ): HTMLCanvasElement => {\n const {\n includeBackground = false,\n backgroundColor = '#FFFFFF',\n includeWatermark = false,\n } = options\n const { canvas: tempCanvas } = createTempCanvas(\n canvas,\n includeBackground,\n backgroundColor\n )\n // includeWatermark 为 true 时才叠加水印,无视 watermark.show 的状态\n // 这样「不含水印导出」即使组件配置了水印也不会叠加\n if (includeWatermark && watermark?.value?.text) {\n drawWatermark(tempCanvas, watermark.value.text)\n }\n return tempCanvas\n }\n\n const exportToBlob = (\n canvas: HTMLCanvasElement,\n quality: number\n ): Promise<Blob> => {\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob(\n blob => (blob ? resolve(blob) : reject(new Error('导出失败'))),\n 'image/png',\n quality\n )\n })\n }\n\n const isCanvasEmpty = (canvas: HTMLCanvasElement): boolean => {\n const ctx = canvas.getContext('2d')\n if (!ctx) return true\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height)\n return !data.some(v => v !== 0)\n }\n\n const exportSignature = async (\n options: ExportOptions = {}\n ): Promise<string | Blob> => {\n const canvas = canvasRef.value\n if (!canvas) throw new Error('Canvas 未初始化')\n if (isCanvasEmpty(canvas)) throw new Error('签名为空,请先签名后再导出')\n const { format = 'png', quality = 0.92 } = options\n if (format === 'svg') {\n return 'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\"><text>SVG export placeholder</text></svg>'\n }\n const tempCanvas = prepareExportCanvas(canvas, options)\n if (format === 'blob') return exportToBlob(tempCanvas, quality)\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'\n return tempCanvas.toDataURL(mimeType, quality)\n }\n\n const download = async (\n filename = 'signature',\n options: ExportOptions = {}\n ): Promise<void> => {\n const format = options.format || 'png'\n const result = await exportSignature({ ...options, format })\n if (result instanceof Blob) {\n const url = URL.createObjectURL(result)\n const link = document.createElement('a')\n link.href = url\n link.download = `${filename}.${format}`\n link.click()\n URL.revokeObjectURL(url)\n } else if (typeof result === 'string') {\n const link = document.createElement('a')\n link.href = result\n link.download = `${filename}.${format}`\n link.click()\n }\n }\n\n const loadImage = async (imageUrl: string): Promise<void> => {\n const canvas = canvasRef.value\n if (!canvas) throw new Error('Canvas 未初始化')\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('无法获取 Canvas 上下文')\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\n resolve()\n }\n img.onerror = () => reject(new Error(`图片加载失败: ${imageUrl}`))\n img.src = imageUrl\n })\n }\n\n return { exportSignature, download, loadImage }\n}\n","import type { EraserConfig, PenConfig, WatermarkConfig } from \"./types\";\r\n\r\nexport const DEFAULT_PEN_CONFIG: PenConfig = {\r\n color: \"#000000\",\r\n width: 2,\r\n opacity: 1,\r\n};\r\n\r\nexport const DEFAULT_ERASER_CONFIG: EraserConfig = { size: 20 };\r\n\r\nexport const DEFAULT_WATERMARK_CONFIG: WatermarkConfig = {\r\n show: false,\r\n text: \"\",\r\n fontSize: 12,\r\n color: \"#999999\",\r\n position: \"bottom-right\",\r\n};\r\n\r\nexport const PRESET_COLORS = [\r\n \"#000000\",\r\n \"#FF0000\",\r\n \"#0000FF\",\r\n \"#00AA00\",\r\n \"#FF6600\",\r\n \"#9900FF\",\r\n];\r\n\r\nexport const PRESET_WIDTHS = [1, 2, 3, 5, 8];\r\n\r\nexport const EXPORT_FORMAT_OPTIONS = [\r\n { label: \"PNG\", value: \"png\" },\r\n { label: \"JPEG\", value: \"jpeg\" },\r\n { label: \"SVG\", value: \"svg\" },\r\n { label: \"Blob\", value: \"blob\" },\r\n] as const;\r\n\r\nexport const WATERMARK_POSITION_OPTIONS = [\r\n { label: \"左上\", value: \"top-left\" },\r\n { label: \"右上\", value: \"top-right\" },\r\n { label: \"左下\", value: \"bottom-left\" },\r\n { label: \"右下\", value: \"bottom-right\" },\r\n] as const;\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 电子签名组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-signature\">\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\n <div class=\"toolbar-section\">\n <NButtonGroup>\n <NButton\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'pen'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\n </template>\n 画笔\n </NButton>\n <NButton\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'eraser'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\n </template>\n 橡皮擦\n </NButton>\n </NButtonGroup>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">颜色</span>\n <NColorPicker\n v-model:value=\"currentPenConfig.color\"\n :show-alpha=\"false\"\n size=\"small\"\n :swatches=\"PRESET_COLORS\"\n />\n </div>\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">粗细</span>\n <NInputNumber\n v-model:value=\"currentPenConfig.width\"\n :min=\"1\"\n :max=\"20\"\n size=\"small\"\n style=\"width: 80px\"\n />\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\n <template #icon>\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 撤销\n </NButton>\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\n <template #icon>\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 重做\n </NButton>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton\n size=\"small\"\n type=\"error\"\n :disabled=\"isEmpty\"\n @click=\"handleClear\"\n >\n <template #icon>\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\n </template>\n 清空\n </NButton>\n </div>\n </div>\n\n <div\n class=\"signature-canvas-wrapper\"\n :class=\"{ disabled, readonly }\"\n :style=\"{\n width: typeof width === 'number' ? `${width}px` : width,\n height: typeof height === 'number' ? `${height}px` : height,\n backgroundColor: backgroundColor || 'transparent',\n }\"\n >\n <canvas\n ref=\"canvasRef\"\n class=\"signature-canvas\"\n :class=\"{ disabled, readonly }\"\n />\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\n 请在此处签名\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\nimport {\n DEFAULT_PEN_CONFIG,\n DEFAULT_WATERMARK_CONFIG,\n PRESET_COLORS,\n} from \"./data\";\nimport type {\n ExportOptions,\n PenConfig,\n PenMode,\n SignatureExpose,\n SignaturePoint,\n SignatureProps,\n SignatureStroke,\n WatermarkConfig,\n} from \"./types\";\n\ndefineOptions({ name: \"C_Signature\" });\n\nconst props = withDefaults(defineProps<SignatureProps>(), {\n width: \"100%\",\n height: 300,\n disabled: false,\n readonly: false,\n showToolbar: true,\n maxHistory: 50,\n});\n\nconst emit = defineEmits<{\n \"start-draw\": [];\n drawing: [point: SignaturePoint];\n \"end-draw\": [stroke: SignatureStroke];\n clear: [];\n undo: [];\n redo: [];\n change: [data: SignatureStroke[]];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\nconst currentMode = ref<PenMode>(\"pen\");\nconst currentPenConfig = reactive<PenConfig>({\n ...DEFAULT_PEN_CONFIG,\n ...props.penConfig,\n});\nconst currentWatermark = reactive<WatermarkConfig>({\n ...DEFAULT_WATERMARK_CONFIG,\n ...props.watermark,\n});\n\nconst {\n strokes,\n canUndo,\n canRedo,\n isEmpty,\n addStroke,\n undo,\n redo,\n clear,\n loadData,\n} = useSignatureHistory({\n maxHistory: props.maxHistory,\n onChange: (data) => {\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\n emit(\"change\", data as SignatureStroke[]);\n },\n});\n\nconst canvasInstance = useSignatureCanvas({\n canvasRef,\n penConfig: toRef(currentPenConfig),\n mode: currentMode,\n disabled: toRef(props, \"disabled\"),\n onStrokeComplete: (stroke: SignatureStroke) => {\n addStroke(stroke);\n emit(\"end-draw\", stroke);\n },\n onDrawStart: () => emit(\"start-draw\"),\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\n});\n\nconst exportInstance = useSignatureExport({\n canvasRef,\n watermark: toRef(currentWatermark),\n});\n\nconst handleUndo = (): boolean => {\n const result = undo();\n if (result) emit(\"undo\");\n return result;\n};\n\nconst handleRedo = (): boolean => {\n const result = redo();\n if (result) emit(\"redo\");\n return result;\n};\n\nconst handleClear = () => {\n clear();\n canvasInstance.clearCanvas();\n emit(\"clear\");\n};\n\nconst exportSignature = async (\n options?: ExportOptions,\n): Promise<string | Blob> => {\n return exportInstance.exportSignature(options);\n};\n\nconst download = async (\n filename?: string,\n options?: ExportOptions,\n): Promise<void> => {\n return exportInstance.download(filename, options);\n};\n\nconst loadImage = async (imageUrl: string): Promise<void> => {\n await exportInstance.loadImage(imageUrl);\n clear();\n};\n\nconst getSignatureData = (): SignatureStroke[] =>\n strokes.value as SignatureStroke[];\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\nconst isSignatureEmpty = (): boolean => isEmpty.value;\n\nonMounted(() => {\n canvasInstance.initCanvas();\n canvasInstance.bindEvents();\n if (props.backgroundImage) loadImage(props.backgroundImage);\n});\n\nonUnmounted(() => canvasInstance.unbindEvents());\n\ndefineExpose<SignatureExpose>({\n clear: handleClear,\n undo: handleUndo,\n redo: handleRedo,\n export: exportSignature,\n download,\n loadImage,\n getSignatureData,\n loadSignatureData,\n isEmpty: isSignatureEmpty,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-25\n * @Description: 电子签名组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n-->\n<template>\n <div class=\"c-signature\">\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\n <div class=\"toolbar-section\">\n <NButtonGroup>\n <NButton\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'pen'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\n </template>\n 画笔\n </NButton>\n <NButton\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\n size=\"small\"\n @click=\"currentMode = 'eraser'\"\n >\n <template #icon>\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\n </template>\n 橡皮擦\n </NButton>\n </NButtonGroup>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">颜色</span>\n <NColorPicker\n v-model:value=\"currentPenConfig.color\"\n :show-alpha=\"false\"\n size=\"small\"\n :swatches=\"PRESET_COLORS\"\n />\n </div>\n\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\n <span class=\"section-label\">粗细</span>\n <NInputNumber\n v-model:value=\"currentPenConfig.width\"\n :min=\"1\"\n :max=\"20\"\n size=\"small\"\n style=\"width: 80px\"\n />\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\n <template #icon>\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 撤销\n </NButton>\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\n <template #icon>\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\n </template>\n 重做\n </NButton>\n </div>\n\n <div class=\"toolbar-section divider\" />\n\n <div class=\"toolbar-section\">\n <NButton\n size=\"small\"\n type=\"error\"\n :disabled=\"isEmpty\"\n @click=\"handleClear\"\n >\n <template #icon>\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\n </template>\n 清空\n </NButton>\n </div>\n </div>\n\n <div\n class=\"signature-canvas-wrapper\"\n :class=\"{ disabled, readonly }\"\n :style=\"{\n width: typeof width === 'number' ? `${width}px` : width,\n height: typeof height === 'number' ? `${height}px` : height,\n backgroundColor: backgroundColor || 'transparent',\n }\"\n >\n <canvas\n ref=\"canvasRef\"\n class=\"signature-canvas\"\n :class=\"{ disabled, readonly }\"\n />\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\n 请在此处签名\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\nimport {\n DEFAULT_PEN_CONFIG,\n DEFAULT_WATERMARK_CONFIG,\n PRESET_COLORS,\n} from \"./data\";\nimport type {\n ExportOptions,\n PenConfig,\n PenMode,\n SignatureExpose,\n SignaturePoint,\n SignatureProps,\n SignatureStroke,\n WatermarkConfig,\n} from \"./types\";\n\ndefineOptions({ name: \"C_Signature\" });\n\nconst props = withDefaults(defineProps<SignatureProps>(), {\n width: \"100%\",\n height: 300,\n disabled: false,\n readonly: false,\n showToolbar: true,\n maxHistory: 50,\n});\n\nconst emit = defineEmits<{\n \"start-draw\": [];\n drawing: [point: SignaturePoint];\n \"end-draw\": [stroke: SignatureStroke];\n clear: [];\n undo: [];\n redo: [];\n change: [data: SignatureStroke[]];\n}>();\n\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\nconst currentMode = ref<PenMode>(\"pen\");\nconst currentPenConfig = reactive<PenConfig>({\n ...DEFAULT_PEN_CONFIG,\n ...props.penConfig,\n});\nconst currentWatermark = reactive<WatermarkConfig>({\n ...DEFAULT_WATERMARK_CONFIG,\n ...props.watermark,\n});\n\nconst {\n strokes,\n canUndo,\n canRedo,\n isEmpty,\n addStroke,\n undo,\n redo,\n clear,\n loadData,\n} = useSignatureHistory({\n maxHistory: props.maxHistory,\n onChange: (data) => {\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\n emit(\"change\", data as SignatureStroke[]);\n },\n});\n\nconst canvasInstance = useSignatureCanvas({\n canvasRef,\n penConfig: toRef(currentPenConfig),\n mode: currentMode,\n disabled: toRef(props, \"disabled\"),\n onStrokeComplete: (stroke: SignatureStroke) => {\n addStroke(stroke);\n emit(\"end-draw\", stroke);\n },\n onDrawStart: () => emit(\"start-draw\"),\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\n});\n\nconst exportInstance = useSignatureExport({\n canvasRef,\n watermark: toRef(currentWatermark),\n});\n\nconst handleUndo = (): boolean => {\n const result = undo();\n if (result) emit(\"undo\");\n return result;\n};\n\nconst handleRedo = (): boolean => {\n const result = redo();\n if (result) emit(\"redo\");\n return result;\n};\n\nconst handleClear = () => {\n clear();\n canvasInstance.clearCanvas();\n emit(\"clear\");\n};\n\nconst exportSignature = async (\n options?: ExportOptions,\n): Promise<string | Blob> => {\n return exportInstance.exportSignature(options);\n};\n\nconst download = async (\n filename?: string,\n options?: ExportOptions,\n): Promise<void> => {\n return exportInstance.download(filename, options);\n};\n\nconst loadImage = async (imageUrl: string): Promise<void> => {\n await exportInstance.loadImage(imageUrl);\n clear();\n};\n\nconst getSignatureData = (): SignatureStroke[] =>\n strokes.value as SignatureStroke[];\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\nconst isSignatureEmpty = (): boolean => isEmpty.value;\n\nonMounted(() => {\n canvasInstance.initCanvas();\n canvasInstance.bindEvents();\n if (props.backgroundImage) loadImage(props.backgroundImage);\n});\n\nonUnmounted(() => canvasInstance.unbindEvents());\n\ndefineExpose<SignatureExpose>({\n clear: handleClear,\n undo: handleUndo,\n redo: handleRedo,\n export: exportSignature,\n download,\n loadImage,\n getSignatureData,\n loadSignatureData,\n isEmpty: isSignatureEmpty,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Skeleton-BNPbaut7.css","names":[],"sources":["../src/components/C_Skeleton/index.vue?vue&type=style&index=0&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Skeleton 骨架屏组件样式 */\n.c-skeleton {\n --c-skeleton-bg: #e5e7eb;\n --c-skeleton-wave-bg: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.4),\n transparent\n );\n --c-skeleton-radius: 4px;\n --c-skeleton-circle-size: 40px;\n --c-skeleton-circle-sm: 32px;\n --c-skeleton-circle-lg: 56px;\n --c-skeleton-line-height: 16px;\n --c-skeleton-line-sm-height: 12px;\n --c-skeleton-line-mini-height: 8px;\n --c-skeleton-gap: 12px;\n --c-skeleton-card-cover-height: 160px;\n --c-skeleton-image-height: 200px;\n width: 100%;\n}\n\n/* ─── 基础骨架块 ─── */\n.c-skeleton__item {\n background-color: var(--c-skeleton-bg);\n border-radius: var(--c-skeleton-radius);\n position: relative;\n overflow: hidden;\n}\n\n/* ─── 动画:脉冲 ─── */\n.c-skeleton--pulse .c-skeleton__item {\n animation: skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes skeleton-pulse {\n0%, 100% {\n opacity: 1;\n}\n50% {\n opacity: 0.4;\n}\n}\n/* ─── 动画:波浪 ─── */\n.c-skeleton--wave .c-skeleton__item::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--c-skeleton-wave-bg);\n animation: skeleton-wave 1.6s linear infinite;\n}\n@keyframes skeleton-wave {\n0% {\n transform: translateX(-100%);\n}\n100% {\n transform: translateX(100%);\n}\n}\n/* ─── 无动画 ─── */\n.c-skeleton--none .c-skeleton__item {\n animation: none;\n}\n.c-skeleton--none .c-skeleton__item::after {\n display: none;\n}\n\n/* ─── 文本行 ─── */\n.c-skeleton__text {\n margin-bottom: 8px;\n}\n.c-skeleton__line {\n height: var(--c-skeleton-line-height);\n width: 100%;\n}\n.c-skeleton__line--sm {\n height: var(--c-skeleton-line-sm-height);\n margin-top: 6px;\n}\n.c-skeleton__line--mini {\n height: var(--c-skeleton-line-mini-height);\n}\n.c-skeleton__line--label {\n height: var(--c-skeleton-line-sm-height);\n margin-bottom: 8px;\n}\n.c-skeleton__line--input {\n height: 34px;\n border-radius: 6px;\n}\n.c-skeleton__line--btn {\n height: 32px;\n border-radius: 6px;\n}\n\n/* ─── 圆形(头像) ─── */\n.c-skeleton__circle {\n width: var(--c-skeleton-circle-size);\n height: var(--c-skeleton-circle-size);\n border-radius: 50%;\n flex-shrink: 0;\n}\n.c-skeleton__circle--sm {\n width: var(--c-skeleton-circle-sm);\n height: var(--c-skeleton-circle-sm);\n}\n.c-skeleton__circle--lg {\n width: var(--c-skeleton-circle-lg);\n height: var(--c-skeleton-circle-lg);\n}\n\n/* ─── Avatar 预设 ─── */\n.c-skeleton__avatar-group {\n display: flex;\n align-items: center;\n gap: var(--c-skeleton-gap);\n}\n.c-skeleton__avatar-text {\n flex: 1;\n}\n\n/* ─── Image 预设 ─── */\n.c-skeleton__image {\n width: 100%;\n height: var(--c-skeleton-image-height);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__image-icon {\n color: var(--c-skeleton-bg);\n opacity: 0.6;\n filter: brightness(0.8);\n}\n\n/* ─── Card 预设 ─── */\n.c-skeleton__card {\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__card-cover {\n width: 100%;\n height: var(--c-skeleton-card-cover-height);\n border-radius: 0;\n}\n.c-skeleton__card-body {\n padding: 16px;\n}\n.c-skeleton__card-desc {\n margin-top: 8px;\n}\n.c-skeleton__card-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid var(--c-skeleton-bg);\n}\n\n/* ─── Table 预设 ─── */\n.c-skeleton__table {\n width: 100%;\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n}\n.c-skeleton__table-header {\n display: flex;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--c-skeleton-bg) 30%, transparent);\n border-bottom: 1px solid var(--c-skeleton-bg);\n}\n.c-skeleton__table-row {\n display: flex;\n padding: 12px 16px;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__table-row:last-child {\n border-bottom: none;\n}\n.c-skeleton__table-cell {\n flex: 1;\n padding: 0 8px;\n}\n.c-skeleton__table-cell--action {\n flex: 0 0 120px;\n}\n.c-skeleton__action-btns {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* ─── Form 预设 ─── */\n.c-skeleton__form {\n display: grid;\n grid-template-columns: repeat(var(--form-cols, 2), 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__form-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__form-actions {\n grid-column: 1/-1;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 16px;\n}\n\n/* ─── List 预设 ─── */\n.c-skeleton__list-item {\n display: flex;\n align-items: flex-start;\n gap: var(--c-skeleton-gap);\n padding: 12px 0;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__list-item:last-child {\n border-bottom: none;\n}\n.c-skeleton__list-content {\n flex: 1;\n}\n\n/* ─── Detail 预设 ─── */\n.c-skeleton__detail-header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n}\n.c-skeleton__detail-title {\n flex: 1;\n}\n.c-skeleton__detail-body {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__detail-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__detail-value {\n margin-top: 4px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Skeleton-Djsjw8XY.css","names":[],"sources":["../src/components/C_Skeleton/index.vue?vue&type=style&index=0&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Skeleton 骨架屏组件样式 */\n.c-skeleton {\n --c-skeleton-bg: #e5e7eb;\n --c-skeleton-wave-bg: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.4),\n transparent\n );\n --c-skeleton-radius: 4px;\n --c-skeleton-circle-size: 40px;\n --c-skeleton-circle-sm: 32px;\n --c-skeleton-circle-lg: 56px;\n --c-skeleton-line-height: 16px;\n --c-skeleton-line-sm-height: 12px;\n --c-skeleton-line-mini-height: 8px;\n --c-skeleton-gap: 12px;\n --c-skeleton-card-cover-height: 160px;\n --c-skeleton-image-height: 200px;\n width: 100%;\n}\n\n/* ─── 基础骨架块 ─── */\n.c-skeleton__item {\n background-color: var(--c-skeleton-bg);\n border-radius: var(--c-skeleton-radius);\n position: relative;\n overflow: hidden;\n}\n\n/* ─── 动画:脉冲 ─── */\n.c-skeleton--pulse .c-skeleton__item {\n animation: skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes skeleton-pulse {\n0%, 100% {\n opacity: 1;\n}\n50% {\n opacity: 0.4;\n}\n}\n/* ─── 动画:波浪 ─── */\n.c-skeleton--wave .c-skeleton__item::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--c-skeleton-wave-bg);\n animation: skeleton-wave 1.6s linear infinite;\n}\n@keyframes skeleton-wave {\n0% {\n transform: translateX(-100%);\n}\n100% {\n transform: translateX(100%);\n}\n}\n/* ─── 无动画 ─── */\n.c-skeleton--none .c-skeleton__item {\n animation: none;\n}\n.c-skeleton--none .c-skeleton__item::after {\n display: none;\n}\n\n/* ─── 文本行 ─── */\n.c-skeleton__text {\n margin-bottom: 8px;\n}\n.c-skeleton__line {\n height: var(--c-skeleton-line-height);\n width: 100%;\n}\n.c-skeleton__line--sm {\n height: var(--c-skeleton-line-sm-height);\n margin-top: 6px;\n}\n.c-skeleton__line--mini {\n height: var(--c-skeleton-line-mini-height);\n}\n.c-skeleton__line--label {\n height: var(--c-skeleton-line-sm-height);\n margin-bottom: 8px;\n}\n.c-skeleton__line--input {\n height: 34px;\n border-radius: 6px;\n}\n.c-skeleton__line--btn {\n height: 32px;\n border-radius: 6px;\n}\n\n/* ─── 圆形(头像) ─── */\n.c-skeleton__circle {\n width: var(--c-skeleton-circle-size);\n height: var(--c-skeleton-circle-size);\n border-radius: 50%;\n flex-shrink: 0;\n}\n.c-skeleton__circle--sm {\n width: var(--c-skeleton-circle-sm);\n height: var(--c-skeleton-circle-sm);\n}\n.c-skeleton__circle--lg {\n width: var(--c-skeleton-circle-lg);\n height: var(--c-skeleton-circle-lg);\n}\n\n/* ─── Avatar 预设 ─── */\n.c-skeleton__avatar-group {\n display: flex;\n align-items: center;\n gap: var(--c-skeleton-gap);\n}\n.c-skeleton__avatar-text {\n flex: 1;\n}\n\n/* ─── Image 预设 ─── */\n.c-skeleton__image {\n width: 100%;\n height: var(--c-skeleton-image-height);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__image-icon {\n color: var(--c-skeleton-bg);\n opacity: 0.6;\n filter: brightness(0.8);\n}\n\n/* ─── Card 预设 ─── */\n.c-skeleton__card {\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__card-cover {\n width: 100%;\n height: var(--c-skeleton-card-cover-height);\n border-radius: 0;\n}\n.c-skeleton__card-body {\n padding: 16px;\n}\n.c-skeleton__card-desc {\n margin-top: 8px;\n}\n.c-skeleton__card-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid var(--c-skeleton-bg);\n}\n\n/* ─── Table 预设 ─── */\n.c-skeleton__table {\n width: 100%;\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n}\n.c-skeleton__table-header {\n display: flex;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--c-skeleton-bg) 30%, transparent);\n border-bottom: 1px solid var(--c-skeleton-bg);\n}\n.c-skeleton__table-row {\n display: flex;\n padding: 12px 16px;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__table-row:last-child {\n border-bottom: none;\n}\n.c-skeleton__table-cell {\n flex: 1;\n padding: 0 8px;\n}\n.c-skeleton__table-cell--action {\n flex: 0 0 120px;\n}\n.c-skeleton__action-btns {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* ─── Form 预设 ─── */\n.c-skeleton__form {\n display: grid;\n grid-template-columns: repeat(var(--form-cols, 2), 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__form-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__form-actions {\n grid-column: 1/-1;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 16px;\n}\n\n/* ─── List 预设 ─── */\n.c-skeleton__list-item {\n display: flex;\n align-items: flex-start;\n gap: var(--c-skeleton-gap);\n padding: 12px 0;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__list-item:last-child {\n border-bottom: none;\n}\n.c-skeleton__list-content {\n flex: 1;\n}\n\n/* ─── Detail 预设 ─── */\n.c-skeleton__detail-header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n}\n.c-skeleton__detail-title {\n flex: 1;\n}\n.c-skeleton__detail-body {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__detail-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__detail-value {\n margin-top: 4px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Skeleton.js","names":["preset","repeat"],"sources":["../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Skeleton2.js","names":["preset","repeat"],"sources":["../src/components/C_Skeleton/index.vue","../src/components/C_Skeleton/index.vue"],"sourcesContent":["<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-06\n * @Description: C_Skeleton 业务级骨架屏组件\n * 提供 8 种预设模式:text / avatar / card / table / form / list / detail / image\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n v-if=\"props.loading\"\n class=\"c-skeleton\"\n :class=\"[`c-skeleton--${animationType}`]\"\n >\n <!-- text 预设 -->\n <template v-if=\"preset === 'text'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__text\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: i === repeat ? '60%' : '100%' }\"\n />\n </div>\n </template>\n\n <!-- avatar 预设 -->\n <template v-else-if=\"preset === 'avatar'\">\n <div class=\"c-skeleton__avatar-group\">\n <div class=\"c-skeleton__circle c-skeleton__item\" />\n <div class=\"c-skeleton__avatar-text\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 40%\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n </template>\n\n <!-- image 预设 -->\n <template v-else-if=\"preset === 'image'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__image c-skeleton__item\"\n >\n <div class=\"c-skeleton__image-icon\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"32\"\n height=\"32\"\n >\n <path\n d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"\n />\n </svg>\n </div>\n </div>\n </template>\n\n <!-- card 预设 -->\n <template v-else-if=\"preset === 'card'\">\n <div\n v-for=\"i in repeat\"\n :key=\"i\"\n class=\"c-skeleton__card\"\n >\n <div\n v-if=\"cardConfig.showCover\"\n class=\"c-skeleton__card-cover c-skeleton__item\"\n />\n <div class=\"c-skeleton__card-body\">\n <div\n v-for=\"t in cardConfig.titleLines\"\n :key=\"`t-${t}`\"\n class=\"c-skeleton__line c-skeleton__item\"\n :style=\"{ width: t === cardConfig.titleLines ? '50%' : '80%' }\"\n />\n <div class=\"c-skeleton__card-desc\">\n <div\n v-for=\"d in cardConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === cardConfig.descLines ? '70%' : '100%',\n }\"\n />\n </div>\n </div>\n <div\n v-if=\"cardConfig.showFooter\"\n class=\"c-skeleton__card-footer\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- table 预设 -->\n <template v-else-if=\"preset === 'table'\">\n <div class=\"c-skeleton__table\">\n <div\n v-if=\"tableConfig.showHeader\"\n class=\"c-skeleton__table-header\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`h-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 60%\"\n />\n </div>\n </div>\n <div\n v-for=\"r in tableConfig.rows\"\n :key=\"`r-${r}`\"\n class=\"c-skeleton__table-row\"\n >\n <div\n v-for=\"c in tableConfig.cols\"\n :key=\"`c-${c}`\"\n class=\"c-skeleton__table-cell\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: `${Math.floor(50 + ((r * c * 17) % 50))}%`,\n }\"\n />\n </div>\n <div\n v-if=\"tableConfig.showActions\"\n class=\"c-skeleton__table-cell c-skeleton__table-cell--action\"\n >\n <div class=\"c-skeleton__action-btns\">\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--mini\"\n style=\"width: 40px\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n\n <!-- form 预设 -->\n <template v-else-if=\"preset === 'form'\">\n <div\n class=\"c-skeleton__form\"\n :style=\"{ '--form-cols': formConfig.cols }\"\n >\n <div\n v-for=\"f in formConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__form-field\"\n >\n <div\n v-if=\"formConfig.showLabel\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${60 + ((f * 13) % 30)}px` }\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--input\"\n />\n </div>\n <div\n v-if=\"formConfig.showActions\"\n class=\"c-skeleton__form-actions\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 100px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--btn\"\n style=\"width: 80px\"\n />\n </div>\n </div>\n </template>\n\n <!-- list 预设 -->\n <template v-else-if=\"preset === 'list'\">\n <div\n v-for=\"i in listConfig.items\"\n :key=\"i\"\n class=\"c-skeleton__list-item\"\n >\n <div\n v-if=\"listConfig.showAvatar\"\n class=\"c-skeleton__circle c-skeleton__circle--sm c-skeleton__item\"\n />\n <div class=\"c-skeleton__list-content\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 30%\"\n />\n <div\n v-for=\"d in listConfig.descLines\"\n :key=\"`d-${d}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: d === listConfig.descLines ? '50%' : '90%',\n }\"\n />\n </div>\n </div>\n </template>\n\n <!-- detail 预设 -->\n <template v-else-if=\"preset === 'detail'\">\n <div class=\"c-skeleton__detail\">\n <div\n v-if=\"detailConfig.showAvatar\"\n class=\"c-skeleton__detail-header\"\n >\n <div\n class=\"c-skeleton__circle c-skeleton__circle--lg c-skeleton__item\"\n />\n <div class=\"c-skeleton__detail-title\">\n <div\n class=\"c-skeleton__line c-skeleton__item\"\n style=\"width: 120px\"\n />\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n style=\"width: 200px\"\n />\n </div>\n </div>\n <div class=\"c-skeleton__detail-body\">\n <div\n v-for=\"f in detailConfig.fields\"\n :key=\"f\"\n class=\"c-skeleton__detail-field\"\n >\n <div\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--label\"\n :style=\"{ width: `${50 + ((f * 17) % 40)}px` }\"\n />\n <div class=\"c-skeleton__detail-value\">\n <div\n v-for=\"v in detailConfig.valueLines\"\n :key=\"`v-${v}`\"\n class=\"c-skeleton__line c-skeleton__item c-skeleton__line--sm\"\n :style=\"{\n width: v === detailConfig.valueLines ? '60%' : '100%',\n }\"\n />\n </div>\n </div>\n </div>\n </div>\n </template>\n </div>\n\n <!-- 加载完成后显示插槽内容 -->\n <slot v-else />\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import type {\n SkeletonProps,\n SkeletonTableConfig,\n SkeletonFormConfig,\n SkeletonListConfig,\n SkeletonCardConfig,\n SkeletonDetailConfig,\n } from './types'\n\n defineOptions({ name: 'C_Skeleton' })\n\n const props = withDefaults(defineProps<SkeletonProps>(), {\n preset: 'text',\n loading: true,\n animation: 'wave',\n repeat: 3,\n borderRadius: '4px',\n })\n\n const animationType = computed(() =>\n props.animation === false ? 'none' : props.animation\n )\n\n const tableConfig = computed<Required<SkeletonTableConfig>>(() => ({\n rows: props.table?.rows ?? 5,\n cols: props.table?.cols ?? 4,\n showHeader: props.table?.showHeader ?? true,\n showActions: props.table?.showActions ?? true,\n }))\n\n const formConfig = computed<Required<SkeletonFormConfig>>(() => ({\n fields: props.form?.fields ?? 6,\n cols: props.form?.cols ?? 2,\n showLabel: props.form?.showLabel ?? true,\n showActions: props.form?.showActions ?? true,\n }))\n\n const listConfig = computed<Required<SkeletonListConfig>>(() => ({\n items: props.list?.items ?? 5,\n showAvatar: props.list?.showAvatar ?? true,\n descLines: props.list?.descLines ?? 2,\n }))\n\n const cardConfig = computed<Required<SkeletonCardConfig>>(() => ({\n showCover: props.card?.showCover ?? true,\n titleLines: props.card?.titleLines ?? 1,\n descLines: props.card?.descLines ?? 2,\n showFooter: props.card?.showFooter ?? true,\n }))\n\n const detailConfig = computed<Required<SkeletonDetailConfig>>(() => ({\n fields: props.detail?.fields ?? 6,\n valueLines: props.detail?.valueLines ?? 1,\n showAvatar: props.detail?.showAvatar ?? true,\n }))\n</script>\n\n<style lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_SplitPane-CgGWYsRE.css","names":[],"sources":["../src/components/C_SplitPane/index.vue?vue&type=style&index=0&scoped=e35daacb&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* 分割面板组件样式 */\n.c-split-pane[data-v-e35daacb] {\n display: flex;\n width: 100%;\n height: 100%;\n overflow: hidden;\n position: relative;\n /* ─── 方向 ────────────────────────────────── */\n /* ─── 拖拽中 ──────────────────────────────── */\n /* ─── 禁用 ────────────────────────────────── */\n /* ─── 折叠过渡 ────────────────────────────── */\n}\n.c-split-pane--horizontal[data-v-e35daacb] {\n flex-direction: row;\n}\n.c-split-pane--vertical[data-v-e35daacb] {\n flex-direction: column;\n}\n.c-split-pane--dragging .split-panel__content[data-v-e35daacb] {\n pointer-events: none;\n user-select: none;\n}\n.c-split-pane--disabled .split-gutter[data-v-e35daacb] {\n cursor: default !important;\n opacity: 0.5;\n}\n.c-split-pane--disabled .split-gutter[data-v-e35daacb]:hover {\n background: transparent;\n}\n.c-split-pane--collapsed-first .split-panel[data-v-e35daacb], .c-split-pane--collapsed-second .split-panel[data-v-e35daacb] {\n transition: width 0.3s ease, height 0.3s ease;\n}\n\n/* ─── 面板 ──────────────────────────────────── */\n.split-panel[data-v-e35daacb] {\n overflow: hidden;\n position: relative;\n}\n.split-panel__content[data-v-e35daacb] {\n width: 100%;\n height: 100%;\n overflow: auto;\n}\n\n/* ─── 分割线手柄 ────────────────────────────── */\n.split-gutter[data-v-e35daacb] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 1;\n background: var(--c-border, #e1e4e8);\n transition: background-color 0.2s ease;\n outline: none;\n /* 水平方向 */\n /* 垂直方向 */\n /* focus 轮廓 */\n /* ─── 视觉指示条 ──────────────────────────── */\n /* ─── 折叠按钮 ────────────────────────────── */\n}\n.c-split-pane--horizontal .split-gutter[data-v-e35daacb] {\n cursor: col-resize;\n min-width: 4px;\n}\n.c-split-pane--horizontal .split-gutter[data-v-e35daacb]:hover, .c-split-pane--horizontal .split-gutter[data-v-e35daacb]:focus-visible {\n background: var(--c-primary, #409eff);\n}\n.c-split-pane--vertical .split-gutter[data-v-e35daacb] {\n cursor: row-resize;\n min-height: 4px;\n}\n.c-split-pane--vertical .split-gutter[data-v-e35daacb]:hover, .c-split-pane--vertical .split-gutter[data-v-e35daacb]:focus-visible {\n background: var(--c-primary, #409eff);\n}\n.split-gutter[data-v-e35daacb]:focus-visible {\n box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.3);\n}\n.split-gutter__visual[data-v-e35daacb] {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.split-gutter__dots[data-v-e35daacb] {\n display: flex;\n gap: 2px;\n}\n.c-split-pane--horizontal .split-gutter__dots[data-v-e35daacb] {\n flex-direction: column;\n}\n.c-split-pane--vertical .split-gutter__dots[data-v-e35daacb] {\n flex-direction: row;\n}\n.split-gutter__dot[data-v-e35daacb] {\n width: 3px;\n height: 3px;\n border-radius: 50%;\n background: var(--c-text-4, #ccc);\n transition: background-color 0.2s ease;\n}\n.split-gutter:hover .split-gutter__dot[data-v-e35daacb] {\n background: #fff;\n}\n.split-gutter__collapse-btn[data-v-e35daacb] {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: 50%;\n background: var(--c-bg-card, #fff);\n color: var(--c-text-3, #999);\n font-size: 12px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease, color 0.2s ease, background-color 0.2s ease;\n z-index: 2;\n /* 水平方向的定位 */\n /* 垂直方向的定位 */\n}\n.split-gutter:hover .split-gutter__collapse-btn[data-v-e35daacb] {\n opacity: 1;\n}\n.split-gutter__collapse-btn[data-v-e35daacb]:hover {\n color: var(--c-primary, #409eff);\n background: var(--c-bg, #fff);\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn[data-v-e35daacb] {\n left: 50%;\n transform: translateX(-50%);\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn--first[data-v-e35daacb] {\n top: 8px;\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn--second[data-v-e35daacb] {\n bottom: 8px;\n}\n.c-split-pane--vertical .split-gutter__collapse-btn[data-v-e35daacb] {\n top: 50%;\n transform: translateY(-50%);\n}\n.c-split-pane--vertical .split-gutter__collapse-btn--first[data-v-e35daacb] {\n left: 8px;\n}\n.c-split-pane--vertical .split-gutter__collapse-btn--second[data-v-e35daacb] {\n right: 8px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_SplitPane-DGf6WEeR.css","names":[],"sources":["../src/components/C_SplitPane/index.vue?vue&type=style&index=0&scoped=e35daacb&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* 分割面板组件样式 */\n.c-split-pane[data-v-e35daacb] {\n display: flex;\n width: 100%;\n height: 100%;\n overflow: hidden;\n position: relative;\n /* ─── 方向 ────────────────────────────────── */\n /* ─── 拖拽中 ──────────────────────────────── */\n /* ─── 禁用 ────────────────────────────────── */\n /* ─── 折叠过渡 ────────────────────────────── */\n}\n.c-split-pane--horizontal[data-v-e35daacb] {\n flex-direction: row;\n}\n.c-split-pane--vertical[data-v-e35daacb] {\n flex-direction: column;\n}\n.c-split-pane--dragging .split-panel__content[data-v-e35daacb] {\n pointer-events: none;\n user-select: none;\n}\n.c-split-pane--disabled .split-gutter[data-v-e35daacb] {\n cursor: default !important;\n opacity: 0.5;\n}\n.c-split-pane--disabled .split-gutter[data-v-e35daacb]:hover {\n background: transparent;\n}\n.c-split-pane--collapsed-first .split-panel[data-v-e35daacb], .c-split-pane--collapsed-second .split-panel[data-v-e35daacb] {\n transition: width 0.3s ease, height 0.3s ease;\n}\n\n/* ─── 面板 ──────────────────────────────────── */\n.split-panel[data-v-e35daacb] {\n overflow: hidden;\n position: relative;\n}\n.split-panel__content[data-v-e35daacb] {\n width: 100%;\n height: 100%;\n overflow: auto;\n}\n\n/* ─── 分割线手柄 ────────────────────────────── */\n.split-gutter[data-v-e35daacb] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n z-index: 1;\n background: var(--c-border, #e1e4e8);\n transition: background-color 0.2s ease;\n outline: none;\n /* 水平方向 */\n /* 垂直方向 */\n /* focus 轮廓 */\n /* ─── 视觉指示条 ──────────────────────────── */\n /* ─── 折叠按钮 ────────────────────────────── */\n}\n.c-split-pane--horizontal .split-gutter[data-v-e35daacb] {\n cursor: col-resize;\n min-width: 4px;\n}\n.c-split-pane--horizontal .split-gutter[data-v-e35daacb]:hover, .c-split-pane--horizontal .split-gutter[data-v-e35daacb]:focus-visible {\n background: var(--c-primary, #409eff);\n}\n.c-split-pane--vertical .split-gutter[data-v-e35daacb] {\n cursor: row-resize;\n min-height: 4px;\n}\n.c-split-pane--vertical .split-gutter[data-v-e35daacb]:hover, .c-split-pane--vertical .split-gutter[data-v-e35daacb]:focus-visible {\n background: var(--c-primary, #409eff);\n}\n.split-gutter[data-v-e35daacb]:focus-visible {\n box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.3);\n}\n.split-gutter__visual[data-v-e35daacb] {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.split-gutter__dots[data-v-e35daacb] {\n display: flex;\n gap: 2px;\n}\n.c-split-pane--horizontal .split-gutter__dots[data-v-e35daacb] {\n flex-direction: column;\n}\n.c-split-pane--vertical .split-gutter__dots[data-v-e35daacb] {\n flex-direction: row;\n}\n.split-gutter__dot[data-v-e35daacb] {\n width: 3px;\n height: 3px;\n border-radius: 50%;\n background: var(--c-text-4, #ccc);\n transition: background-color 0.2s ease;\n}\n.split-gutter:hover .split-gutter__dot[data-v-e35daacb] {\n background: #fff;\n}\n.split-gutter__collapse-btn[data-v-e35daacb] {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n padding: 0;\n border: 1px solid var(--c-border, #e1e4e8);\n border-radius: 50%;\n background: var(--c-bg-card, #fff);\n color: var(--c-text-3, #999);\n font-size: 12px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.2s ease, color 0.2s ease, background-color 0.2s ease;\n z-index: 2;\n /* 水平方向的定位 */\n /* 垂直方向的定位 */\n}\n.split-gutter:hover .split-gutter__collapse-btn[data-v-e35daacb] {\n opacity: 1;\n}\n.split-gutter__collapse-btn[data-v-e35daacb]:hover {\n color: var(--c-primary, #409eff);\n background: var(--c-bg, #fff);\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn[data-v-e35daacb] {\n left: 50%;\n transform: translateX(-50%);\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn--first[data-v-e35daacb] {\n top: 8px;\n}\n.c-split-pane--horizontal .split-gutter__collapse-btn--second[data-v-e35daacb] {\n bottom: 8px;\n}\n.c-split-pane--vertical .split-gutter__collapse-btn[data-v-e35daacb] {\n top: 50%;\n transform: translateY(-50%);\n}\n.c-split-pane--vertical .split-gutter__collapse-btn--first[data-v-e35daacb] {\n left: 8px;\n}\n.c-split-pane--vertical .split-gutter__collapse-btn--second[data-v-e35daacb] {\n right: 8px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_SplitPane.js","names":["direction","disabled","showCollapseButton","collapsible"],"sources":["../src/components/C_SplitPane/composables/useSplitResize.ts","../src/components/C_SplitPane/index.vue","../src/components/C_SplitPane/index.vue"],"sourcesContent":["import { ref, computed, onUnmounted } from \"vue\";\r\nimport type { Ref } from \"vue\";\r\nimport type { CollapseTarget, SplitDirection } from \"../types\";\r\n\r\ninterface UseSplitResizeOptions {\r\n /** 容器引用 */\r\n containerRef: Ref<HTMLElement | null>;\r\n /** 分割方向 */\r\n direction: Ref<SplitDirection>;\r\n /** 首面板默认大小(百分比) */\r\n defaultSize: number;\r\n /** 首面板最小大小(百分比) */\r\n minSize: number;\r\n /** 首面板最大大小(百分比) */\r\n maxSize: number;\r\n /** 是否禁用 */\r\n disabled: Ref<boolean>;\r\n /** 是否可折叠 */\r\n collapsible: Ref<boolean>;\r\n /** 键盘微调步长(百分比) */\r\n step: number;\r\n /** resize 回调 */\r\n onResize?: (firstSize: number, secondSize: number) => void;\r\n /** 折叠回调 */\r\n onCollapse?: (target: CollapseTarget) => void;\r\n /** 展开回调 */\r\n onExpand?: (target: CollapseTarget) => void;\r\n /** 拖拽开始回调 */\r\n onDragStart?: (size: number) => void;\r\n /** 拖拽结束回调 */\r\n onDragEnd?: (size: number) => void;\r\n}\r\n\r\n/**\r\n * 分割面板拖拽调整逻辑\r\n */\r\nexport function useSplitResize(options: UseSplitResizeOptions) {\r\n const {\r\n containerRef,\r\n direction,\r\n defaultSize,\r\n minSize,\r\n maxSize,\r\n disabled,\r\n collapsible,\r\n step,\r\n onResize,\r\n onCollapse,\r\n onExpand,\r\n onDragStart,\r\n onDragEnd,\r\n } = options;\r\n\r\n /** 首面板当前大小(百分比) */\r\n const panelSize = ref(defaultSize);\r\n /** 是否正在拖拽 */\r\n const isDragging = ref(false);\r\n /** 折叠状态 */\r\n const collapsedTarget = ref<CollapseTarget | null>(null);\r\n /** 折叠前记住的面板大小 */\r\n const sizeBeforeCollapse = ref(defaultSize);\r\n\r\n /** 首面板是否折叠 */\r\n const isFirstCollapsed = computed(() => collapsedTarget.value === \"first\");\r\n /** 第二面板是否折叠 */\r\n const isSecondCollapsed = computed(() => collapsedTarget.value === \"second\");\r\n\r\n /**\r\n * 将大小限制在 min/max 范围内\r\n */\r\n const clampSize = (size: number): number => {\r\n return Math.min(maxSize, Math.max(minSize, size));\r\n };\r\n\r\n /**\r\n * 获取容器在分割方向上的总长度(px)\r\n */\r\n const getContainerLength = (): number => {\r\n const container = containerRef.value;\r\n if (!container) return 0;\r\n return direction.value === \"horizontal\"\r\n ? container.offsetWidth\r\n : container.offsetHeight;\r\n };\r\n\r\n /**\r\n * 获取容器在分割方向上的起始坐标\r\n */\r\n const getContainerStart = (): number => {\r\n const container = containerRef.value;\r\n if (!container) return 0;\r\n const rect = container.getBoundingClientRect();\r\n return direction.value === \"horizontal\" ? rect.left : rect.top;\r\n };\r\n\r\n /**\r\n * 根据鼠标/触摸位置计算面板大小(百分比)\r\n */\r\n const calcSizeFromPosition = (clientPos: number): number => {\r\n const containerLength = getContainerLength();\r\n if (containerLength === 0) return panelSize.value;\r\n\r\n const containerStart = getContainerStart();\r\n const offset = clientPos - containerStart;\r\n const percentage = (offset / containerLength) * 100;\r\n\r\n return clampSize(percentage);\r\n };\r\n\r\n /**\r\n * 获取事件的位置坐标\r\n */\r\n const getClientPos = (e: MouseEvent | TouchEvent): number => {\r\n if (e instanceof TouchEvent) {\r\n return direction.value === \"horizontal\"\r\n ? e.touches[0].clientX\r\n : e.touches[0].clientY;\r\n }\r\n return direction.value === \"horizontal\" ? e.clientX : e.clientY;\r\n };\r\n\r\n /**\r\n * 更新面板大小\r\n */\r\n const updateSize = (newSize: number) => {\r\n const clamped = clampSize(newSize);\r\n panelSize.value = clamped;\r\n onResize?.(clamped, 100 - clamped);\r\n };\r\n\r\n /* ─── 拖拽逻辑 ──────────────────────────────── */\r\n const handleMouseMove = (e: MouseEvent | TouchEvent) => {\r\n if (!isDragging.value || disabled.value) return;\r\n\r\n e.preventDefault();\r\n const pos = getClientPos(e);\r\n const newSize = calcSizeFromPosition(pos);\r\n\r\n /* 拖拽过程中取消折叠状态 */\r\n if (collapsedTarget.value) {\r\n collapsedTarget.value = null;\r\n }\r\n updateSize(newSize);\r\n };\r\n\r\n const handleMouseUp = () => {\r\n if (!isDragging.value) return;\r\n\r\n isDragging.value = false;\r\n document.body.style.cursor = \"\";\r\n document.body.style.userSelect = \"\";\r\n\r\n onDragEnd?.(panelSize.value);\r\n\r\n document.removeEventListener(\"mousemove\", handleMouseMove);\r\n document.removeEventListener(\"mouseup\", handleMouseUp);\r\n document.removeEventListener(\"touchmove\", handleMouseMove);\r\n document.removeEventListener(\"touchend\", handleMouseUp);\r\n };\r\n\r\n const handleMouseDown = (e: MouseEvent | TouchEvent) => {\r\n if (disabled.value) return;\r\n\r\n e.preventDefault();\r\n /* preventDefault 会阻止默认聚焦行为,需手动 focus 以支持键盘控制 */\r\n (e.currentTarget as HTMLElement)?.focus();\r\n isDragging.value = true;\r\n\r\n document.body.style.cursor =\r\n direction.value === \"horizontal\" ? \"col-resize\" : \"row-resize\";\r\n document.body.style.userSelect = \"none\";\r\n\r\n onDragStart?.(panelSize.value);\r\n\r\n document.addEventListener(\"mousemove\", handleMouseMove);\r\n document.addEventListener(\"mouseup\", handleMouseUp);\r\n document.addEventListener(\"touchmove\", handleMouseMove, { passive: false });\r\n document.addEventListener(\"touchend\", handleMouseUp);\r\n };\r\n\r\n /* ─── 双击折叠 ──────────────────────────────── */\r\n const handleDoubleClick = () => {\r\n if (disabled.value || !collapsible.value) return;\r\n toggle(\"first\");\r\n };\r\n\r\n /* ─── 折叠 / 展开 ───────────────────────────── */\r\n const collapse = (target: CollapseTarget = \"first\") => {\r\n if (!collapsible.value || collapsedTarget.value === target) return;\r\n\r\n /* 记住折叠前的大小 */\r\n if (!collapsedTarget.value) {\r\n sizeBeforeCollapse.value = panelSize.value;\r\n }\r\n\r\n collapsedTarget.value = target;\r\n\r\n if (target === \"first\") {\r\n panelSize.value = 0;\r\n } else {\r\n panelSize.value = 100;\r\n }\r\n\r\n onCollapse?.(target);\r\n onResize?.(panelSize.value, 100 - panelSize.value);\r\n };\r\n\r\n const expand = () => {\r\n if (!collapsedTarget.value) return;\r\n\r\n const target = collapsedTarget.value;\r\n collapsedTarget.value = null;\r\n panelSize.value = sizeBeforeCollapse.value;\r\n\r\n onExpand?.(target);\r\n onResize?.(panelSize.value, 100 - panelSize.value);\r\n };\r\n\r\n const toggle = (target: CollapseTarget = \"first\") => {\r\n if (collapsedTarget.value) {\r\n expand();\r\n } else {\r\n collapse(target);\r\n }\r\n };\r\n\r\n /* ─── 键盘微调 ──────────────────────────────── */\r\n /**\r\n * 根据按键获取增量\r\n */\r\n const getKeyDelta = (key: string, isHorizontal: boolean): number | null => {\r\n const keyMap: Record<string, number | null> = {\r\n ArrowLeft: isHorizontal ? -step : 0,\r\n ArrowRight: isHorizontal ? step : 0,\r\n ArrowUp: !isHorizontal ? -step : 0,\r\n ArrowDown: !isHorizontal ? step : 0,\r\n };\r\n return keyMap[key] ?? null;\r\n };\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (disabled.value) return;\r\n\r\n /* Home / End 直接跳到极值 */\r\n if (e.key === \"Home\") {\r\n updateSize(minSize);\r\n e.preventDefault();\r\n return;\r\n }\r\n if (e.key === \"End\") {\r\n updateSize(maxSize);\r\n e.preventDefault();\r\n return;\r\n }\r\n\r\n const delta = getKeyDelta(e.key, direction.value === \"horizontal\");\r\n if (delta === null || delta === 0) return;\r\n\r\n e.preventDefault();\r\n if (collapsedTarget.value) collapsedTarget.value = null;\r\n updateSize(panelSize.value + delta);\r\n };\r\n\r\n /* ─── 重置 / 查询 ───────────────────────────── */\r\n const resetSize = () => {\r\n collapsedTarget.value = null;\r\n panelSize.value = defaultSize;\r\n onResize?.(defaultSize, 100 - defaultSize);\r\n };\r\n\r\n const setSize = (size: number) => {\r\n collapsedTarget.value = null;\r\n updateSize(size);\r\n };\r\n\r\n const getPanelInfo = () => ({\r\n first: {\r\n size: panelSize.value,\r\n collapsed: isFirstCollapsed.value,\r\n },\r\n second: {\r\n size: 100 - panelSize.value,\r\n collapsed: isSecondCollapsed.value,\r\n },\r\n });\r\n\r\n /* 清理 */\r\n onUnmounted(() => {\r\n document.removeEventListener(\"mousemove\", handleMouseMove);\r\n document.removeEventListener(\"mouseup\", handleMouseUp);\r\n document.removeEventListener(\"touchmove\", handleMouseMove);\r\n document.removeEventListener(\"touchend\", handleMouseUp);\r\n });\r\n\r\n return {\r\n panelSize,\r\n isDragging,\r\n collapsedTarget,\r\n isFirstCollapsed,\r\n isSecondCollapsed,\r\n handleMouseDown,\r\n handleDoubleClick,\r\n handleKeyDown,\r\n collapse,\r\n expand,\r\n toggle,\r\n resetSize,\r\n setSize,\r\n getPanelInfo,\r\n };\r\n}\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-16\n * @Description: 分割面板组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-split-pane\"\n :class=\"[\n `c-split-pane--${direction}`,\n {\n 'c-split-pane--dragging': isDragging,\n 'c-split-pane--disabled': disabled,\n 'c-split-pane--collapsed-first': isFirstCollapsed,\n 'c-split-pane--collapsed-second': isSecondCollapsed,\n },\n ]\"\n >\n <!-- 首面板 -->\n <div class=\"split-panel split-panel--first\" :style=\"firstPanelStyle\">\n <div class=\"split-panel__content\">\n <slot name=\"first\" />\n </div>\n </div>\n\n <!-- 分割线手柄 -->\n <div\n class=\"split-gutter\"\n :style=\"gutterStyle\"\n role=\"separator\"\n :aria-orientation=\"direction === 'horizontal' ? 'vertical' : 'horizontal'\"\n :aria-valuenow=\"Math.round(panelSize)\"\n :aria-valuemin=\"0\"\n :aria-valuemax=\"100\"\n tabindex=\"0\"\n @mousedown=\"handleMouseDown\"\n @touchstart.prevent=\"handleMouseDown\"\n @dblclick=\"handleDoubleClick\"\n @keydown=\"handleKeyDown\"\n >\n <div class=\"split-gutter__visual\">\n <div class=\"split-gutter__dots\">\n <span v-for=\"i in 3\" :key=\"i\" class=\"split-gutter__dot\" />\n </div>\n </div>\n\n <!-- 折叠按钮 -->\n <template v-if=\"showCollapseButton && collapsible\">\n <button\n class=\"split-gutter__collapse-btn split-gutter__collapse-btn--first\"\n :title=\"isFirstCollapsed ? '展开首面板' : '折叠首面板'\"\n @click.stop=\"toggle('first')\"\n @mousedown.stop\n >\n <C_Icon :name=\"collapseFirstIcon\" :size=\"16\" color=\"currentColor\" />\n </button>\n <button\n class=\"split-gutter__collapse-btn split-gutter__collapse-btn--second\"\n :title=\"isSecondCollapsed ? '展开第二面板' : '折叠第二面板'\"\n @click.stop=\"toggle('second')\"\n @mousedown.stop\n >\n <C_Icon :name=\"collapseSecondIcon\" :size=\"16\" color=\"currentColor\" />\n </button>\n </template>\n </div>\n\n <!-- 第二面板 -->\n <div class=\"split-panel split-panel--second\" :style=\"secondPanelStyle\">\n <div class=\"split-panel__content\">\n <slot name=\"second\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, toRef } from \"vue\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSplitResize } from \"./composables/useSplitResize\";\nimport type { CollapseTarget, SplitDirection, SplitPaneExpose } from \"./types\";\n\ndefineOptions({ name: \"C_SplitPane\" });\n\ninterface Props {\n /** 分割方向 */\n direction?: SplitDirection;\n /** 首面板默认大小(百分比 0-100) */\n defaultSize?: number;\n /** 首面板最小大小(百分比 0-100) */\n minSize?: number;\n /** 首面板最大大小(百分比 0-100) */\n maxSize?: number;\n /** 是否禁用拖拽调整 */\n disabled?: boolean;\n /** 是否可折叠 */\n collapsible?: boolean;\n /** 是否显示折叠按钮 */\n showCollapseButton?: boolean;\n /** 分割线宽度(px) */\n gutterSize?: number;\n /** 键盘微调步长(百分比) */\n step?: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n direction: \"horizontal\",\n defaultSize: 50,\n minSize: 0,\n maxSize: 100,\n disabled: false,\n collapsible: true,\n showCollapseButton: true,\n gutterSize: 6,\n step: 2,\n});\n\nconst emit = defineEmits<{\n resize: [firstSize: number, secondSize: number];\n collapse: [target: CollapseTarget];\n expand: [target: CollapseTarget];\n \"drag-start\": [size: number];\n \"drag-end\": [size: number];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\n\nconst {\n panelSize,\n isDragging,\n isFirstCollapsed,\n isSecondCollapsed,\n handleMouseDown,\n handleDoubleClick,\n handleKeyDown,\n collapse,\n expand,\n toggle,\n resetSize,\n setSize,\n getPanelInfo,\n} = useSplitResize({\n containerRef,\n direction: toRef(props, \"direction\"),\n defaultSize: props.defaultSize,\n minSize: props.minSize,\n maxSize: props.maxSize,\n disabled: toRef(props, \"disabled\"),\n collapsible: toRef(props, \"collapsible\"),\n step: props.step,\n onResize: (first, second) => emit(\"resize\", first, second),\n onCollapse: (target) => emit(\"collapse\", target),\n onExpand: (target) => emit(\"expand\", target),\n onDragStart: (size) => emit(\"drag-start\", size),\n onDragEnd: (size) => emit(\"drag-end\", size),\n});\n\n/* ─── 计算样式 ──────────────────────────────── */\nconst firstPanelStyle = computed(() => {\n const sizeValue = `calc(${panelSize.value}% - ${props.gutterSize / 2}px)`;\n return props.direction === \"horizontal\"\n ? { width: sizeValue }\n : { height: sizeValue };\n});\n\nconst secondPanelStyle = computed(() => {\n const sizeValue = `calc(${100 - panelSize.value}% - ${props.gutterSize / 2}px)`;\n return props.direction === \"horizontal\"\n ? { width: sizeValue }\n : { height: sizeValue };\n});\n\nconst gutterStyle = computed(() => {\n return props.direction === \"horizontal\"\n ? { width: `${props.gutterSize}px` }\n : { height: `${props.gutterSize}px` };\n});\n\n/* ─── 折叠按钮图标 ──────────────────────────── */\nconst collapseFirstIcon = computed(() => {\n if (props.direction === \"horizontal\") {\n return isFirstCollapsed.value ? \"mdi:chevron-right\" : \"mdi:chevron-left\";\n }\n return isFirstCollapsed.value ? \"mdi:chevron-down\" : \"mdi:chevron-up\";\n});\n\nconst collapseSecondIcon = computed(() => {\n if (props.direction === \"horizontal\") {\n return isSecondCollapsed.value ? \"mdi:chevron-left\" : \"mdi:chevron-right\";\n }\n return isSecondCollapsed.value ? \"mdi:chevron-up\" : \"mdi:chevron-down\";\n});\n\n/* ─── 暴露方法 ──────────────────────────────── */\ndefineExpose<SplitPaneExpose>({\n collapse,\n expand,\n toggle,\n resetSize,\n getPanelInfo,\n setSize,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-16\n * @Description: 分割面板组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n<template>\n <div\n ref=\"containerRef\"\n class=\"c-split-pane\"\n :class=\"[\n `c-split-pane--${direction}`,\n {\n 'c-split-pane--dragging': isDragging,\n 'c-split-pane--disabled': disabled,\n 'c-split-pane--collapsed-first': isFirstCollapsed,\n 'c-split-pane--collapsed-second': isSecondCollapsed,\n },\n ]\"\n >\n <!-- 首面板 -->\n <div class=\"split-panel split-panel--first\" :style=\"firstPanelStyle\">\n <div class=\"split-panel__content\">\n <slot name=\"first\" />\n </div>\n </div>\n\n <!-- 分割线手柄 -->\n <div\n class=\"split-gutter\"\n :style=\"gutterStyle\"\n role=\"separator\"\n :aria-orientation=\"direction === 'horizontal' ? 'vertical' : 'horizontal'\"\n :aria-valuenow=\"Math.round(panelSize)\"\n :aria-valuemin=\"0\"\n :aria-valuemax=\"100\"\n tabindex=\"0\"\n @mousedown=\"handleMouseDown\"\n @touchstart.prevent=\"handleMouseDown\"\n @dblclick=\"handleDoubleClick\"\n @keydown=\"handleKeyDown\"\n >\n <div class=\"split-gutter__visual\">\n <div class=\"split-gutter__dots\">\n <span v-for=\"i in 3\" :key=\"i\" class=\"split-gutter__dot\" />\n </div>\n </div>\n\n <!-- 折叠按钮 -->\n <template v-if=\"showCollapseButton && collapsible\">\n <button\n class=\"split-gutter__collapse-btn split-gutter__collapse-btn--first\"\n :title=\"isFirstCollapsed ? '展开首面板' : '折叠首面板'\"\n @click.stop=\"toggle('first')\"\n @mousedown.stop\n >\n <C_Icon :name=\"collapseFirstIcon\" :size=\"16\" color=\"currentColor\" />\n </button>\n <button\n class=\"split-gutter__collapse-btn split-gutter__collapse-btn--second\"\n :title=\"isSecondCollapsed ? '展开第二面板' : '折叠第二面板'\"\n @click.stop=\"toggle('second')\"\n @mousedown.stop\n >\n <C_Icon :name=\"collapseSecondIcon\" :size=\"16\" color=\"currentColor\" />\n </button>\n </template>\n </div>\n\n <!-- 第二面板 -->\n <div class=\"split-panel split-panel--second\" :style=\"secondPanelStyle\">\n <div class=\"split-panel__content\">\n <slot name=\"second\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, toRef } from \"vue\";\nimport C_Icon from \"../C_Icon/index.vue\";\nimport { useSplitResize } from \"./composables/useSplitResize\";\nimport type { CollapseTarget, SplitDirection, SplitPaneExpose } from \"./types\";\n\ndefineOptions({ name: \"C_SplitPane\" });\n\ninterface Props {\n /** 分割方向 */\n direction?: SplitDirection;\n /** 首面板默认大小(百分比 0-100) */\n defaultSize?: number;\n /** 首面板最小大小(百分比 0-100) */\n minSize?: number;\n /** 首面板最大大小(百分比 0-100) */\n maxSize?: number;\n /** 是否禁用拖拽调整 */\n disabled?: boolean;\n /** 是否可折叠 */\n collapsible?: boolean;\n /** 是否显示折叠按钮 */\n showCollapseButton?: boolean;\n /** 分割线宽度(px) */\n gutterSize?: number;\n /** 键盘微调步长(百分比) */\n step?: number;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n direction: \"horizontal\",\n defaultSize: 50,\n minSize: 0,\n maxSize: 100,\n disabled: false,\n collapsible: true,\n showCollapseButton: true,\n gutterSize: 6,\n step: 2,\n});\n\nconst emit = defineEmits<{\n resize: [firstSize: number, secondSize: number];\n collapse: [target: CollapseTarget];\n expand: [target: CollapseTarget];\n \"drag-start\": [size: number];\n \"drag-end\": [size: number];\n}>();\n\nconst containerRef = ref<HTMLElement | null>(null);\n\nconst {\n panelSize,\n isDragging,\n isFirstCollapsed,\n isSecondCollapsed,\n handleMouseDown,\n handleDoubleClick,\n handleKeyDown,\n collapse,\n expand,\n toggle,\n resetSize,\n setSize,\n getPanelInfo,\n} = useSplitResize({\n containerRef,\n direction: toRef(props, \"direction\"),\n defaultSize: props.defaultSize,\n minSize: props.minSize,\n maxSize: props.maxSize,\n disabled: toRef(props, \"disabled\"),\n collapsible: toRef(props, \"collapsible\"),\n step: props.step,\n onResize: (first, second) => emit(\"resize\", first, second),\n onCollapse: (target) => emit(\"collapse\", target),\n onExpand: (target) => emit(\"expand\", target),\n onDragStart: (size) => emit(\"drag-start\", size),\n onDragEnd: (size) => emit(\"drag-end\", size),\n});\n\n/* ─── 计算样式 ──────────────────────────────── */\nconst firstPanelStyle = computed(() => {\n const sizeValue = `calc(${panelSize.value}% - ${props.gutterSize / 2}px)`;\n return props.direction === \"horizontal\"\n ? { width: sizeValue }\n : { height: sizeValue };\n});\n\nconst secondPanelStyle = computed(() => {\n const sizeValue = `calc(${100 - panelSize.value}% - ${props.gutterSize / 2}px)`;\n return props.direction === \"horizontal\"\n ? { width: sizeValue }\n : { height: sizeValue };\n});\n\nconst gutterStyle = computed(() => {\n return props.direction === \"horizontal\"\n ? { width: `${props.gutterSize}px` }\n : { height: `${props.gutterSize}px` };\n});\n\n/* ─── 折叠按钮图标 ──────────────────────────── */\nconst collapseFirstIcon = computed(() => {\n if (props.direction === \"horizontal\") {\n return isFirstCollapsed.value ? \"mdi:chevron-right\" : \"mdi:chevron-left\";\n }\n return isFirstCollapsed.value ? \"mdi:chevron-down\" : \"mdi:chevron-up\";\n});\n\nconst collapseSecondIcon = computed(() => {\n if (props.direction === \"horizontal\") {\n return isSecondCollapsed.value ? \"mdi:chevron-left\" : \"mdi:chevron-right\";\n }\n return isSecondCollapsed.value ? \"mdi:chevron-up\" : \"mdi:chevron-down\";\n});\n\n/* ─── 暴露方法 ──────────────────────────────── */\ndefineExpose<SplitPaneExpose>({\n collapse,\n expand,\n toggle,\n resetSize,\n getPanelInfo,\n setSize,\n});\n</script>\n\n<style lang=\"scss\" scoped>\n@use \"./index.scss\";\n</style>\n"],"mappings":"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"}