@robot-admin/naive-ui-components 0.9.1 → 0.9.3

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 (327) hide show
  1. package/dist/C_ActionBar-BAcfOfRw.css.map +1 -0
  2. package/dist/C_ActionBar-DG2HW7t5.css.map +1 -0
  3. package/dist/C_ActionBar.css +47 -47
  4. package/dist/C_ActionBar.js.map +1 -1
  5. package/dist/C_ActionBar2.js +1 -1
  6. package/dist/C_ActionBar2.js.map +1 -1
  7. package/dist/{C_AntV-BY8jqqmi.css.map → C_AntV-D_jTK8oZ.css.map} +1 -1
  8. package/dist/{C_AntV-BbkHc-_a.css.map → C_AntV-DanTAq22.css.map} +1 -1
  9. package/dist/C_AntV.css +79 -79
  10. package/dist/C_AntV.js.map +1 -1
  11. package/dist/C_AntV2.js +3 -3
  12. package/dist/C_AntV2.js.map +1 -1
  13. package/dist/{C_AudioPlayer-DKRIGhi7.css.map → C_AudioPlayer-BnYIJXPD.css.map} +1 -1
  14. package/dist/{C_AudioPlayer-DlB6eNsa.css.map → C_AudioPlayer-ldTy9Y34.css.map} +1 -1
  15. package/dist/C_AudioPlayer.css +47 -47
  16. package/dist/C_AudioPlayer.js.map +1 -1
  17. package/dist/C_AudioPlayer2.js +1 -1
  18. package/dist/C_AudioPlayer2.js.map +1 -1
  19. package/dist/{C_AvatarGroup-D02zci-i.css.map → C_AvatarGroup-B9d-GJ9c.css.map} +1 -1
  20. package/dist/{C_AvatarGroup-DatHaUlY.css.map → C_AvatarGroup-SIzxuuZr.css.map} +1 -1
  21. package/dist/C_AvatarGroup.css +21 -21
  22. package/dist/C_AvatarGroup.js.map +1 -1
  23. package/dist/C_AvatarGroup2.js +1 -1
  24. package/dist/C_AvatarGroup2.js.map +1 -1
  25. package/dist/{C_Barcode-DYDRDe2O.css.map → C_Barcode-CAU2mFcx.css.map} +1 -1
  26. package/dist/{C_Barcode-muJdc_O4.css.map → C_Barcode-D2oJaEg3.css.map} +1 -1
  27. package/dist/C_Barcode.css +7 -7
  28. package/dist/C_Barcode.js.map +1 -1
  29. package/dist/C_Barcode2.js +1 -1
  30. package/dist/C_Barcode2.js.map +1 -1
  31. package/dist/C_Breadcrumb.js.map +1 -1
  32. package/dist/C_Breadcrumb2.js +1 -1
  33. package/dist/C_Breadcrumb2.js.map +1 -1
  34. package/dist/{C_Captcha-9_hk6VmY.css.map → C_Captcha-B3yrtG7t.css.map} +1 -1
  35. package/dist/{C_Captcha-MtASlJ0f.css.map → C_Captcha-D4hDdWDu.css.map} +1 -1
  36. package/dist/C_Captcha.css +19 -19
  37. package/dist/C_Captcha.js.map +1 -1
  38. package/dist/C_Captcha2.js +1 -1
  39. package/dist/C_Captcha2.js.map +1 -1
  40. package/dist/C_Cascade-BE7t1OX5.css.map +1 -0
  41. package/dist/C_Cascade-CpDiau1y.css.map +1 -0
  42. package/dist/C_Cascade.css +3 -3
  43. package/dist/C_Cascade.js.map +1 -1
  44. package/dist/C_Cascade2.js +1 -1
  45. package/dist/C_Cascade2.js.map +1 -1
  46. package/dist/{C_Chat-Csjz_BFw.css.map → C_Chat-CF1SU7mc.css.map} +1 -1
  47. package/dist/{C_Chat-DO1ZBA_0.css.map → C_Chat-DeUv6uuI.css.map} +1 -1
  48. package/dist/C_Chat.css +65 -65
  49. package/dist/C_Chat.js.map +1 -1
  50. package/dist/C_Chat2.js +1 -1
  51. package/dist/C_Chat2.js.map +1 -1
  52. package/dist/{C_City-Bam08Qv3.css.map → C_City-DdkX6u64.css.map} +1 -1
  53. package/dist/{C_City-Bb3W-KaN.css.map → C_City-iP-dIvui.css.map} +1 -1
  54. package/dist/C_City.css +29 -29
  55. package/dist/C_City.js.map +1 -1
  56. package/dist/C_City2.js +1 -1
  57. package/dist/C_City2.js.map +1 -1
  58. package/dist/C_Code-BWmJMNS7.css.map +1 -0
  59. package/dist/C_Code-k14vjgVl.css.map +1 -0
  60. package/dist/C_Code.css +3 -3
  61. package/dist/C_Code.js.map +1 -1
  62. package/dist/C_Code2.js +1 -1
  63. package/dist/C_Code2.js.map +1 -1
  64. package/dist/{C_CollapsePanel-CWkFCqNQ.css.map → C_CollapsePanel-BSKcWSmY.css.map} +1 -1
  65. package/dist/{C_CollapsePanel-pcVJA_4z.css.map → C_CollapsePanel-DRvRq8tB.css.map} +1 -1
  66. package/dist/C_CollapsePanel.css +35 -35
  67. package/dist/C_CollapsePanel.js.map +1 -1
  68. package/dist/C_CollapsePanel2.js +1 -1
  69. package/dist/C_CollapsePanel2.js.map +1 -1
  70. package/dist/{C_ContextMenu-B3Cgz_wJ.css.map → C_ContextMenu-Bn_uhJSo.css.map} +1 -1
  71. package/dist/{C_ContextMenu-u1LixF3_.css.map → C_ContextMenu-C9iuxG2n.css.map} +1 -1
  72. package/dist/C_ContextMenu.css +17 -17
  73. package/dist/C_ContextMenu.js.map +1 -1
  74. package/dist/C_ContextMenu2.js +1 -1
  75. package/dist/C_ContextMenu2.js.map +1 -1
  76. package/dist/{C_Cron-Civir5-I.css.map → C_Cron-BIQ2By9v.css.map} +1 -1
  77. package/dist/{C_Cron-iw3qpMsy.css.map → C_Cron-BNSAGD6A.css.map} +1 -1
  78. package/dist/C_Cron.css +57 -57
  79. package/dist/C_Cron.js.map +1 -1
  80. package/dist/C_Cron2.js +1 -1
  81. package/dist/C_Cron2.js.map +1 -1
  82. package/dist/C_Date.js.map +1 -1
  83. package/dist/C_Date2.js +1 -1
  84. package/dist/C_Date2.js.map +1 -1
  85. package/dist/{C_Draggable-BCjIvIwT.css.map → C_Draggable-BDAbk4s5.css.map} +1 -1
  86. package/dist/{C_Draggable-DwkSlCOS.css.map → C_Draggable-UhfDLXop.css.map} +1 -1
  87. package/dist/C_Draggable.css +46 -46
  88. package/dist/C_Draggable.js.map +1 -1
  89. package/dist/C_Draggable2.js +1 -1
  90. package/dist/C_Draggable2.js.map +1 -1
  91. package/dist/{C_Editor-BfjjYQ9B.css.map → C_Editor-CZOaChru.css.map} +1 -1
  92. package/dist/{C_Editor-Do2StvoJ.css.map → C_Editor-kJAQq5z6.css.map} +1 -1
  93. package/dist/C_Editor.css +14 -14
  94. package/dist/C_Editor.js.map +1 -1
  95. package/dist/C_Editor2.js +1 -1
  96. package/dist/C_Editor2.js.map +1 -1
  97. package/dist/{C_FilePreview-BhcbiXsV.css.map → C_FilePreview-Bs_omgJS.css.map} +1 -1
  98. package/dist/{C_FilePreview-DJudcIbW.css.map → C_FilePreview-DbwoyF2j.css.map} +1 -1
  99. package/dist/C_FilePreview.css +91 -91
  100. package/dist/C_FilePreview.js.map +1 -1
  101. package/dist/C_FilePreview2.js +1 -1
  102. package/dist/C_FilePreview2.js.map +1 -1
  103. package/dist/{C_Form-BtcAPIRi.css.map → C_Form-SCq-DZaZ.css.map} +1 -1
  104. package/dist/{C_Form-D_gwQ7hC.css.map → C_Form-mcd1nKvF.css.map} +1 -1
  105. package/dist/C_Form.css +223 -223
  106. package/dist/C_Form.js.map +1 -1
  107. package/dist/C_Form2.js +1 -1
  108. package/dist/C_Form2.js.map +1 -1
  109. package/dist/{C_FormSearch-Bi4XYjjk.css.map → C_FormSearch-C3F8peAY.css.map} +1 -1
  110. package/dist/{C_FormSearch-DUGOoX0u.css.map → C_FormSearch-qW56bJPo.css.map} +1 -1
  111. package/dist/C_FormSearch.css +45 -45
  112. package/dist/C_FormSearch.js.map +1 -1
  113. package/dist/C_FormSearch2.js +1 -1
  114. package/dist/C_FormSearch2.js.map +1 -1
  115. package/dist/{C_FormulaEditor-CJk3SSUJ.css.map → C_FormulaEditor-ChOvDbsZ.css.map} +1 -1
  116. package/dist/{C_FormulaEditor-Cy7mjfVO.css.map → C_FormulaEditor-mfiIUDY4.css.map} +1 -1
  117. package/dist/C_FormulaEditor.css +78 -78
  118. package/dist/C_FormulaEditor.js.map +1 -1
  119. package/dist/C_FormulaEditor2.js +1 -1
  120. package/dist/C_FormulaEditor2.js.map +1 -1
  121. package/dist/C_FullCalendar-C2nsqrgS.css.map +1 -0
  122. package/dist/C_FullCalendar-DdFtXVhy.css.map +1 -0
  123. package/dist/C_FullCalendar.css +2 -2
  124. package/dist/C_FullCalendar.js.map +1 -1
  125. package/dist/C_FullCalendar2.js +1 -1
  126. package/dist/C_FullCalendar2.js.map +1 -1
  127. package/dist/{C_GlobalSearch-B6wK3m3k.css.map → C_GlobalSearch-Dq4Wo01K.css.map} +1 -1
  128. package/dist/{C_GlobalSearch-DoPjldFm.css.map → C_GlobalSearch-RB7J43gu.css.map} +1 -1
  129. package/dist/C_GlobalSearch.css +112 -112
  130. package/dist/C_GlobalSearch.js.map +1 -1
  131. package/dist/C_GlobalSearch2.js +1 -1
  132. package/dist/C_GlobalSearch2.js.map +1 -1
  133. package/dist/C_Guide.js.map +1 -1
  134. package/dist/C_Guide2.js +1 -1
  135. package/dist/C_Guide2.js.map +1 -1
  136. package/dist/C_Icon.js.map +1 -1
  137. package/dist/C_Icon2.js.map +1 -1
  138. package/dist/{C_ImageCropper-BqZpkZfU.css.map → C_ImageCropper-CdTX2nxU.css.map} +1 -1
  139. package/dist/{C_ImageCropper-CylwGuzS.css.map → C_ImageCropper-ilOqPklJ.css.map} +1 -1
  140. package/dist/C_ImageCropper.css +23 -23
  141. package/dist/C_ImageCropper.js.map +1 -1
  142. package/dist/C_ImageCropper2.js +1 -1
  143. package/dist/C_ImageCropper2.js.map +1 -1
  144. package/dist/C_Language.js.map +1 -1
  145. package/dist/C_Language2.js +1 -1
  146. package/dist/C_Language2.js.map +1 -1
  147. package/dist/{C_Login-BkdnkBKX.css.map → C_Login-B3qYkLrN.css.map} +1 -1
  148. package/dist/{C_Login-VkMM6OJ2.css.map → C_Login-xMI1_ojE.css.map} +1 -1
  149. package/dist/C_Login.css +72 -72
  150. package/dist/C_Login.js.map +1 -1
  151. package/dist/C_Login2.js +1 -1
  152. package/dist/C_Login2.js.map +1 -1
  153. package/dist/{C_Map-DNnBcY70.css.map → C_Map-CWMMN58_.css.map} +1 -1
  154. package/dist/{C_Map-LEXIx6zM.css.map → C_Map-xSR2H-9o.css.map} +1 -1
  155. package/dist/C_Map.css +4 -4
  156. package/dist/C_Map.js.map +1 -1
  157. package/dist/C_Map2.js +1 -1
  158. package/dist/C_Map2.js.map +1 -1
  159. package/dist/{C_Markdown-DwmI0_0Q.css.map → C_Markdown-C7lTVJ1S.css.map} +1 -1
  160. package/dist/{C_Markdown-k0794RW0.css.map → C_Markdown-CZDm_baQ.css.map} +1 -1
  161. package/dist/C_Markdown.css +33 -33
  162. package/dist/C_Markdown.js.map +1 -1
  163. package/dist/C_Markdown2.js +1 -1
  164. package/dist/C_Markdown2.js.map +1 -1
  165. package/dist/C_Menu.js.map +1 -1
  166. package/dist/C_Menu2.js +1 -1
  167. package/dist/C_Menu2.js.map +1 -1
  168. package/dist/{C_NotificationCenter-DT6fQ79O.css.map → C_NotificationCenter-D7GGGWg7.css.map} +1 -1
  169. package/dist/{C_NotificationCenter-DbgBiyqB.css.map → C_NotificationCenter-SSmeHA45.css.map} +1 -1
  170. package/dist/C_NotificationCenter.css +89 -89
  171. package/dist/C_NotificationCenter.js.map +1 -1
  172. package/dist/C_NotificationCenter2.js +1 -1
  173. package/dist/C_NotificationCenter2.js.map +1 -1
  174. package/dist/C_OrgChart.js.map +1 -1
  175. package/dist/C_OrgChart2.js.map +1 -1
  176. package/dist/C_Progress.js.map +1 -1
  177. package/dist/C_Progress2.js +1 -1
  178. package/dist/C_Progress2.js.map +1 -1
  179. package/dist/{C_QRCode-CFNTda_1.css.map → C_QRCode-B_1lHUdx.css.map} +1 -1
  180. package/dist/{C_QRCode-CmWr9lK-.css.map → C_QRCode-CuQRYu0s.css.map} +1 -1
  181. package/dist/C_QRCode.css +9 -9
  182. package/dist/C_QRCode.js.map +1 -1
  183. package/dist/C_QRCode2.js +1 -1
  184. package/dist/C_QRCode2.js.map +1 -1
  185. package/dist/{C_Signature-BDx4ctsE.css.map → C_Signature-Bp-RBpAl.css.map} +1 -1
  186. package/dist/{C_Signature-Bz_uNbwv.css.map → C_Signature-Cb2VW1ok.css.map} +1 -1
  187. package/dist/C_Signature.css +15 -15
  188. package/dist/C_Signature.js.map +1 -1
  189. package/dist/C_Signature2.js +1 -1
  190. package/dist/C_Signature2.js.map +1 -1
  191. package/dist/C_Skeleton.js.map +1 -1
  192. package/dist/C_Skeleton2.js.map +1 -1
  193. package/dist/{C_SplitPane-BOwr1C7K.css.map → C_SplitPane-CgGWYsRE.css.map} +1 -1
  194. package/dist/{C_SplitPane-N-a_D-7F.css.map → C_SplitPane-DGf6WEeR.css.map} +1 -1
  195. package/dist/C_SplitPane.css +31 -31
  196. package/dist/C_SplitPane.js.map +1 -1
  197. package/dist/C_SplitPane2.js +1 -1
  198. package/dist/C_SplitPane2.js.map +1 -1
  199. package/dist/C_Steps-Buyg7Axn.css.map +1 -0
  200. package/dist/C_Steps-DNY91VbQ.css.map +1 -0
  201. package/dist/C_Steps.css +38 -38
  202. package/dist/C_Steps.js.map +1 -1
  203. package/dist/C_Steps2.js +1 -1
  204. package/dist/C_Steps2.js.map +1 -1
  205. package/dist/{C_Table-BcM5LqAM.css.map → C_Table--kbQaaBv.css.map} +1 -1
  206. package/dist/{C_Table-HATVoq1F.css.map → C_Table-D631kdXC.css.map} +1 -1
  207. package/dist/C_Table.css +104 -104
  208. package/dist/C_Table.js.map +1 -1
  209. package/dist/C_Table2.js +2 -2
  210. package/dist/C_Table2.js.map +1 -1
  211. package/dist/{C_TagsView-DX3LecK1.css.map → C_TagsView-COjGNM9h.css.map} +1 -1
  212. package/dist/{C_TagsView-DqOTa8bL.css.map → C_TagsView-zUDj9S06.css.map} +1 -1
  213. package/dist/C_TagsView.css +36 -36
  214. package/dist/C_TagsView.js.map +1 -1
  215. package/dist/C_TagsView2.js +1 -1
  216. package/dist/C_TagsView2.js.map +1 -1
  217. package/dist/C_Theme.js.map +1 -1
  218. package/dist/C_Theme2.js +1 -1
  219. package/dist/C_Theme2.js.map +1 -1
  220. package/dist/C_Time-BQ9PGy8B.css.map +1 -0
  221. package/dist/C_Time-CO73krC6.css.map +1 -0
  222. package/dist/C_Time.css +5 -5
  223. package/dist/C_Time.js.map +1 -1
  224. package/dist/C_Time2.js +1 -1
  225. package/dist/C_Time2.js.map +1 -1
  226. package/dist/{C_Timeline-BKkimrZx.css.map → C_Timeline-4rk0Dzgn.css.map} +1 -1
  227. package/dist/{C_Timeline-DTuSCX6p.css.map → C_Timeline-DdESmqwL.css.map} +1 -1
  228. package/dist/C_Timeline.css +45 -45
  229. package/dist/C_Timeline.js.map +1 -1
  230. package/dist/C_Timeline2.js +1 -1
  231. package/dist/C_Timeline2.js.map +1 -1
  232. package/dist/{C_Transfer-BOB6OBqS.css.map → C_Transfer-B-vjvhjI.css.map} +1 -1
  233. package/dist/{C_Transfer-Dpq7ezWC.css.map → C_Transfer-EzdHzZNv.css.map} +1 -1
  234. package/dist/C_Transfer.css +31 -31
  235. package/dist/C_Transfer.js.map +1 -1
  236. package/dist/C_Transfer2.js +1 -1
  237. package/dist/C_Transfer2.js.map +1 -1
  238. package/dist/{C_Tree-D98nX9qT.css.map → C_Tree-CsXgGfhn.css.map} +1 -1
  239. package/dist/{C_Tree-ulfm7b-P.css.map → C_Tree-P7eRpnOa.css.map} +1 -1
  240. package/dist/C_Tree.css +33 -33
  241. package/dist/C_Tree.js.map +1 -1
  242. package/dist/C_Tree2.js +1 -1
  243. package/dist/C_Tree2.js.map +1 -1
  244. package/dist/{C_Upload-BR9fg5r4.css.map → C_Upload-CHjiVVh7.css.map} +1 -1
  245. package/dist/{C_Upload-CPqf74Ea.css.map → C_Upload-DE3OLsZD.css.map} +1 -1
  246. package/dist/C_Upload.css +50 -50
  247. package/dist/C_Upload.js.map +1 -1
  248. package/dist/C_Upload2.js +2 -2
  249. package/dist/C_Upload2.js.map +1 -1
  250. package/dist/{C_VideoPlayer-4J96tKfK.css.map → C_VideoPlayer-CnaNOFtW.css.map} +1 -1
  251. package/dist/{C_VideoPlayer-D35seHkm.css.map → C_VideoPlayer-cnP88zNV.css.map} +1 -1
  252. package/dist/C_VideoPlayer.css +68 -68
  253. package/dist/C_VideoPlayer.js.map +1 -1
  254. package/dist/C_VideoPlayer2.js +3 -3
  255. package/dist/C_VideoPlayer2.js.map +1 -1
  256. package/dist/{C_VtableGantt-C2lxFmWg.css.map → C_VtableGantt-CZlJgvpC.css.map} +1 -1
  257. package/dist/{C_VtableGantt-Dwnkw_WL.css.map → C_VtableGantt-DKfQkql0.css.map} +1 -1
  258. package/dist/C_VtableGantt.css +15 -15
  259. package/dist/C_VtableGantt.js.map +1 -1
  260. package/dist/C_VtableGantt2.js +1 -1
  261. package/dist/C_VtableGantt2.js.map +1 -1
  262. package/dist/{C_WaterFall-C4HDqf-a.css.map → C_WaterFall-BJ_39ext.css.map} +1 -1
  263. package/dist/{C_WaterFall-HWB-gPON.css.map → C_WaterFall-cYc1vntE.css.map} +1 -1
  264. package/dist/C_WaterFall.css +16 -16
  265. package/dist/C_WaterFall.js.map +1 -1
  266. package/dist/C_WaterFall2.js +1 -1
  267. package/dist/C_WaterFall2.js.map +1 -1
  268. package/dist/{C_WorkFlow-2hJfvvTK.css.map → C_WorkFlow-BFzRGGhJ.css.map} +1 -1
  269. package/dist/{C_WorkFlow-DHoNjl8-.css.map → C_WorkFlow-DSyCOvRp.css.map} +1 -1
  270. package/dist/C_WorkFlow.css +193 -193
  271. package/dist/C_WorkFlow.js.map +1 -1
  272. package/dist/C_WorkFlow2.js +1 -1
  273. package/dist/C_WorkFlow2.js.map +1 -1
  274. package/dist/constants.d.ts +1 -1
  275. package/dist/constants2.d.ts +2 -2
  276. package/dist/constants3.d.ts +1 -1
  277. package/dist/constants4.d.ts +1 -1
  278. package/dist/constants5.d.ts +2 -2
  279. package/dist/data.d.ts +1 -1
  280. package/dist/index.vue.d.ts +2 -2
  281. package/dist/index11.vue.d.ts +2 -2
  282. package/dist/index12.vue.d.ts +1 -1
  283. package/dist/index13.vue.d.ts +2 -2
  284. package/dist/index14.vue.d.ts +3 -3
  285. package/dist/index15.vue.d.ts +6 -6
  286. package/dist/index17.vue.d.ts +1 -1
  287. package/dist/index18.vue.d.ts +2 -2
  288. package/dist/index2.vue.d.ts +6 -6
  289. package/dist/index20.vue.d.ts +1 -1
  290. package/dist/index21.vue.d.ts +2 -2
  291. package/dist/index22.vue.d.ts +2 -2
  292. package/dist/index24.vue.d.ts +1 -1
  293. package/dist/index26.vue.d.ts +3 -3
  294. package/dist/index27.vue.d.ts +1 -1
  295. package/dist/index28.vue.d.ts +2 -2
  296. package/dist/index3.vue.d.ts +2 -2
  297. package/dist/index4.vue.d.ts +2 -2
  298. package/dist/index6.vue.d.ts +3 -3
  299. package/dist/style.css +1991 -1991
  300. package/dist/useCalendarEvents.d.ts +1 -1
  301. package/dist/useCollapsePanel.d.ts +3 -3
  302. package/dist/useCropperCore.d.ts +4 -4
  303. package/dist/useDraggableLayout.d.ts +2 -2
  304. package/dist/useDynamicFormState.d.ts +13 -13
  305. package/dist/useEdgeInteraction.d.ts +1 -1
  306. package/dist/useInfiniteScroll.d.ts +3 -3
  307. package/dist/useModalEdit.d.ts +3 -3
  308. package/dist/useQRCode.d.ts +3 -3
  309. package/dist/useSignatureHistory.d.ts +1 -1
  310. package/dist/useSplitResize.d.ts +5 -5
  311. package/dist/useTimeSelection.d.ts +2 -2
  312. package/dist/useTreeOperations.d.ts +4 -4
  313. package/dist/useWorkflowValidation.d.ts +4 -4
  314. package/package.json +4 -7
  315. package/dist/C_ActionBar-DYG0Yf3A.css.map +0 -1
  316. package/dist/C_ActionBar-MAjRhqcI.css.map +0 -1
  317. package/dist/C_Cascade-Dq0S5Jkm.css.map +0 -1
  318. package/dist/C_Cascade-IUUHIh7r.css.map +0 -1
  319. package/dist/C_Code-BFi5xxnM.css.map +0 -1
  320. package/dist/C_Code-CZ7yfnri.css.map +0 -1
  321. package/dist/C_FullCalendar-BQA0OjGB.css.map +0 -1
  322. package/dist/C_FullCalendar-ChJUosAi.css.map +0 -1
  323. package/dist/C_Steps-Bk1krgiR.css.map +0 -1
  324. package/dist/C_Steps-Dn2CMpy1.css.map +0 -1
  325. package/dist/C_Time-BzyQVvTS.css.map +0 -1
  326. package/dist/C_Time-DmpKLQHc.css.map +0 -1
  327. package/dist/themes/glass-morphism.css +0 -1
@@ -1,11 +1,11 @@
1
1
  /* unplugin-vue-components disabled *//* 电子签名组件样式 */
2
- .c-signature[data-v-fbc647a9] {
2
+ .c-signature[data-v-d7438dde] {
3
3
  display: flex;
4
4
  flex-direction: column;
5
5
  gap: 12px;
6
6
  width: 100%;
7
7
  }
8
- .c-signature .signature-toolbar[data-v-fbc647a9] {
8
+ .c-signature .signature-toolbar[data-v-d7438dde] {
9
9
  display: flex;
10
10
  align-items: center;
11
11
  gap: 12px;
@@ -15,29 +15,29 @@
15
15
  border-radius: var(--c-radius, 6px);
16
16
  flex-wrap: wrap;
17
17
  }
18
- .c-signature .signature-toolbar .toolbar-section[data-v-fbc647a9] {
18
+ .c-signature .signature-toolbar .toolbar-section[data-v-d7438dde] {
19
19
  display: flex;
20
20
  align-items: center;
21
21
  gap: 8px;
22
22
  }
23
- .c-signature .signature-toolbar .toolbar-section.divider[data-v-fbc647a9] {
23
+ .c-signature .signature-toolbar .toolbar-section.divider[data-v-d7438dde] {
24
24
  width: 1px;
25
25
  height: 24px;
26
26
  background: var(--c-border, #e1e4e8);
27
27
  margin: 0 4px;
28
28
  }
29
- .c-signature .signature-toolbar .toolbar-section .section-label[data-v-fbc647a9] {
29
+ .c-signature .signature-toolbar .toolbar-section .section-label[data-v-d7438dde] {
30
30
  font-size: 13px;
31
31
  color: var(--c-text-3, #999);
32
32
  font-weight: 500;
33
33
  white-space: nowrap;
34
34
  flex-shrink: 0;
35
35
  }
36
- .c-signature .signature-toolbar .toolbar-section .n-color-picker[data-v-fbc647a9] {
36
+ .c-signature .signature-toolbar .toolbar-section .n-color-picker[data-v-d7438dde] {
37
37
  width: 90px !important;
38
38
  flex-shrink: 0;
39
39
  }
40
- .c-signature .signature-canvas-wrapper[data-v-fbc647a9] {
40
+ .c-signature .signature-canvas-wrapper[data-v-d7438dde] {
41
41
  position: relative;
42
42
  border: 1px solid var(--c-border, #e1e4e8);
43
43
  border-radius: var(--c-radius, 6px);
@@ -45,28 +45,28 @@
45
45
  background: var(--c-bg, #fff);
46
46
  transition: border-color 0.3s;
47
47
  }
48
- .c-signature .signature-canvas-wrapper[data-v-fbc647a9]:hover {
48
+ .c-signature .signature-canvas-wrapper[data-v-d7438dde]:hover {
49
49
  border-color: var(--c-primary, #409eff);
50
50
  }
51
- .c-signature .signature-canvas-wrapper.disabled[data-v-fbc647a9] {
51
+ .c-signature .signature-canvas-wrapper.disabled[data-v-d7438dde] {
52
52
  opacity: 0.6;
53
53
  cursor: not-allowed;
54
54
  border-color: var(--c-border, #e1e4e8);
55
55
  }
56
- .c-signature .signature-canvas-wrapper.readonly[data-v-fbc647a9] {
56
+ .c-signature .signature-canvas-wrapper.readonly[data-v-d7438dde] {
57
57
  cursor: default;
58
58
  }
59
- .c-signature .signature-canvas-wrapper .signature-canvas[data-v-fbc647a9] {
59
+ .c-signature .signature-canvas-wrapper .signature-canvas[data-v-d7438dde] {
60
60
  display: block;
61
61
  width: 100%;
62
62
  height: 100%;
63
63
  cursor: crosshair;
64
64
  touch-action: none;
65
65
  }
66
- .c-signature .signature-canvas-wrapper .signature-canvas.disabled[data-v-fbc647a9], .c-signature .signature-canvas-wrapper .signature-canvas.readonly[data-v-fbc647a9] {
66
+ .c-signature .signature-canvas-wrapper .signature-canvas.disabled[data-v-d7438dde], .c-signature .signature-canvas-wrapper .signature-canvas.readonly[data-v-d7438dde] {
67
67
  cursor: not-allowed;
68
68
  }
69
- .c-signature .signature-canvas-wrapper .canvas-placeholder[data-v-fbc647a9] {
69
+ .c-signature .signature-canvas-wrapper .canvas-placeholder[data-v-d7438dde] {
70
70
  position: absolute;
71
71
  top: 50%;
72
72
  left: 50%;
@@ -76,10 +76,10 @@
76
76
  pointer-events: none;
77
77
  user-select: none;
78
78
  }
79
- .c-signature .signature-actions[data-v-fbc647a9] {
79
+ .c-signature .signature-actions[data-v-d7438dde] {
80
80
  display: flex;
81
81
  justify-content: flex-end;
82
82
  gap: 8px;
83
83
  }
84
84
 
85
- /*# sourceMappingURL=C_Signature-BDx4ctsE.css.map*/
85
+ /*# sourceMappingURL=C_Signature-Bp-RBpAl.css.map*/
@@ -1 +1 @@
1
- {"version":3,"file":"C_Signature.js","names":[],"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"],"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"],"mappings":"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"}
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,2 +1,2 @@
1
- import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{computed as n,createCommentVNode as r,createElementBlock as i,createElementVNode as a,createTextVNode as o,createVNode as s,defineComponent as c,normalizeClass as l,normalizeStyle as u,onMounted as d,onUnmounted as f,openBlock as p,reactive as m,readonly as h,ref as g,toRef as _,unref as v,withCtx as y}from"vue";import{NButton as b,NButtonGroup as x,NColorPicker as S,NInputNumber as C}from"naive-ui";function w(e){let{canvasRef:t,penConfig:n,mode:r,disabled:i,onStrokeComplete:a,onDrawStart:o,onDrawing:s}=e,c=g(!1),l=g([]),u=null,d=()=>{let e=t.value;if(!e||(u=e.getContext(`2d`,{willReadFrequently:!0}),!u))return;let n=window.devicePixelRatio||1,r=e.getBoundingClientRect();e.width=r.width*n,e.height=r.height*n,e.style.width=`${r.width}px`,e.style.height=`${r.height}px`,u.scale(n,n),u.lineCap=`round`,u.lineJoin=`round`},f=e=>{let n=t.value;if(!n)return{x:0,y:0};let r=n.getBoundingClientRect(),i,a;if(`touches`in e&&e.touches.length>0)({clientX:i,clientY:a}=e.touches[0]);else if(`clientX`in e)({clientX:i,clientY:a}=e);else return{x:0,y:0};return{x:i-r.left,y:a-r.top,timestamp:Date.now()}},p=(e,t,n,r=!1)=>{u&&(u.save(),r?(u.globalCompositeOperation=`destination-out`,u.lineWidth=20):(u.globalCompositeOperation=`source-over`,u.strokeStyle=n.color,u.lineWidth=n.width,u.globalAlpha=n.opacity),u.beginPath(),u.moveTo(e.x,e.y),u.lineTo(t.x,t.y),u.stroke(),u.restore())},m=e=>{if(i.value)return;e.preventDefault(),c.value=!0,l.value=[];let t=f(e);l.value.push(t),o()},_=e=>{if(!c.value||i.value)return;e.preventDefault();let t=f(e),a=l.value[l.value.length-1];a&&p(a,t,n.value,r.value===`eraser`),l.value.push(t),s(t)},v=e=>{!c.value||i.value||(e.preventDefault(),c.value=!1,l.value.length>0&&(a({points:[...l.value],color:n.value.color,width:n.value.width,opacity:n.value.opacity,mode:r.value}),l.value=[]))};return{isDrawing:h(c),initCanvas:d,bindEvents:()=>{let e=t.value;e&&(e.addEventListener(`mousedown`,m),e.addEventListener(`mousemove`,_),e.addEventListener(`mouseup`,v),e.addEventListener(`mouseleave`,v),e.addEventListener(`touchstart`,m,{passive:!1}),e.addEventListener(`touchmove`,_,{passive:!1}),e.addEventListener(`touchend`,v),e.addEventListener(`touchcancel`,v))},unbindEvents:()=>{let e=t.value;e&&(e.removeEventListener(`mousedown`,m),e.removeEventListener(`mousemove`,_),e.removeEventListener(`mouseup`,v),e.removeEventListener(`mouseleave`,v),e.removeEventListener(`touchstart`,m),e.removeEventListener(`touchmove`,_),e.removeEventListener(`touchend`,v),e.removeEventListener(`touchcancel`,v))},redrawStrokes:e=>{if(!u||!t.value)return;let n=t.value;u.clearRect(0,0,n.width,n.height),e.forEach(e=>{for(let t=1;t<e.points.length;t++)p(e.points[t-1],e.points[t],{color:e.color,width:e.width,opacity:e.opacity},e.mode===`eraser`)})},clearCanvas:()=>{!u||!t.value||u.clearRect(0,0,t.value.width,t.value.height)}}}function T(e={}){let{maxHistory:t=50,onChange:r}=e,i=g([]),a=g([]),o=g(-1),s=n(()=>o.value>0),c=n(()=>o.value<a.value.length-1),l=e=>{i.value.push(e),u()},u=()=>{a.value=a.value.slice(0,o.value+1),a.value.push([...i.value]),o.value++,a.value.length>t&&(a.value.shift(),o.value--),r?.(i.value)},d=()=>s.value?(o.value--,i.value=[...a.value[o.value]],r?.(i.value),!0):!1,f=()=>c.value?(o.value++,i.value=[...a.value[o.value]],r?.(i.value),!0):!1,p=()=>{i.value=[],a.value=[[]],o.value=0,r?.(i.value)},m=e=>{i.value=[...e],a.value=[[...e]],o.value=0,r?.(i.value)},_=n(()=>i.value.length===0);return a.value=[[]],o.value=0,{strokes:h(i),canUndo:h(s),canRedo:h(c),isEmpty:h(_),addStroke:l,undo:d,redo:f,clear:p,loadData:m}}function E(e){let{canvasRef:t,watermark:n}=e,r=(e,t,n,r)=>{let i={"top-left":{x:10,y:n+10},"top-right":{x:e.width-t-10,y:n+10},"bottom-left":{x:10,y:e.height-10},"bottom-right":{x:e.width-t-10,y:e.height-10}};return i[r]||i[`bottom-right`]},i=(e,t)=>{let i=e.getContext(`2d`);if(!i||!n?.value?.show)return;let a={fontSize:n.value.fontSize||12,color:n.value.color||`#999999`,position:n.value.position||`bottom-right`};i.save(),i.font=`${a.fontSize}px Arial`,i.fillStyle=a.color,i.textBaseline=`bottom`;let o=i.measureText(t).width,{x:s,y:c}=r(e,o,a.fontSize,a.position);i.fillText(t,s,c),i.restore()},a=(e,t,n)=>{let r=document.createElement(`canvas`);r.width=e.width,r.height=e.height;let i=r.getContext(`2d`);if(!i)throw Error(`无法创建临时 Canvas`);return t&&(i.fillStyle=n,i.fillRect(0,0,r.width,r.height)),i.drawImage(e,0,0),{canvas:r,ctx:i}},o=(e,t)=>{let{includeBackground:r=!1,backgroundColor:o=`#FFFFFF`,includeWatermark:s=!1}=t,{canvas:c}=a(e,r,o);return s&&n?.value?.text&&i(c,n.value.text),c},s=(e,t)=>new Promise((n,r)=>{e.toBlob(e=>e?n(e):r(Error(`导出失败`)),`image/png`,t)}),c=e=>{let t=e.getContext(`2d`);if(!t)return!0;let{data:n}=t.getImageData(0,0,e.width,e.height);return!n.some(e=>e!==0)},l=async(e={})=>{let n=t.value;if(!n)throw Error(`Canvas 未初始化`);if(c(n))throw Error(`签名为空,请先签名后再导出`);let{format:r=`png`,quality:i=.92}=e;if(r===`svg`)return`data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><text>SVG export placeholder</text></svg>`;let a=o(n,e);if(r===`blob`)return s(a,i);let l=r===`jpeg`?`image/jpeg`:`image/png`;return a.toDataURL(l,i)};return{exportSignature:l,download:async(e=`signature`,t={})=>{let n=t.format||`png`,r=await l({...t,format:n});if(r instanceof Blob){let t=URL.createObjectURL(r),i=document.createElement(`a`);i.href=t,i.download=`${e}.${n}`,i.click(),URL.revokeObjectURL(t)}else if(typeof r==`string`){let t=document.createElement(`a`);t.href=r,t.download=`${e}.${n}`,t.click()}},loadImage:async e=>{let n=t.value;if(!n)throw Error(`Canvas 未初始化`);let r=n.getContext(`2d`);if(!r)throw Error(`无法获取 Canvas 上下文`);return new Promise((t,i)=>{let a=new Image;a.crossOrigin=`anonymous`,a.onload=()=>{r.clearRect(0,0,n.width,n.height),r.drawImage(a,0,0,n.width,n.height),t()},a.onerror=()=>i(Error(`图片加载失败: ${e}`)),a.src=e})}}}const D={color:`#000000`,width:2,opacity:1},O={show:!1,text:``,fontSize:12,color:`#999999`,position:`bottom-right`},k=[`#000000`,`#FF0000`,`#0000FF`,`#00AA00`,`#FF6600`,`#9900FF`],A={class:`c-signature`},j={key:0,class:`signature-toolbar`},M={class:`toolbar-section`},ee={key:0,class:`toolbar-section`},te={key:1,class:`toolbar-section`},ne={class:`toolbar-section`},re={class:`toolbar-section`},N={key:0,class:`canvas-placeholder`};var P=t(c({name:`C_Signature`,__name:`index`,props:{width:{default:`100%`},height:{default:300},penConfig:{},eraserConfig:{},disabled:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},backgroundImage:{},backgroundColor:{},watermark:{},showToolbar:{type:Boolean,default:!0},maxHistory:{default:50}},emits:[`start-draw`,`drawing`,`end-draw`,`clear`,`undo`,`redo`,`change`],setup(t,{expose:n,emit:c}){let h=t,P=c,F=g(null),I=g(`pen`),L=m({...D,...h.penConfig}),R=m({...O,...h.watermark}),{strokes:z,canUndo:B,canRedo:V,isEmpty:H,addStroke:U,undo:W,redo:G,clear:K,loadData:q}=T({maxHistory:h.maxHistory,onChange:e=>{J.redrawStrokes(e),P(`change`,e)}}),J=w({canvasRef:F,penConfig:_(L),mode:I,disabled:_(h,`disabled`),onStrokeComplete:e=>{U(e),P(`end-draw`,e)},onDrawStart:()=>P(`start-draw`),onDrawing:e=>P(`drawing`,e)}),Y=E({canvasRef:F,watermark:_(R)}),X=()=>{let e=W();return e&&P(`undo`),e},Z=()=>{let e=G();return e&&P(`redo`),e},Q=()=>{K(),J.clearCanvas(),P(`clear`)},ie=async e=>Y.exportSignature(e),ae=async(e,t)=>Y.download(e,t),$=async e=>{await Y.loadImage(e),K()};return d(()=>{J.initCanvas(),J.bindEvents(),h.backgroundImage&&$(h.backgroundImage)}),f(()=>J.unbindEvents()),n({clear:Q,undo:X,redo:Z,export:ie,download:ae,loadImage:$,getSignatureData:()=>z.value,loadSignatureData:e=>q(e),isEmpty:()=>H.value}),(t,n)=>(p(),i(`div`,A,[t.showToolbar?(p(),i(`div`,j,[a(`div`,M,[s(v(x),null,{default:y(()=>[s(v(b),{type:I.value===`pen`?`primary`:`default`,size:`small`,onClick:n[0]||=e=>I.value=`pen`},{icon:y(()=>[s(e,{name:`mdi:draw`,size:16,color:`currentColor`})]),default:y(()=>[n[4]||=o(` 画笔 `,-1)]),_:1,__:[4]},8,[`type`]),s(v(b),{type:I.value===`eraser`?`primary`:`default`,size:`small`,onClick:n[1]||=e=>I.value=`eraser`},{icon:y(()=>[s(e,{name:`mdi:eraser`,size:16,color:`currentColor`})]),default:y(()=>[n[5]||=o(` 橡皮擦 `,-1)]),_:1,__:[5]},8,[`type`])]),_:1})]),n[11]||=a(`div`,{class:`toolbar-section divider`},null,-1),I.value===`pen`?(p(),i(`div`,ee,[n[6]||=a(`span`,{class:`section-label`},`颜色`,-1),s(v(S),{value:L.color,"onUpdate:value":n[2]||=e=>L.color=e,"show-alpha":!1,size:`small`,swatches:v(k)},null,8,[`value`,`swatches`])])):r(`v-if`,!0),I.value===`pen`?(p(),i(`div`,te,[n[7]||=a(`span`,{class:`section-label`},`粗细`,-1),s(v(C),{value:L.width,"onUpdate:value":n[3]||=e=>L.width=e,min:1,max:20,size:`small`,style:{width:`80px`}},null,8,[`value`])])):r(`v-if`,!0),n[12]||=a(`div`,{class:`toolbar-section divider`},null,-1),a(`div`,ne,[s(v(b),{size:`small`,disabled:!v(B),onClick:X},{icon:y(()=>[s(e,{name:`mdi:undo`,size:16,color:`currentColor`})]),default:y(()=>[n[8]||=o(` 撤销 `,-1)]),_:1,__:[8]},8,[`disabled`]),s(v(b),{size:`small`,disabled:!v(V),onClick:Z},{icon:y(()=>[s(e,{name:`mdi:redo`,size:16,color:`currentColor`})]),default:y(()=>[n[9]||=o(` 重做 `,-1)]),_:1,__:[9]},8,[`disabled`])]),n[13]||=a(`div`,{class:`toolbar-section divider`},null,-1),a(`div`,re,[s(v(b),{size:`small`,type:`error`,disabled:v(H),onClick:Q},{icon:y(()=>[s(e,{name:`mdi:delete-outline`,size:16,color:`currentColor`})]),default:y(()=>[n[10]||=o(` 清空 `,-1)]),_:1,__:[10]},8,[`disabled`])])])):r(`v-if`,!0),a(`div`,{class:l([`signature-canvas-wrapper`,{disabled:t.disabled,readonly:t.readonly}]),style:u({width:typeof t.width==`number`?`${t.width}px`:t.width,height:typeof t.height==`number`?`${t.height}px`:t.height,backgroundColor:t.backgroundColor||`transparent`})},[a(`canvas`,{ref_key:`canvasRef`,ref:F,class:l([`signature-canvas`,{disabled:t.disabled,readonly:t.readonly}])},null,2),v(H)&&!t.disabled&&!t.readonly?(p(),i(`div`,N,` 请在此处签名 `)):r(`v-if`,!0)],6)]))}}),[[`__scopeId`,`data-v-fbc647a9`]]);export{w as i,E as n,T as r,P as t};
1
+ import{t as e}from"./C_Icon2.js";import{t}from"./export-helper.js";import{NButton as n,NButtonGroup as r,NColorPicker as i,NInputNumber as a}from"naive-ui";import{computed as o,createCommentVNode as s,createElementBlock as c,createElementVNode as l,createTextVNode as u,createVNode as d,defineComponent as f,normalizeClass as p,normalizeStyle as m,onMounted as h,onUnmounted as g,openBlock as _,reactive as v,readonly as y,ref as b,toRef as x,unref as S,withCtx as C}from"vue";function w(e){let{canvasRef:t,penConfig:n,mode:r,disabled:i,onStrokeComplete:a,onDrawStart:o,onDrawing:s}=e,c=b(!1),l=b([]),u=null,d=()=>{let e=t.value;if(!e||(u=e.getContext(`2d`,{willReadFrequently:!0}),!u))return;let n=window.devicePixelRatio||1,r=e.getBoundingClientRect();e.width=r.width*n,e.height=r.height*n,e.style.width=`${r.width}px`,e.style.height=`${r.height}px`,u.scale(n,n),u.lineCap=`round`,u.lineJoin=`round`},f=e=>{let n=t.value;if(!n)return{x:0,y:0};let r=n.getBoundingClientRect(),i,a;if(`touches`in e&&e.touches.length>0)({clientX:i,clientY:a}=e.touches[0]);else if(`clientX`in e)({clientX:i,clientY:a}=e);else return{x:0,y:0};return{x:i-r.left,y:a-r.top,timestamp:Date.now()}},p=(e,t,n,r=!1)=>{u&&(u.save(),r?(u.globalCompositeOperation=`destination-out`,u.lineWidth=20):(u.globalCompositeOperation=`source-over`,u.strokeStyle=n.color,u.lineWidth=n.width,u.globalAlpha=n.opacity),u.beginPath(),u.moveTo(e.x,e.y),u.lineTo(t.x,t.y),u.stroke(),u.restore())},m=e=>{if(i.value)return;e.preventDefault(),c.value=!0,l.value=[];let t=f(e);l.value.push(t),o()},h=e=>{if(!c.value||i.value)return;e.preventDefault();let t=f(e),a=l.value[l.value.length-1];a&&p(a,t,n.value,r.value===`eraser`),l.value.push(t),s(t)},g=e=>{!c.value||i.value||(e.preventDefault(),c.value=!1,l.value.length>0&&(a({points:[...l.value],color:n.value.color,width:n.value.width,opacity:n.value.opacity,mode:r.value}),l.value=[]))};return{isDrawing:y(c),initCanvas:d,bindEvents:()=>{let e=t.value;e&&(e.addEventListener(`mousedown`,m),e.addEventListener(`mousemove`,h),e.addEventListener(`mouseup`,g),e.addEventListener(`mouseleave`,g),e.addEventListener(`touchstart`,m,{passive:!1}),e.addEventListener(`touchmove`,h,{passive:!1}),e.addEventListener(`touchend`,g),e.addEventListener(`touchcancel`,g))},unbindEvents:()=>{let e=t.value;e&&(e.removeEventListener(`mousedown`,m),e.removeEventListener(`mousemove`,h),e.removeEventListener(`mouseup`,g),e.removeEventListener(`mouseleave`,g),e.removeEventListener(`touchstart`,m),e.removeEventListener(`touchmove`,h),e.removeEventListener(`touchend`,g),e.removeEventListener(`touchcancel`,g))},redrawStrokes:e=>{if(!u||!t.value)return;let n=t.value;u.clearRect(0,0,n.width,n.height),e.forEach(e=>{for(let t=1;t<e.points.length;t++)p(e.points[t-1],e.points[t],{color:e.color,width:e.width,opacity:e.opacity},e.mode===`eraser`)})},clearCanvas:()=>{!u||!t.value||u.clearRect(0,0,t.value.width,t.value.height)}}}function T(e={}){let{maxHistory:t=50,onChange:n}=e,r=b([]),i=b([]),a=b(-1),s=o(()=>a.value>0),c=o(()=>a.value<i.value.length-1),l=e=>{r.value.push(e),u()},u=()=>{i.value=i.value.slice(0,a.value+1),i.value.push([...r.value]),a.value++,i.value.length>t&&(i.value.shift(),a.value--),n?.(r.value)},d=()=>s.value?(a.value--,r.value=[...i.value[a.value]],n?.(r.value),!0):!1,f=()=>c.value?(a.value++,r.value=[...i.value[a.value]],n?.(r.value),!0):!1,p=()=>{r.value=[],i.value=[[]],a.value=0,n?.(r.value)},m=e=>{r.value=[...e],i.value=[[...e]],a.value=0,n?.(r.value)},h=o(()=>r.value.length===0);return i.value=[[]],a.value=0,{strokes:y(r),canUndo:y(s),canRedo:y(c),isEmpty:y(h),addStroke:l,undo:d,redo:f,clear:p,loadData:m}}function E(e){let{canvasRef:t,watermark:n}=e,r=(e,t,n,r)=>{let i={"top-left":{x:10,y:n+10},"top-right":{x:e.width-t-10,y:n+10},"bottom-left":{x:10,y:e.height-10},"bottom-right":{x:e.width-t-10,y:e.height-10}};return i[r]||i[`bottom-right`]},i=(e,t)=>{let i=e.getContext(`2d`);if(!i||!n?.value?.show)return;let a={fontSize:n.value.fontSize||12,color:n.value.color||`#999999`,position:n.value.position||`bottom-right`};i.save(),i.font=`${a.fontSize}px Arial`,i.fillStyle=a.color,i.textBaseline=`bottom`;let o=i.measureText(t).width,{x:s,y:c}=r(e,o,a.fontSize,a.position);i.fillText(t,s,c),i.restore()},a=(e,t,n)=>{let r=document.createElement(`canvas`);r.width=e.width,r.height=e.height;let i=r.getContext(`2d`);if(!i)throw Error(`无法创建临时 Canvas`);return t&&(i.fillStyle=n,i.fillRect(0,0,r.width,r.height)),i.drawImage(e,0,0),{canvas:r,ctx:i}},o=(e,t)=>{let{includeBackground:r=!1,backgroundColor:o=`#FFFFFF`,includeWatermark:s=!1}=t,{canvas:c}=a(e,r,o);return s&&n?.value?.text&&i(c,n.value.text),c},s=(e,t)=>new Promise((n,r)=>{e.toBlob(e=>e?n(e):r(Error(`导出失败`)),`image/png`,t)}),c=e=>{let t=e.getContext(`2d`);if(!t)return!0;let{data:n}=t.getImageData(0,0,e.width,e.height);return!n.some(e=>e!==0)},l=async(e={})=>{let n=t.value;if(!n)throw Error(`Canvas 未初始化`);if(c(n))throw Error(`签名为空,请先签名后再导出`);let{format:r=`png`,quality:i=.92}=e;if(r===`svg`)return`data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><text>SVG export placeholder</text></svg>`;let a=o(n,e);if(r===`blob`)return s(a,i);let l=r===`jpeg`?`image/jpeg`:`image/png`;return a.toDataURL(l,i)};return{exportSignature:l,download:async(e=`signature`,t={})=>{let n=t.format||`png`,r=await l({...t,format:n});if(r instanceof Blob){let t=URL.createObjectURL(r),i=document.createElement(`a`);i.href=t,i.download=`${e}.${n}`,i.click(),URL.revokeObjectURL(t)}else if(typeof r==`string`){let t=document.createElement(`a`);t.href=r,t.download=`${e}.${n}`,t.click()}},loadImage:async e=>{let n=t.value;if(!n)throw Error(`Canvas 未初始化`);let r=n.getContext(`2d`);if(!r)throw Error(`无法获取 Canvas 上下文`);return new Promise((t,i)=>{let a=new Image;a.crossOrigin=`anonymous`,a.onload=()=>{r.clearRect(0,0,n.width,n.height),r.drawImage(a,0,0,n.width,n.height),t()},a.onerror=()=>i(Error(`图片加载失败: ${e}`)),a.src=e})}}}const ee={color:`#000000`,width:2,opacity:1},te={show:!1,text:``,fontSize:12,color:`#999999`,position:`bottom-right`},D=[`#000000`,`#FF0000`,`#0000FF`,`#00AA00`,`#FF6600`,`#9900FF`],O={class:`c-signature`},k={key:0,class:`signature-toolbar`},A={class:`toolbar-section`},j={key:0,class:`toolbar-section`},M={key:1,class:`toolbar-section`},N={class:`toolbar-section`},ne={class:`toolbar-section`},re={key:0,class:`canvas-placeholder`};var P=t(f({name:`C_Signature`,__name:`index`,props:{width:{default:`100%`},height:{default:300},penConfig:{},eraserConfig:{},disabled:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},backgroundImage:{},backgroundColor:{},watermark:{},showToolbar:{type:Boolean,default:!0},maxHistory:{default:50}},emits:[`start-draw`,`drawing`,`end-draw`,`clear`,`undo`,`redo`,`change`],setup(t,{expose:o,emit:f}){let y=t,P=f,F=b(null),I=b(`pen`),L=v({...ee,...y.penConfig}),R=v({...te,...y.watermark}),{strokes:z,canUndo:B,canRedo:V,isEmpty:H,addStroke:U,undo:W,redo:G,clear:K,loadData:q}=T({maxHistory:y.maxHistory,onChange:e=>{J.redrawStrokes(e),P(`change`,e)}}),J=w({canvasRef:F,penConfig:x(L),mode:I,disabled:x(y,`disabled`),onStrokeComplete:e=>{U(e),P(`end-draw`,e)},onDrawStart:()=>P(`start-draw`),onDrawing:e=>P(`drawing`,e)}),Y=E({canvasRef:F,watermark:x(R)}),X=()=>{let e=W();return e&&P(`undo`),e},Z=()=>{let e=G();return e&&P(`redo`),e},Q=()=>{K(),J.clearCanvas(),P(`clear`)},ie=async e=>Y.exportSignature(e),ae=async(e,t)=>Y.download(e,t),$=async e=>{await Y.loadImage(e),K()};return h(()=>{J.initCanvas(),J.bindEvents(),y.backgroundImage&&$(y.backgroundImage)}),g(()=>J.unbindEvents()),o({clear:Q,undo:X,redo:Z,export:ie,download:ae,loadImage:$,getSignatureData:()=>z.value,loadSignatureData:e=>q(e),isEmpty:()=>H.value}),(t,o)=>(_(),c(`div`,O,[t.showToolbar?(_(),c(`div`,k,[l(`div`,A,[d(S(r),null,{default:C(()=>[d(S(n),{type:I.value===`pen`?`primary`:`default`,size:`small`,onClick:o[0]||=e=>I.value=`pen`},{icon:C(()=>[d(e,{name:`mdi:draw`,size:16,color:`currentColor`})]),default:C(()=>[o[4]||=u(` 画笔 `,-1)]),_:1,__:[4]},8,[`type`]),d(S(n),{type:I.value===`eraser`?`primary`:`default`,size:`small`,onClick:o[1]||=e=>I.value=`eraser`},{icon:C(()=>[d(e,{name:`mdi:eraser`,size:16,color:`currentColor`})]),default:C(()=>[o[5]||=u(` 橡皮擦 `,-1)]),_:1,__:[5]},8,[`type`])]),_:1})]),o[11]||=l(`div`,{class:`toolbar-section divider`},null,-1),I.value===`pen`?(_(),c(`div`,j,[o[6]||=l(`span`,{class:`section-label`},`颜色`,-1),d(S(i),{value:L.color,"onUpdate:value":o[2]||=e=>L.color=e,"show-alpha":!1,size:`small`,swatches:S(D)},null,8,[`value`,`swatches`])])):s(`v-if`,!0),I.value===`pen`?(_(),c(`div`,M,[o[7]||=l(`span`,{class:`section-label`},`粗细`,-1),d(S(a),{value:L.width,"onUpdate:value":o[3]||=e=>L.width=e,min:1,max:20,size:`small`,style:{width:`80px`}},null,8,[`value`])])):s(`v-if`,!0),o[12]||=l(`div`,{class:`toolbar-section divider`},null,-1),l(`div`,N,[d(S(n),{size:`small`,disabled:!S(B),onClick:X},{icon:C(()=>[d(e,{name:`mdi:undo`,size:16,color:`currentColor`})]),default:C(()=>[o[8]||=u(` 撤销 `,-1)]),_:1,__:[8]},8,[`disabled`]),d(S(n),{size:`small`,disabled:!S(V),onClick:Z},{icon:C(()=>[d(e,{name:`mdi:redo`,size:16,color:`currentColor`})]),default:C(()=>[o[9]||=u(` 重做 `,-1)]),_:1,__:[9]},8,[`disabled`])]),o[13]||=l(`div`,{class:`toolbar-section divider`},null,-1),l(`div`,ne,[d(S(n),{size:`small`,type:`error`,disabled:S(H),onClick:Q},{icon:C(()=>[d(e,{name:`mdi:delete-outline`,size:16,color:`currentColor`})]),default:C(()=>[o[10]||=u(` 清空 `,-1)]),_:1,__:[10]},8,[`disabled`])])])):s(`v-if`,!0),l(`div`,{class:p([`signature-canvas-wrapper`,{disabled:t.disabled,readonly:t.readonly}]),style:m({width:typeof t.width==`number`?`${t.width}px`:t.width,height:typeof t.height==`number`?`${t.height}px`:t.height,backgroundColor:t.backgroundColor||`transparent`})},[l(`canvas`,{ref_key:`canvasRef`,ref:F,class:p([`signature-canvas`,{disabled:t.disabled,readonly:t.readonly}])},null,2),S(H)&&!t.disabled&&!t.readonly?(_(),c(`div`,re,` 请在此处签名 `)):s(`v-if`,!0)],6)]))}}),[[`__scopeId`,`data-v-d7438dde`]]);export{w as i,E as n,T as r,P as t};
2
2
  //# sourceMappingURL=C_Signature2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"C_Signature2.js","names":[],"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"],"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"],"mappings":"6dAmBA,SAAgB,EAAmB,EAAoC,CACrE,GAAM,CACJ,YACA,YACA,OACA,WACA,mBACA,cACA,aACE,EAEE,EAAY,EAAI,GAAM,CACtB,EAAgB,EAAsB,EAAE,CAAC,CAC3C,EAAuC,KAErC,MAAmB,CACvB,IAAM,EAAS,EAAU,MAGzB,GAFI,CAAC,IACL,EAAM,EAAO,WAAW,KAAM,CAAE,mBAAoB,GAAM,CAAC,CACvD,CAAC,GAAK,OACV,IAAM,EAAM,OAAO,kBAAoB,EACjC,EAAO,EAAO,uBAAuB,CAC3C,EAAO,MAAQ,EAAK,MAAQ,EAC5B,EAAO,OAAS,EAAK,OAAS,EAC9B,EAAO,MAAM,MAAQ,GAAG,EAAK,MAAM,IACnC,EAAO,MAAM,OAAS,GAAG,EAAK,OAAO,IACrC,EAAI,MAAM,EAAK,EAAI,CACnB,EAAI,QAAU,QACd,EAAI,SAAW,SAGX,EAAqB,GAA+C,CACxE,IAAM,EAAS,EAAU,MACzB,GAAI,CAAC,EAAQ,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,CAClC,IAAM,EAAO,EAAO,uBAAuB,CACvC,EACA,EACJ,GAAI,YAAa,GAAK,EAAE,QAAQ,OAAS,GACtC,sBAAuB,EAAE,QAAQ,YACzB,YAAa,GACrB,sBAAuB,QAExB,MAAO,CAAE,EAAG,EAAG,EAAG,EAAG,CAEvB,MAAO,CACL,EAAG,EAAU,EAAK,KAClB,EAAG,EAAU,EAAK,IAClB,UAAW,KAAK,KAAK,CACtB,EAGG,GACJ,EACA,EACA,EACA,EAAa,KACV,CACE,IACL,EAAI,MAAM,CACN,GACF,EAAI,yBAA2B,kBAC/B,EAAI,UAAY,KAEhB,EAAI,yBAA2B,cAC/B,EAAI,YAAc,EAAO,MACzB,EAAI,UAAY,EAAO,MACvB,EAAI,YAAc,EAAO,SAE3B,EAAI,WAAW,CACf,EAAI,OAAO,EAAK,EAAG,EAAK,EAAE,CAC1B,EAAI,OAAO,EAAG,EAAG,EAAG,EAAE,CACtB,EAAI,QAAQ,CACZ,EAAI,SAAS,GAGT,EAAgB,GAA+B,CACnD,GAAI,EAAS,MAAO,OACpB,EAAE,gBAAgB,CAClB,EAAU,MAAQ,GAClB,EAAc,MAAQ,EAAE,CACxB,IAAM,EAAQ,EAAkB,EAAE,CAClC,EAAc,MAAM,KAAK,EAAM,CAC/B,GAAa,EAGT,EAAQ,GAA+B,CAC3C,GAAI,CAAC,EAAU,OAAS,EAAS,MAAO,OACxC,EAAE,gBAAgB,CAClB,IAAM,EAAQ,EAAkB,EAAE,CAC5B,EAAY,EAAc,MAAM,EAAc,MAAM,OAAS,GAC/D,GACF,EAAW,EAAW,EAAO,EAAU,MAAO,EAAK,QAAU,SAAS,CAExE,EAAc,MAAM,KAAK,EAAM,CAC/B,EAAU,EAAM,EAGZ,EAAc,GAA+B,CAC7C,CAAC,EAAU,OAAS,EAAS,QACjC,EAAE,gBAAgB,CAClB,EAAU,MAAQ,GACd,EAAc,MAAM,OAAS,IAQ/B,EAPgC,CAC9B,OAAQ,CAAC,GAAG,EAAc,MAAM,CAChC,MAAO,EAAU,MAAM,MACvB,MAAO,EAAU,MAAM,MACvB,QAAS,EAAU,MAAM,QACzB,KAAM,EAAK,MACZ,CACuB,CACxB,EAAc,MAAQ,EAAE,IAmD5B,MAAO,CACL,UAAW,EAAS,EAAU,CAC9B,aACA,eA7BuB,CACvB,IAAM,EAAS,EAAU,MACpB,IACL,EAAO,iBAAiB,YAAa,EAAa,CAClD,EAAO,iBAAiB,YAAa,EAAK,CAC1C,EAAO,iBAAiB,UAAW,EAAW,CAC9C,EAAO,iBAAiB,aAAc,EAAW,CACjD,EAAO,iBAAiB,aAAc,EAAc,CAAE,QAAS,GAAO,CAAC,CACvE,EAAO,iBAAiB,YAAa,EAAM,CAAE,QAAS,GAAO,CAAC,CAC9D,EAAO,iBAAiB,WAAY,EAAW,CAC/C,EAAO,iBAAiB,cAAe,EAAW,GAoBlD,iBAjByB,CACzB,IAAM,EAAS,EAAU,MACpB,IACL,EAAO,oBAAoB,YAAa,EAAa,CACrD,EAAO,oBAAoB,YAAa,EAAK,CAC7C,EAAO,oBAAoB,UAAW,EAAW,CACjD,EAAO,oBAAoB,aAAc,EAAW,CACpD,EAAO,oBAAoB,aAAc,EAAa,CACtD,EAAO,oBAAoB,YAAa,EAAK,CAC7C,EAAO,oBAAoB,WAAY,EAAW,CAClD,EAAO,oBAAoB,cAAe,EAAW,GAQrD,cApDqB,GAA+B,CACpD,GAAI,CAAC,GAAO,CAAC,EAAU,MAAO,OAC9B,IAAM,EAAS,EAAU,MACzB,EAAI,UAAU,EAAG,EAAG,EAAO,MAAO,EAAO,OAAO,CAChD,EAAQ,QAAS,GAAW,CAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IACxC,EACE,EAAO,OAAO,EAAI,GAClB,EAAO,OAAO,GACd,CAAE,MAAO,EAAO,MAAO,MAAO,EAAO,MAAO,QAAS,EAAO,QAAS,CACrE,EAAO,OAAS,SACjB,EAEH,EAwCF,gBArCwB,CACpB,CAAC,GAAO,CAAC,EAAU,OACvB,EAAI,UAAU,EAAG,EAAG,EAAU,MAAM,MAAO,EAAU,MAAM,OAAO,EAoCnE,CCnLH,SAAgB,EAAoB,EAAsC,EAAE,CAAE,CAC5E,GAAM,CAAE,aAAa,GAAI,YAAa,EAEhC,EAAU,EAAuB,EAAE,CAAC,CACpC,EAAe,EAAyB,EAAE,CAAC,CAC3C,EAAe,EAAI,GAAG,CAEtB,EAAU,MAAe,EAAa,MAAQ,EAAE,CAChD,EAAU,MACR,EAAa,MAAQ,EAAa,MAAM,OAAS,EACxD,CAEK,EAAa,GAA4B,CAC7C,EAAQ,MAAM,KAAK,EAAO,CAC1B,GAAe,EAGX,MAAsB,CAC1B,EAAa,MAAQ,EAAa,MAAM,MAAM,EAAG,EAAa,MAAQ,EAAE,CACxE,EAAa,MAAM,KAAK,CAAC,GAAG,EAAQ,MAAM,CAAC,CAC3C,EAAa,QACT,EAAa,MAAM,OAAS,IAC9B,EAAa,MAAM,OAAO,CAC1B,EAAa,SAEf,IAAW,EAAQ,MAAM,EAGrB,MACC,EAAQ,OACb,EAAa,QACb,EAAQ,MAAQ,CAAC,GAAG,EAAa,MAAM,EAAa,OAAO,CAC3D,IAAW,EAAQ,MAAM,CAClB,IAJoB,GAOvB,MACC,EAAQ,OACb,EAAa,QACb,EAAQ,MAAQ,CAAC,GAAG,EAAa,MAAM,EAAa,OAAO,CAC3D,IAAW,EAAQ,MAAM,CAClB,IAJoB,GAOvB,MAAc,CAClB,EAAQ,MAAQ,EAAE,CAClB,EAAa,MAAQ,CAAC,EAAE,CAAC,CACzB,EAAa,MAAQ,EACrB,IAAW,EAAQ,MAAM,EAGrB,EAAY,GAA4B,CAC5C,EAAQ,MAAQ,CAAC,GAAG,EAAK,CACzB,EAAa,MAAQ,CAAC,CAAC,GAAG,EAAK,CAAC,CAChC,EAAa,MAAQ,EACrB,IAAW,EAAQ,MAAM,EAGrB,EAAU,MAAe,EAAQ,MAAM,SAAW,EAAE,CAM1D,MAHA,GAAa,MAAQ,CAAC,EAAE,CAAC,CACzB,EAAa,MAAQ,EAEd,CACL,QAAS,EAAS,EAAQ,CAC1B,QAAS,EAAS,EAAQ,CAC1B,QAAS,EAAS,EAAQ,CAC1B,QAAS,EAAS,EAAQ,CAC1B,YACA,OACA,OACA,QACA,WACD,CCvEH,SAAgB,EAAmB,EAAoC,CACrE,GAAM,CAAE,YAAW,aAAc,EAE3B,GACJ,EACA,EACA,EACA,IAC6B,CAC7B,IACM,EAAY,CAChB,WAAY,CAAE,EAAG,GAAS,EAAG,EAAW,GAAS,CACjD,YAAa,CACX,EAAG,EAAO,MAAQ,EAAY,GAC9B,EAAG,EAAW,GACf,CACD,cAAe,CAAE,EAAG,GAAS,EAAG,EAAO,OAAS,GAAS,CACzD,eAAgB,CACd,EAAG,EAAO,MAAQ,EAAY,GAC9B,EAAG,EAAO,OAAS,GACpB,CACF,CACD,OACE,EAAU,IAAuC,EAAU,iBAIzD,GAAiB,EAA2B,IAAuB,CACvE,IAAM,EAAM,EAAO,WAAW,KAAK,CACnC,GAAI,CAAC,GAAO,CAAC,GAAW,OAAO,KAAM,OACrC,IAAM,EAAS,CACb,SAAU,EAAU,MAAM,UAAY,GACtC,MAAO,EAAU,MAAM,OAAS,UAChC,SAAU,EAAU,MAAM,UAAY,eACvC,CACD,EAAI,MAAM,CACV,EAAI,KAAO,GAAG,EAAO,SAAS,UAC9B,EAAI,UAAY,EAAO,MACvB,EAAI,aAAe,SACnB,IAAM,EAAY,EAAI,YAAY,EAAK,CAAC,MAClC,CAAE,IAAG,KAAM,EACf,EACA,EACA,EAAO,SACP,EAAO,SACR,CACD,EAAI,SAAS,EAAM,EAAG,EAAE,CACxB,EAAI,SAAS,EAGT,GACJ,EACA,EACA,IACG,CACH,IAAM,EAAa,SAAS,cAAc,SAAS,CACnD,EAAW,MAAQ,EAAa,MAChC,EAAW,OAAS,EAAa,OACjC,IAAM,EAAU,EAAW,WAAW,KAAK,CAC3C,GAAI,CAAC,EAAS,MAAU,MAAM,gBAAgB,CAM9C,OALI,IACF,EAAQ,UAAY,EACpB,EAAQ,SAAS,EAAG,EAAG,EAAW,MAAO,EAAW,OAAO,EAE7D,EAAQ,UAAU,EAAc,EAAG,EAAE,CAC9B,CAAE,OAAQ,EAAY,IAAK,EAAS,EAGvC,GACJ,EACA,IACsB,CACtB,GAAM,CACJ,oBAAoB,GACpB,kBAAkB,UAClB,mBAAmB,IACjB,EACE,CAAE,OAAQ,GAAe,EAC7B,EACA,EACA,EACD,CAMD,OAHI,GAAoB,GAAW,OAAO,MACxC,EAAc,EAAY,EAAU,MAAM,KAAK,CAE1C,GAGH,GACJ,EACA,IAEO,IAAI,SAAe,EAAS,IAAW,CAC5C,EAAO,OACL,GAAS,EAAO,EAAQ,EAAK,CAAG,EAAW,MAAM,OAAO,CAAC,CACzD,YACA,EACD,EACD,CAGE,EAAiB,GAAuC,CAC5D,IAAM,EAAM,EAAO,WAAW,KAAK,CACnC,GAAI,CAAC,EAAK,MAAO,GACjB,GAAM,CAAE,QAAS,EAAI,aAAa,EAAG,EAAG,EAAO,MAAO,EAAO,OAAO,CACpE,MAAO,CAAC,EAAK,KAAK,GAAK,IAAM,EAAE,EAG3B,EAAkB,MACtB,EAAyB,EAAE,GACA,CAC3B,IAAM,EAAS,EAAU,MACzB,GAAI,CAAC,EAAQ,MAAU,MAAM,cAAc,CAC3C,GAAI,EAAc,EAAO,CAAE,MAAU,MAAM,gBAAgB,CAC3D,GAAM,CAAE,SAAS,MAAO,UAAU,KAAS,EAC3C,GAAI,IAAW,MACb,MAAO,qHAET,IAAM,EAAa,EAAoB,EAAQ,EAAQ,CACvD,GAAI,IAAW,OAAQ,OAAO,EAAa,EAAY,EAAQ,CAC/D,IAAM,EAAW,IAAW,OAAS,aAAe,YACpD,OAAO,EAAW,UAAU,EAAU,EAAQ,EA0ChD,MAAO,CAAE,kBAAiB,SAvCT,MACf,EAAW,YACX,EAAyB,EAAE,GACT,CAClB,IAAM,EAAS,EAAQ,QAAU,MAC3B,EAAS,MAAM,EAAgB,CAAE,GAAG,EAAS,SAAQ,CAAC,CAC5D,GAAI,aAAkB,KAAM,CAC1B,IAAM,EAAM,IAAI,gBAAgB,EAAO,CACjC,EAAO,SAAS,cAAc,IAAI,CACxC,EAAK,KAAO,EACZ,EAAK,SAAW,GAAG,EAAS,GAAG,IAC/B,EAAK,OAAO,CACZ,IAAI,gBAAgB,EAAI,SACf,OAAO,GAAW,SAAU,CACrC,IAAM,EAAO,SAAS,cAAc,IAAI,CACxC,EAAK,KAAO,EACZ,EAAK,SAAW,GAAG,EAAS,GAAG,IAC/B,EAAK,OAAO,GAsBoB,UAlBlB,KAAO,IAAoC,CAC3D,IAAM,EAAS,EAAU,MACzB,GAAI,CAAC,EAAQ,MAAU,MAAM,cAAc,CAC3C,IAAM,EAAM,EAAO,WAAW,KAAK,CACnC,GAAI,CAAC,EAAK,MAAU,MAAM,kBAAkB,CAC5C,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAM,IAAI,MAChB,EAAI,YAAc,YAClB,EAAI,WAAe,CACjB,EAAI,UAAU,EAAG,EAAG,EAAO,MAAO,EAAO,OAAO,CAChD,EAAI,UAAU,EAAK,EAAG,EAAG,EAAO,MAAO,EAAO,OAAO,CACrD,GAAS,EAEX,EAAI,YAAgB,EAAW,MAAM,WAAW,IAAW,CAAC,CAC5D,EAAI,IAAM,GACV,EAG2C,CC9KjD,MAAa,EAAgC,CAC3C,MAAO,UACP,MAAO,EACP,QAAS,EACV,CAIY,EAA4C,CACvD,KAAM,GACN,KAAM,GACN,SAAU,GACV,MAAO,UACP,SAAU,eACX,CAEY,EAAgB,CAC3B,UACA,UACA,UACA,UACA,UACA,UACD,upBCiHD,IAAM,EAAQ,EASR,EAAO,EAUP,EAAY,EAA8B,KAAK,CAC/C,EAAc,EAAa,MAAM,CACjC,EAAmB,EAAoB,CAC3C,GAAG,EACH,GAAG,EAAM,UACV,CAAC,CACI,EAAmB,EAA0B,CACjD,GAAG,EACH,GAAG,EAAM,UACV,CAAC,CAEI,CACJ,UACA,UACA,UACA,UACA,YACA,OACA,OACA,QACA,YACE,EAAoB,CACtB,WAAY,EAAM,WAClB,SAAW,GAAS,CAClB,EAAe,cAAc,EAA0B,CACvD,EAAK,SAAU,EAA0B,EAE5C,CAAC,CAEI,EAAiB,EAAmB,CACxC,YACA,UAAW,EAAM,EAAiB,CAClC,KAAM,EACN,SAAU,EAAM,EAAO,WAAW,CAClC,iBAAmB,GAA4B,CAC7C,EAAU,EAAO,CACjB,EAAK,WAAY,EAAO,EAE1B,gBAAmB,EAAK,aAAa,CACrC,UAAY,GAA0B,EAAK,UAAW,EAAM,CAC7D,CAAC,CAEI,EAAiB,EAAmB,CACxC,YACA,UAAW,EAAM,EAAiB,CACnC,CAAC,CAEI,MAA4B,CAChC,IAAM,EAAS,GAAM,CAErB,OADI,GAAQ,EAAK,OAAO,CACjB,GAGH,MAA4B,CAChC,IAAM,EAAS,GAAM,CAErB,OADI,GAAQ,EAAK,OAAO,CACjB,GAGH,MAAoB,CACxB,GAAO,CACP,EAAe,aAAa,CAC5B,EAAK,QAAQ,EAGT,GAAkB,KACtB,IAEO,EAAe,gBAAgB,EAAQ,CAG1C,GAAW,MACf,EACA,IAEO,EAAe,SAAS,EAAU,EAAQ,CAG7C,EAAY,KAAO,IAAoC,CAC3D,MAAM,EAAe,UAAU,EAAS,CACxC,GAAO,SAQT,MAAgB,CACd,EAAe,YAAY,CAC3B,EAAe,YAAY,CACvB,EAAM,iBAAiB,EAAU,EAAM,gBAAgB,EAC3D,CAEF,MAAkB,EAAe,cAAc,CAAC,CAEhD,EAA8B,CAC5B,MAAO,EACP,KAAM,EACN,KAAM,EACN,OAAQ,GACR,YACA,YACA,qBAnBA,EAAQ,MAoBR,kBAnByB,GAAkC,EAAS,EAAK,CAoBzE,YAnBsC,EAAQ,MAoB/C,CAAC,aA/PA,EAsGK,MAtGL,EAsGK,CArGQ,EAAA,aAAA,GAAA,CAAX,EAiFK,MAjFL,EAiFK,CAhFH,EAuBK,MAvBL,EAuBK,CAtBH,EAqBc,EAAA,EAAA,CAAA,KAAA,eAXH,CATT,EASS,EAAA,EAAA,CAAA,CARN,KAAM,EAAA,QAAW,MAAA,UAAA,UAClB,KAAK,QACJ,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAW,QAER,KAAI,MAC4C,CAAzD,EAAyD,EAAA,CAAjD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFY,OAEZ,GAAA,CAAA,CAAA,yBACA,EASS,EAAA,EAAA,CAAA,CARN,KAAM,EAAA,QAAW,SAAA,UAAA,UAClB,KAAK,QACJ,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAW,WAER,KAAI,MAC8C,CAA3D,EAA2D,EAAA,CAAnD,KAAK,aAAc,KAAM,GAAI,MAAM,iCAG/C,CAAA,AAAA,EAAA,KAAA,EAFY,QAEZ,GAAA,CAAA,CAAA,2CAIJ,EAAsC,MAAA,CAAjC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEzB,EAAA,QAAW,OAAA,GAAA,CAAtB,EAQK,MARL,GAQK,CAAA,AAAA,EAAA,KAPH,EAAoC,OAAA,CAA9B,MAAM,gBAAe,CAAC,KAAE,GAAA,CAC9B,EAKC,EAAA,EAAA,CAAA,CAJS,MAAO,EAAiB,iCAAjB,EAAiB,MAAK,EACpC,aAAY,GACb,KAAK,QACJ,SAAU,EAAA,EAAa,+CAIjB,EAAA,QAAW,OAAA,GAAA,CAAtB,EASK,MATL,GASK,CAAA,AAAA,EAAA,KARH,EAAoC,OAAA,CAA9B,MAAM,gBAAe,CAAC,KAAE,GAAA,CAC9B,EAMC,EAAA,EAAA,CAAA,CALS,MAAO,EAAiB,iCAAjB,EAAiB,MAAK,EACpC,IAAK,EACL,IAAK,GACN,KAAK,QACL,MAAA,CAAA,MAAA,OAAkB,4CAItB,EAAsC,MAAA,CAAjC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEpC,EAaK,MAbL,GAaK,CAZH,EAKS,EAAA,EAAA,CAAA,CALA,KAAK,QAAS,SAAQ,CAAG,EAAA,EAAO,CAAG,QAAO,IACtC,KAAI,MAC4C,CAAzD,EAAyD,EAAA,CAAjD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFY,OAEZ,GAAA,CAAA,CAAA,6BACA,EAKS,EAAA,EAAA,CAAA,CALA,KAAK,QAAS,SAAQ,CAAG,EAAA,EAAO,CAAG,QAAO,IACtC,KAAI,MAC4C,CAAzD,EAAyD,EAAA,CAAjD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFY,OAEZ,GAAA,CAAA,CAAA,uCAGF,EAAsC,MAAA,CAAjC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEpC,EAYK,MAZL,GAYK,CAXH,EAUS,EAAA,EAAA,CAAA,CATP,KAAK,QACL,KAAK,QACJ,SAAU,EAAA,EAAO,CACjB,QAAO,IAEG,KAAI,MACsD,CAAnE,EAAmE,EAAA,CAA3D,KAAK,qBAAsB,KAAM,GAAI,MAAM,iCAGvD,CAAA,AAAA,EAAA,MAAA,EAFY,OAEZ,GAAA,CAAA,CAAA,gDAIJ,EAiBK,MAAA,CAhBH,MAAK,EAAA,CAAC,2BAAyB,CAAA,SACrB,EAAA,SAAQ,SAAE,EAAA,SAAQ,CAAA,CAAA,CAC3B,MAAK,EAAA,cAAE,EAAA,OAAA,SAAA,GAAA,EAAA,MAAA,IAAA,EAAA,oBAAA,EAAA,QAAA,SAAA,GAAA,EAAA,OAAA,IAAA,EAAA,uBAAA,EAAA,iBAAA,kBAMR,EAIC,SAAA,SAHK,YAAJ,IAAI,EACJ,MAAK,EAAA,CAAC,mBAAiB,CAAA,SACb,EAAA,SAAQ,SAAE,EAAA,SAAQ,CAAA,CAAA,UAEnB,EAAA,EAAO,EAAA,CAAK,EAAA,UAAQ,CAAK,EAAA,UAAA,GAAA,CAApC,EAEK,MAFL,EAAwE,WAExE,EAAA,EAAA,OAAA,GAAA,CAAA,CAAA,EAAA,CAAA,CAAA"}
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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"}