@robot-admin/naive-ui-components 0.6.28 → 0.6.30
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.
- package/dist/C_Chat-CJ8KESTM.css.map +1 -0
- package/dist/C_Chat-DzV4AFLd.css.map +1 -0
- package/dist/C_Chat.css +14 -8
- package/dist/{C_CollapsePanel-CWkFCqNQ.css.map → C_CollapsePanel-BkOivqn3.css.map} +1 -1
- package/dist/{C_CollapsePanel-pcVJA_4z.css.map → C_CollapsePanel-CedsEM0N.css.map} +1 -1
- package/dist/C_CollapsePanel.css +35 -35
- package/dist/C_CollapsePanel.js.map +1 -1
- package/dist/C_CollapsePanel2.js +1 -1
- package/dist/C_CollapsePanel2.js.map +1 -1
- package/dist/C_Editor-C49qURgb.css.map +1 -0
- package/dist/C_Editor-DuxBD9Qg.css.map +1 -0
- package/dist/C_Editor.css +60 -29
- package/dist/C_Editor.js.map +1 -1
- package/dist/C_Editor2.js +1 -1
- package/dist/C_Editor2.js.map +1 -1
- package/dist/C_Guide.d.cts +2 -2
- package/dist/C_Guide.d.ts +2 -2
- package/dist/C_Guide.js.map +1 -1
- package/dist/C_Guide2.js +1 -1
- package/dist/C_Guide2.js.map +1 -1
- package/dist/C_Markdown-7J0uPEuk.css.map +1 -0
- package/dist/C_Markdown-C7Lg0_9z.css.map +1 -0
- package/dist/C_Markdown.css +16 -10
- package/dist/C_OrgChart-ChZu346B.css.map +1 -0
- package/dist/C_OrgChart-DqBufOv5.css.map +1 -0
- package/dist/C_OrgChart.cjs +1 -0
- package/dist/C_OrgChart.css +282 -0
- package/dist/C_OrgChart.d.cts +2 -0
- package/dist/C_OrgChart.d.ts +2 -0
- package/dist/C_OrgChart.js +1 -0
- package/dist/C_OrgChart.js.map +1 -0
- package/dist/C_OrgChart2.js +2 -0
- package/dist/C_OrgChart2.js.map +1 -0
- package/dist/C_Progress.d.cts +1 -1
- package/dist/C_Progress.d.ts +1 -1
- package/dist/C_Signature.js.map +1 -1
- package/dist/C_Signature2.js.map +1 -1
- package/dist/C_Skeleton-BNPbaut7.css.map +1 -0
- package/dist/C_Skeleton-Djsjw8XY.css.map +1 -0
- package/dist/C_Skeleton.cjs +1 -0
- package/dist/C_Skeleton.css +253 -0
- package/dist/C_Skeleton.d.cts +2 -0
- package/dist/C_Skeleton.d.ts +2 -0
- package/dist/C_Skeleton.js +1 -0
- package/dist/C_Skeleton.js.map +1 -0
- package/dist/C_Skeleton2.js +2 -0
- package/dist/C_Skeleton2.js.map +1 -0
- package/dist/C_Steps.d.cts +1 -1
- package/dist/C_Steps.d.ts +1 -1
- package/dist/C_Table-B8hpzOcR.css.map +1 -0
- package/dist/C_Table-CGP3n_u0.css.map +1 -0
- package/dist/C_Table.css +94 -69
- package/dist/C_Table.d.cts +2 -2
- package/dist/C_Table.d.ts +2 -2
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +1 -1
- package/dist/C_Table2.js.map +1 -1
- package/dist/C_TagsView.d.cts +1 -1
- package/dist/C_TagsView.d.ts +1 -1
- package/dist/C_Theme.d.cts +1 -1
- package/dist/C_Theme.d.ts +1 -1
- package/dist/{C_Timeline-BKkimrZx.css.map → C_Timeline-DG70WtJP.css.map} +1 -1
- package/dist/{C_Timeline-DTuSCX6p.css.map → C_Timeline-Dzxmmdjg.css.map} +1 -1
- package/dist/C_Timeline.css +45 -45
- package/dist/C_Timeline.d.cts +1 -1
- package/dist/C_Timeline.d.ts +1 -1
- package/dist/C_Timeline.js.map +1 -1
- package/dist/C_Timeline2.js +1 -1
- package/dist/C_Timeline2.js.map +1 -1
- package/dist/C_Transfer.d.cts +1 -1
- package/dist/C_Transfer.d.ts +1 -1
- package/dist/{C_Upload-S30RmC9t.css.map → C_Upload-CFAxVGVz.css.map} +1 -1
- package/dist/{C_Upload-i8LB_29U.css.map → C_Upload-D8_QeSV0.css.map} +1 -1
- package/dist/C_Upload.css +14 -9
- package/dist/C_Upload.js.map +1 -1
- package/dist/C_Upload2.js +1 -1
- package/dist/C_Upload2.js.map +1 -1
- package/dist/C_VtableGantt.d.cts +1 -1
- package/dist/C_VtableGantt.d.ts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants2.d.ts +2 -2
- package/dist/constants3.d.ts +3 -3
- package/dist/constants4.d.ts +5 -5
- package/dist/constants5.d.ts +2 -2
- package/dist/data.d.ts +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -20
- package/dist/index.d.ts +22 -20
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index13.vue.d.ts +3 -3
- package/dist/index14.vue.d.ts +85 -7
- package/dist/index15.vue.d.ts +6 -6
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index18.vue.d.ts +4 -4
- package/dist/index20.vue.d.ts +87 -40
- package/dist/index21.vue.d.ts +47 -27
- package/dist/index22.vue.d.ts +95 -79
- package/dist/index23.vue.d.ts +24 -7
- package/dist/index24.vue.d.ts +76 -100
- package/dist/index25.vue.d.ts +7 -70
- package/dist/index26.vue.d.ts +99 -649
- package/dist/index27.vue.d.ts +81 -0
- package/dist/index28.vue.d.ts +662 -0
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.ts +6 -6
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index8.vue.d.ts +1 -1
- package/dist/resolver.cjs +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.d.cts +1 -1
- package/dist/resolver.d.ts +1 -1
- package/dist/resolver.js +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +832 -220
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.ts +8 -8
- package/dist/useCropperCore.d.ts +4 -4
- package/dist/useDraggableLayout.d.ts +8 -8
- package/dist/useDynamicFormState.d.ts +10 -10
- package/dist/useEdgeInteraction.d.ts +1 -1
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.ts +2 -2
- package/dist/useModalEdit.d.ts +52 -6
- package/dist/useQRCode.d.ts +5 -5
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +3 -3
- package/dist/useSplitResize.d.ts +8 -8
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +4 -4
- package/dist/useWorkflowValidation.d.ts +2 -2
- package/package.json +5 -1
- package/dist/C_Chat-CcdWgVE8.css.map +0 -1
- package/dist/C_Chat-Cx0woEEe.css.map +0 -1
- package/dist/C_Editor-D0_6UhIa.css.map +0 -1
- package/dist/C_Editor-OlxIF9-5.css.map +0 -1
- package/dist/C_Markdown-7iBnLDtL.css.map +0 -1
- package/dist/C_Markdown-BbTvdFCl.css.map +0 -1
- package/dist/C_Table-vZlcgH6x.css.map +0 -1
- package/dist/C_Table-wzAO43l0.css.map +0 -1
package/dist/C_Signature.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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","../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","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_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","../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'\r\nimport type { ExportOptions, WatermarkConfig } from '../types'\r\n\r\ninterface UseSignatureExportOptions {\r\n canvasRef: Ref<HTMLCanvasElement | null>\r\n watermark?: Ref<Partial<WatermarkConfig>>\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport function useSignatureExport(options: UseSignatureExportOptions) {\r\n const { canvasRef, watermark } = options\r\n\r\n const getWatermarkPosition = (\r\n canvas: HTMLCanvasElement,\r\n textWidth: number,\r\n fontSize: number,\r\n position: string\r\n ): { x: number; y: number } => {\r\n const padding = 10\r\n const positions = {\r\n 'top-left': { x: padding, y: fontSize + padding },\r\n 'top-right': {\r\n x: canvas.width - textWidth - padding,\r\n y: fontSize + padding,\r\n },\r\n 'bottom-left': { x: padding, y: canvas.height - padding },\r\n 'bottom-right': {\r\n x: canvas.width - textWidth - padding,\r\n y: canvas.height - padding,\r\n },\r\n }\r\n return (\r\n positions[position as keyof typeof positions] || positions['bottom-right']\r\n )\r\n }\r\n\r\n const drawWatermark = (canvas: HTMLCanvasElement, text: string): void => {\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx || !watermark?.value?.show) return\r\n const config = {\r\n fontSize: watermark.value.fontSize || 12,\r\n color: watermark.value.color || '#999999',\r\n position: watermark.value.position || 'bottom-right',\r\n }\r\n ctx.save()\r\n ctx.font = `${config.fontSize}px Arial`\r\n ctx.fillStyle = config.color\r\n ctx.textBaseline = 'bottom'\r\n const textWidth = ctx.measureText(text).width\r\n const { x, y } = getWatermarkPosition(\r\n canvas,\r\n textWidth,\r\n config.fontSize,\r\n config.position\r\n )\r\n ctx.fillText(text, x, y)\r\n ctx.restore()\r\n }\r\n\r\n const createTempCanvas = (\r\n sourceCanvas: HTMLCanvasElement,\r\n includeBackground: boolean,\r\n backgroundColor: string\r\n ) => {\r\n const tempCanvas = document.createElement('canvas')\r\n tempCanvas.width = sourceCanvas.width\r\n tempCanvas.height = sourceCanvas.height\r\n const tempCtx = tempCanvas.getContext('2d')\r\n if (!tempCtx) throw new Error('无法创建临时 Canvas')\r\n if (includeBackground) {\r\n tempCtx.fillStyle = backgroundColor\r\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height)\r\n }\r\n tempCtx.drawImage(sourceCanvas, 0, 0)\r\n return { canvas: tempCanvas, ctx: tempCtx }\r\n }\r\n\r\n const prepareExportCanvas = (\r\n canvas: HTMLCanvasElement,\r\n options: ExportOptions\r\n ): HTMLCanvasElement => {\r\n const {\r\n includeBackground = false,\r\n backgroundColor = '#FFFFFF',\r\n includeWatermark = false,\r\n } = options\r\n const { canvas: tempCanvas } = createTempCanvas(\r\n canvas,\r\n includeBackground,\r\n backgroundColor\r\n )\r\n // includeWatermark 为 true 时才叠加水印,无视 watermark.show 的状态\r\n // 这样「不含水印导出」即使组件配置了水印也不会叠加\r\n if (includeWatermark && watermark?.value?.text) {\r\n drawWatermark(tempCanvas, watermark.value.text)\r\n }\r\n return tempCanvas\r\n }\r\n\r\n const exportToBlob = (\r\n canvas: HTMLCanvasElement,\r\n quality: number\r\n ): Promise<Blob> => {\r\n return new Promise<Blob>((resolve, reject) => {\r\n canvas.toBlob(\r\n blob => (blob ? resolve(blob) : reject(new Error('导出失败'))),\r\n 'image/png',\r\n quality\r\n )\r\n })\r\n }\r\n\r\n const isCanvasEmpty = (canvas: HTMLCanvasElement): boolean => {\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return true\r\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height)\r\n return !data.some(v => v !== 0)\r\n }\r\n\r\n const exportSignature = async (\r\n options: ExportOptions = {}\r\n ): Promise<string | Blob> => {\r\n const canvas = canvasRef.value\r\n if (!canvas) throw new Error('Canvas 未初始化')\r\n if (isCanvasEmpty(canvas)) throw new Error('签名为空,请先签名后再导出')\r\n const { format = 'png', quality = 0.92 } = options\r\n if (format === 'svg') {\r\n return 'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\"><text>SVG export placeholder</text></svg>'\r\n }\r\n const tempCanvas = prepareExportCanvas(canvas, options)\r\n if (format === 'blob') return exportToBlob(tempCanvas, quality)\r\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'\r\n return tempCanvas.toDataURL(mimeType, quality)\r\n }\r\n\r\n const download = async (\r\n filename = 'signature',\r\n options: ExportOptions = {}\r\n ): Promise<void> => {\r\n const format = options.format || 'png'\r\n const result = await exportSignature({ ...options, format })\r\n if (result instanceof Blob) {\r\n const url = URL.createObjectURL(result)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `${filename}.${format}`\r\n link.click()\r\n URL.revokeObjectURL(url)\r\n } else if (typeof result === 'string') {\r\n const link = document.createElement('a')\r\n link.href = result\r\n link.download = `${filename}.${format}`\r\n link.click()\r\n }\r\n }\r\n\r\n const loadImage = async (imageUrl: string): Promise<void> => {\r\n const canvas = canvasRef.value\r\n if (!canvas) throw new Error('Canvas 未初始化')\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) throw new Error('无法获取 Canvas 上下文')\r\n return new Promise((resolve, reject) => {\r\n const img = new Image()\r\n img.crossOrigin = 'anonymous'\r\n img.onload = () => {\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n resolve()\r\n }\r\n img.onerror = () => reject(new Error(`图片加载失败: ${imageUrl}`))\r\n img.src = imageUrl\r\n })\r\n }\r\n\r\n return { exportSignature, download, loadImage }\r\n}\r\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","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
package/dist/C_Signature2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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","../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","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\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,GAAgC,CAC3C,MAAO,UACP,MAAO,EACP,QAAS,EACV,CAIY,GAA4C,CACvD,KAAM,GACN,KAAM,GACN,SAAU,GACV,MAAO,UACP,SAAU,eACX,CAEY,EAAgB,CAC3B,UACA,UACA,UACA,UACA,UACA,UACD,qpBGiHD,IAAM,EAAQ,EASR,EAAO,EAUP,EAAY,EAA8B,KAAK,CAC/C,EAAc,EAAa,MAAM,CACjC,EAAmB,EAAoB,CAC3C,GAAG,GACH,GAAG,EAAM,UACV,CAAC,CACI,EAAmB,EAA0B,CACjD,GAAG,GACH,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,EAsGM,MAtGN,EAsGM,CArGOA,EAAAA,aAAAA,GAAAA,CAAX,EAiFM,MAjFN,EAiFM,CAhFJ,EAuBM,MAvBN,EAuBM,CAtBJ,EAqBe,EAAA,EAAA,CAAA,KAAA,eAXH,CATV,EASU,EAAA,EAAA,CAAA,CARP,KAAM,EAAA,QAAW,MAAA,UAAA,UAClB,KAAK,QACJ,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAW,QAER,KAAI,MAC6C,CAA1D,EAA0D,EAAA,CAAlD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFa,OAEb,GAAA,CAAA,CAAA,yBACA,EASU,EAAA,EAAA,CAAA,CARP,KAAM,EAAA,QAAW,SAAA,UAAA,UAClB,KAAK,QACJ,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAW,WAER,KAAI,MAC+C,CAA5D,EAA4D,EAAA,CAApD,KAAK,aAAc,KAAM,GAAI,MAAM,iCAG/C,CAAA,AAAA,EAAA,KAAA,EAFa,QAEb,GAAA,CAAA,CAAA,2CAIJ,EAAuC,MAAA,CAAlC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEzB,EAAA,QAAW,OAAA,GAAA,CAAtB,EAQM,MARN,EAQM,CAAA,AAAA,EAAA,KAPJ,EAAqC,OAAA,CAA/B,MAAM,gBAAe,CAAC,KAAE,GAAA,CAC9B,EAKE,EAAA,EAAA,CAAA,CAJQ,MAAO,EAAiB,iCAAjB,EAAiB,MAAK,EACpC,aAAY,GACb,KAAK,QACJ,SAAU,EAAA,EAAA,+CAIJ,EAAA,QAAW,OAAA,GAAA,CAAtB,EASM,MATN,EASM,CAAA,AAAA,EAAA,KARJ,EAAqC,OAAA,CAA/B,MAAM,gBAAe,CAAC,KAAE,GAAA,CAC9B,EAME,EAAA,EAAA,CAAA,CALQ,MAAO,EAAiB,iCAAjB,EAAiB,MAAK,EACpC,IAAK,EACL,IAAK,GACN,KAAK,QACL,MAAA,CAAA,MAAA,OAAA,4CAIJ,EAAuC,MAAA,CAAlC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEpC,EAaM,MAbN,EAaM,CAZJ,EAKU,EAAA,EAAA,CAAA,CALD,KAAK,QAAS,SAAQ,CAAG,EAAA,EAAO,CAAG,QAAO,IACtC,KAAI,MAC6C,CAA1D,EAA0D,EAAA,CAAlD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFa,OAEb,GAAA,CAAA,CAAA,6BACA,EAKU,EAAA,EAAA,CAAA,CALD,KAAK,QAAS,SAAQ,CAAG,EAAA,EAAO,CAAG,QAAO,IACtC,KAAI,MAC6C,CAA1D,EAA0D,EAAA,CAAlD,KAAK,WAAY,KAAM,GAAI,MAAM,iCAG7C,CAAA,AAAA,EAAA,KAAA,EAFa,OAEb,GAAA,CAAA,CAAA,uCAGF,EAAuC,MAAA,CAAlC,MAAM,0BAAyB,CAAA,KAAA,GAAA,CAEpC,EAYM,MAZN,GAYM,CAXJ,EAUU,EAAA,EAAA,CAAA,CATR,KAAK,QACL,KAAK,QACJ,SAAU,EAAA,EAAO,CACjB,QAAO,IAEG,KAAI,MACuD,CAApE,EAAoE,EAAA,CAA5D,KAAK,qBAAsB,KAAM,GAAI,MAAM,iCAGvD,CAAA,AAAA,EAAA,MAAA,EAFa,OAEb,GAAA,CAAA,CAAA,gDAIJ,EAiBM,MAAA,CAhBJ,MAAK,EAAA,CAAC,2BAA0B,CAAA,SACtBC,EAAAA,SAAQ,SAAEC,EAAAA,SAAQ,CAAA,CAAA,CAC3B,MAAK,EAAA,cAA2BC,EAAAA,OAAK,SAAA,GAAmBA,EAAAA,MAAK,IAAOA,EAAAA,oBAA+BC,EAAAA,QAAM,SAAA,GAAmBA,EAAAA,OAAM,IAAOA,EAAAA,uBAAkCC,EAAAA,iBAAe,kBAM3L,EAIE,SAAA,SAHI,YAAJ,IAAI,EACJ,MAAK,EAAA,CAAC,mBAAkB,CAAA,SACdJ,EAAAA,SAAQ,SAAEC,EAAAA,SAAQ,CAAA,CAAA,UAEnB,EAAA,EAAO,EAAA,CAAKD,EAAAA,UAAQ,CAAKC,EAAAA,UAAAA,GAAAA,CAApC,EAEM,MAFN,GAAyE,WAEzE,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","../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'\r\nimport type { ExportOptions, WatermarkConfig } from '../types'\r\n\r\ninterface UseSignatureExportOptions {\r\n canvasRef: Ref<HTMLCanvasElement | null>\r\n watermark?: Ref<Partial<WatermarkConfig>>\r\n}\r\n\r\n/**\r\n *\r\n */\r\nexport function useSignatureExport(options: UseSignatureExportOptions) {\r\n const { canvasRef, watermark } = options\r\n\r\n const getWatermarkPosition = (\r\n canvas: HTMLCanvasElement,\r\n textWidth: number,\r\n fontSize: number,\r\n position: string\r\n ): { x: number; y: number } => {\r\n const padding = 10\r\n const positions = {\r\n 'top-left': { x: padding, y: fontSize + padding },\r\n 'top-right': {\r\n x: canvas.width - textWidth - padding,\r\n y: fontSize + padding,\r\n },\r\n 'bottom-left': { x: padding, y: canvas.height - padding },\r\n 'bottom-right': {\r\n x: canvas.width - textWidth - padding,\r\n y: canvas.height - padding,\r\n },\r\n }\r\n return (\r\n positions[position as keyof typeof positions] || positions['bottom-right']\r\n )\r\n }\r\n\r\n const drawWatermark = (canvas: HTMLCanvasElement, text: string): void => {\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx || !watermark?.value?.show) return\r\n const config = {\r\n fontSize: watermark.value.fontSize || 12,\r\n color: watermark.value.color || '#999999',\r\n position: watermark.value.position || 'bottom-right',\r\n }\r\n ctx.save()\r\n ctx.font = `${config.fontSize}px Arial`\r\n ctx.fillStyle = config.color\r\n ctx.textBaseline = 'bottom'\r\n const textWidth = ctx.measureText(text).width\r\n const { x, y } = getWatermarkPosition(\r\n canvas,\r\n textWidth,\r\n config.fontSize,\r\n config.position\r\n )\r\n ctx.fillText(text, x, y)\r\n ctx.restore()\r\n }\r\n\r\n const createTempCanvas = (\r\n sourceCanvas: HTMLCanvasElement,\r\n includeBackground: boolean,\r\n backgroundColor: string\r\n ) => {\r\n const tempCanvas = document.createElement('canvas')\r\n tempCanvas.width = sourceCanvas.width\r\n tempCanvas.height = sourceCanvas.height\r\n const tempCtx = tempCanvas.getContext('2d')\r\n if (!tempCtx) throw new Error('无法创建临时 Canvas')\r\n if (includeBackground) {\r\n tempCtx.fillStyle = backgroundColor\r\n tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height)\r\n }\r\n tempCtx.drawImage(sourceCanvas, 0, 0)\r\n return { canvas: tempCanvas, ctx: tempCtx }\r\n }\r\n\r\n const prepareExportCanvas = (\r\n canvas: HTMLCanvasElement,\r\n options: ExportOptions\r\n ): HTMLCanvasElement => {\r\n const {\r\n includeBackground = false,\r\n backgroundColor = '#FFFFFF',\r\n includeWatermark = false,\r\n } = options\r\n const { canvas: tempCanvas } = createTempCanvas(\r\n canvas,\r\n includeBackground,\r\n backgroundColor\r\n )\r\n // includeWatermark 为 true 时才叠加水印,无视 watermark.show 的状态\r\n // 这样「不含水印导出」即使组件配置了水印也不会叠加\r\n if (includeWatermark && watermark?.value?.text) {\r\n drawWatermark(tempCanvas, watermark.value.text)\r\n }\r\n return tempCanvas\r\n }\r\n\r\n const exportToBlob = (\r\n canvas: HTMLCanvasElement,\r\n quality: number\r\n ): Promise<Blob> => {\r\n return new Promise<Blob>((resolve, reject) => {\r\n canvas.toBlob(\r\n blob => (blob ? resolve(blob) : reject(new Error('导出失败'))),\r\n 'image/png',\r\n quality\r\n )\r\n })\r\n }\r\n\r\n const isCanvasEmpty = (canvas: HTMLCanvasElement): boolean => {\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return true\r\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height)\r\n return !data.some(v => v !== 0)\r\n }\r\n\r\n const exportSignature = async (\r\n options: ExportOptions = {}\r\n ): Promise<string | Blob> => {\r\n const canvas = canvasRef.value\r\n if (!canvas) throw new Error('Canvas 未初始化')\r\n if (isCanvasEmpty(canvas)) throw new Error('签名为空,请先签名后再导出')\r\n const { format = 'png', quality = 0.92 } = options\r\n if (format === 'svg') {\r\n return 'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\"><text>SVG export placeholder</text></svg>'\r\n }\r\n const tempCanvas = prepareExportCanvas(canvas, options)\r\n if (format === 'blob') return exportToBlob(tempCanvas, quality)\r\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png'\r\n return tempCanvas.toDataURL(mimeType, quality)\r\n }\r\n\r\n const download = async (\r\n filename = 'signature',\r\n options: ExportOptions = {}\r\n ): Promise<void> => {\r\n const format = options.format || 'png'\r\n const result = await exportSignature({ ...options, format })\r\n if (result instanceof Blob) {\r\n const url = URL.createObjectURL(result)\r\n const link = document.createElement('a')\r\n link.href = url\r\n link.download = `${filename}.${format}`\r\n link.click()\r\n URL.revokeObjectURL(url)\r\n } else if (typeof result === 'string') {\r\n const link = document.createElement('a')\r\n link.href = result\r\n link.download = `${filename}.${format}`\r\n link.click()\r\n }\r\n }\r\n\r\n const loadImage = async (imageUrl: string): Promise<void> => {\r\n const canvas = canvasRef.value\r\n if (!canvas) throw new Error('Canvas 未初始化')\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) throw new Error('无法获取 Canvas 上下文')\r\n return new Promise((resolve, reject) => {\r\n const img = new Image()\r\n img.crossOrigin = 'anonymous'\r\n img.onload = () => {\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height)\r\n resolve()\r\n }\r\n img.onerror = () => reject(new Error(`图片加载失败: ${imageUrl}`))\r\n img.src = imageUrl\r\n })\r\n }\r\n\r\n return { exportSignature, download, loadImage }\r\n}\r\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","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2026-02-25\r\n * @Description: 电子签名组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n-->\r\n<template>\r\n <div class=\"c-signature\">\r\n <div v-if=\"showToolbar\" class=\"signature-toolbar\">\r\n <div class=\"toolbar-section\">\r\n <NButtonGroup>\r\n <NButton\r\n :type=\"currentMode === 'pen' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'pen'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:draw\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 画笔\r\n </NButton>\r\n <NButton\r\n :type=\"currentMode === 'eraser' ? 'primary' : 'default'\"\r\n size=\"small\"\r\n @click=\"currentMode = 'eraser'\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:eraser\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 橡皮擦\r\n </NButton>\r\n </NButtonGroup>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">颜色</span>\r\n <NColorPicker\r\n v-model:value=\"currentPenConfig.color\"\r\n :show-alpha=\"false\"\r\n size=\"small\"\r\n :swatches=\"PRESET_COLORS\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"currentMode === 'pen'\" class=\"toolbar-section\">\r\n <span class=\"section-label\">粗细</span>\r\n <NInputNumber\r\n v-model:value=\"currentPenConfig.width\"\r\n :min=\"1\"\r\n :max=\"20\"\r\n size=\"small\"\r\n style=\"width: 80px\"\r\n />\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton size=\"small\" :disabled=\"!canUndo\" @click=\"handleUndo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:undo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 撤销\r\n </NButton>\r\n <NButton size=\"small\" :disabled=\"!canRedo\" @click=\"handleRedo\">\r\n <template #icon>\r\n <C_Icon name=\"mdi:redo\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 重做\r\n </NButton>\r\n </div>\r\n\r\n <div class=\"toolbar-section divider\" />\r\n\r\n <div class=\"toolbar-section\">\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"isEmpty\"\r\n @click=\"handleClear\"\r\n >\r\n <template #icon>\r\n <C_Icon name=\"mdi:delete-outline\" :size=\"16\" color=\"currentColor\" />\r\n </template>\r\n 清空\r\n </NButton>\r\n </div>\r\n </div>\r\n\r\n <div\r\n class=\"signature-canvas-wrapper\"\r\n :class=\"{ disabled, readonly }\"\r\n :style=\"{\r\n width: typeof width === 'number' ? `${width}px` : width,\r\n height: typeof height === 'number' ? `${height}px` : height,\r\n backgroundColor: backgroundColor || 'transparent',\r\n }\"\r\n >\r\n <canvas\r\n ref=\"canvasRef\"\r\n class=\"signature-canvas\"\r\n :class=\"{ disabled, readonly }\"\r\n />\r\n <div v-if=\"isEmpty && !disabled && !readonly\" class=\"canvas-placeholder\">\r\n 请在此处签名\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, toRef, onMounted, onUnmounted } from \"vue\";\r\nimport { NButton, NButtonGroup, NColorPicker, NInputNumber } from \"naive-ui\";\r\nimport C_Icon from \"../C_Icon/index.vue\";\r\nimport { useSignatureCanvas } from \"./composables/useSignatureCanvas\";\r\nimport { useSignatureHistory } from \"./composables/useSignatureHistory\";\r\nimport { useSignatureExport } from \"./composables/useSignatureExport\";\r\nimport {\r\n DEFAULT_PEN_CONFIG,\r\n DEFAULT_WATERMARK_CONFIG,\r\n PRESET_COLORS,\r\n} from \"./data\";\r\nimport type {\r\n ExportOptions,\r\n PenConfig,\r\n PenMode,\r\n SignatureExpose,\r\n SignaturePoint,\r\n SignatureProps,\r\n SignatureStroke,\r\n WatermarkConfig,\r\n} from \"./types\";\r\n\r\ndefineOptions({ name: \"C_Signature\" });\r\n\r\nconst props = withDefaults(defineProps<SignatureProps>(), {\r\n width: \"100%\",\r\n height: 300,\r\n disabled: false,\r\n readonly: false,\r\n showToolbar: true,\r\n maxHistory: 50,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n \"start-draw\": [];\r\n drawing: [point: SignaturePoint];\r\n \"end-draw\": [stroke: SignatureStroke];\r\n clear: [];\r\n undo: [];\r\n redo: [];\r\n change: [data: SignatureStroke[]];\r\n}>();\r\n\r\nconst canvasRef = ref<HTMLCanvasElement | null>(null);\r\nconst currentMode = ref<PenMode>(\"pen\");\r\nconst currentPenConfig = reactive<PenConfig>({\r\n ...DEFAULT_PEN_CONFIG,\r\n ...props.penConfig,\r\n});\r\nconst currentWatermark = reactive<WatermarkConfig>({\r\n ...DEFAULT_WATERMARK_CONFIG,\r\n ...props.watermark,\r\n});\r\n\r\nconst {\r\n strokes,\r\n canUndo,\r\n canRedo,\r\n isEmpty,\r\n addStroke,\r\n undo,\r\n redo,\r\n clear,\r\n loadData,\r\n} = useSignatureHistory({\r\n maxHistory: props.maxHistory,\r\n onChange: (data) => {\r\n canvasInstance.redrawStrokes(data as SignatureStroke[]);\r\n emit(\"change\", data as SignatureStroke[]);\r\n },\r\n});\r\n\r\nconst canvasInstance = useSignatureCanvas({\r\n canvasRef,\r\n penConfig: toRef(currentPenConfig),\r\n mode: currentMode,\r\n disabled: toRef(props, \"disabled\"),\r\n onStrokeComplete: (stroke: SignatureStroke) => {\r\n addStroke(stroke);\r\n emit(\"end-draw\", stroke);\r\n },\r\n onDrawStart: () => emit(\"start-draw\"),\r\n onDrawing: (point: SignaturePoint) => emit(\"drawing\", point),\r\n});\r\n\r\nconst exportInstance = useSignatureExport({\r\n canvasRef,\r\n watermark: toRef(currentWatermark),\r\n});\r\n\r\nconst handleUndo = (): boolean => {\r\n const result = undo();\r\n if (result) emit(\"undo\");\r\n return result;\r\n};\r\n\r\nconst handleRedo = (): boolean => {\r\n const result = redo();\r\n if (result) emit(\"redo\");\r\n return result;\r\n};\r\n\r\nconst handleClear = () => {\r\n clear();\r\n canvasInstance.clearCanvas();\r\n emit(\"clear\");\r\n};\r\n\r\nconst exportSignature = async (\r\n options?: ExportOptions,\r\n): Promise<string | Blob> => {\r\n return exportInstance.exportSignature(options);\r\n};\r\n\r\nconst download = async (\r\n filename?: string,\r\n options?: ExportOptions,\r\n): Promise<void> => {\r\n return exportInstance.download(filename, options);\r\n};\r\n\r\nconst loadImage = async (imageUrl: string): Promise<void> => {\r\n await exportInstance.loadImage(imageUrl);\r\n clear();\r\n};\r\n\r\nconst getSignatureData = (): SignatureStroke[] =>\r\n strokes.value as SignatureStroke[];\r\nconst loadSignatureData = (data: SignatureStroke[]): void => loadData(data);\r\nconst isSignatureEmpty = (): boolean => isEmpty.value;\r\n\r\nonMounted(() => {\r\n canvasInstance.initCanvas();\r\n canvasInstance.bindEvents();\r\n if (props.backgroundImage) loadImage(props.backgroundImage);\r\n});\r\n\r\nonUnmounted(() => canvasInstance.unbindEvents());\r\n\r\ndefineExpose<SignatureExpose>({\r\n clear: handleClear,\r\n undo: handleUndo,\r\n redo: handleRedo,\r\n export: exportSignature,\r\n download,\r\n loadImage,\r\n getSignatureData,\r\n loadSignatureData,\r\n isEmpty: isSignatureEmpty,\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n@use \"./index.scss\";\r\n</style>\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"C_Skeleton-BNPbaut7.css","names":[],"sources":["../src/components/C_Skeleton/index.vue?vue&type=style&index=0&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Skeleton 骨架屏组件样式 */\n.c-skeleton {\n --c-skeleton-bg: #e5e7eb;\n --c-skeleton-wave-bg: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.4),\n transparent\n );\n --c-skeleton-radius: 4px;\n --c-skeleton-circle-size: 40px;\n --c-skeleton-circle-sm: 32px;\n --c-skeleton-circle-lg: 56px;\n --c-skeleton-line-height: 16px;\n --c-skeleton-line-sm-height: 12px;\n --c-skeleton-line-mini-height: 8px;\n --c-skeleton-gap: 12px;\n --c-skeleton-card-cover-height: 160px;\n --c-skeleton-image-height: 200px;\n width: 100%;\n}\n\n/* ─── 基础骨架块 ─── */\n.c-skeleton__item {\n background-color: var(--c-skeleton-bg);\n border-radius: var(--c-skeleton-radius);\n position: relative;\n overflow: hidden;\n}\n\n/* ─── 动画:脉冲 ─── */\n.c-skeleton--pulse .c-skeleton__item {\n animation: skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes skeleton-pulse {\n0%, 100% {\n opacity: 1;\n}\n50% {\n opacity: 0.4;\n}\n}\n/* ─── 动画:波浪 ─── */\n.c-skeleton--wave .c-skeleton__item::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--c-skeleton-wave-bg);\n animation: skeleton-wave 1.6s linear infinite;\n}\n@keyframes skeleton-wave {\n0% {\n transform: translateX(-100%);\n}\n100% {\n transform: translateX(100%);\n}\n}\n/* ─── 无动画 ─── */\n.c-skeleton--none .c-skeleton__item {\n animation: none;\n}\n.c-skeleton--none .c-skeleton__item::after {\n display: none;\n}\n\n/* ─── 文本行 ─── */\n.c-skeleton__text {\n margin-bottom: 8px;\n}\n.c-skeleton__line {\n height: var(--c-skeleton-line-height);\n width: 100%;\n}\n.c-skeleton__line--sm {\n height: var(--c-skeleton-line-sm-height);\n margin-top: 6px;\n}\n.c-skeleton__line--mini {\n height: var(--c-skeleton-line-mini-height);\n}\n.c-skeleton__line--label {\n height: var(--c-skeleton-line-sm-height);\n margin-bottom: 8px;\n}\n.c-skeleton__line--input {\n height: 34px;\n border-radius: 6px;\n}\n.c-skeleton__line--btn {\n height: 32px;\n border-radius: 6px;\n}\n\n/* ─── 圆形(头像) ─── */\n.c-skeleton__circle {\n width: var(--c-skeleton-circle-size);\n height: var(--c-skeleton-circle-size);\n border-radius: 50%;\n flex-shrink: 0;\n}\n.c-skeleton__circle--sm {\n width: var(--c-skeleton-circle-sm);\n height: var(--c-skeleton-circle-sm);\n}\n.c-skeleton__circle--lg {\n width: var(--c-skeleton-circle-lg);\n height: var(--c-skeleton-circle-lg);\n}\n\n/* ─── Avatar 预设 ─── */\n.c-skeleton__avatar-group {\n display: flex;\n align-items: center;\n gap: var(--c-skeleton-gap);\n}\n.c-skeleton__avatar-text {\n flex: 1;\n}\n\n/* ─── Image 预设 ─── */\n.c-skeleton__image {\n width: 100%;\n height: var(--c-skeleton-image-height);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__image-icon {\n color: var(--c-skeleton-bg);\n opacity: 0.6;\n filter: brightness(0.8);\n}\n\n/* ─── Card 预设 ─── */\n.c-skeleton__card {\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__card-cover {\n width: 100%;\n height: var(--c-skeleton-card-cover-height);\n border-radius: 0;\n}\n.c-skeleton__card-body {\n padding: 16px;\n}\n.c-skeleton__card-desc {\n margin-top: 8px;\n}\n.c-skeleton__card-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid var(--c-skeleton-bg);\n}\n\n/* ─── Table 预设 ─── */\n.c-skeleton__table {\n width: 100%;\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n}\n.c-skeleton__table-header {\n display: flex;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--c-skeleton-bg) 30%, transparent);\n border-bottom: 1px solid var(--c-skeleton-bg);\n}\n.c-skeleton__table-row {\n display: flex;\n padding: 12px 16px;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__table-row:last-child {\n border-bottom: none;\n}\n.c-skeleton__table-cell {\n flex: 1;\n padding: 0 8px;\n}\n.c-skeleton__table-cell--action {\n flex: 0 0 120px;\n}\n.c-skeleton__action-btns {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* ─── Form 预设 ─── */\n.c-skeleton__form {\n display: grid;\n grid-template-columns: repeat(var(--form-cols, 2), 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__form-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__form-actions {\n grid-column: 1/-1;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 16px;\n}\n\n/* ─── List 预设 ─── */\n.c-skeleton__list-item {\n display: flex;\n align-items: flex-start;\n gap: var(--c-skeleton-gap);\n padding: 12px 0;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__list-item:last-child {\n border-bottom: none;\n}\n.c-skeleton__list-content {\n flex: 1;\n}\n\n/* ─── Detail 预设 ─── */\n.c-skeleton__detail-header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n}\n.c-skeleton__detail-title {\n flex: 1;\n}\n.c-skeleton__detail-body {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__detail-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__detail-value {\n margin-top: 4px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"C_Skeleton-Djsjw8XY.css","names":[],"sources":["../src/components/C_Skeleton/index.vue?vue&type=style&index=0&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//* C_Skeleton 骨架屏组件样式 */\n.c-skeleton {\n --c-skeleton-bg: #e5e7eb;\n --c-skeleton-wave-bg: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.4),\n transparent\n );\n --c-skeleton-radius: 4px;\n --c-skeleton-circle-size: 40px;\n --c-skeleton-circle-sm: 32px;\n --c-skeleton-circle-lg: 56px;\n --c-skeleton-line-height: 16px;\n --c-skeleton-line-sm-height: 12px;\n --c-skeleton-line-mini-height: 8px;\n --c-skeleton-gap: 12px;\n --c-skeleton-card-cover-height: 160px;\n --c-skeleton-image-height: 200px;\n width: 100%;\n}\n\n/* ─── 基础骨架块 ─── */\n.c-skeleton__item {\n background-color: var(--c-skeleton-bg);\n border-radius: var(--c-skeleton-radius);\n position: relative;\n overflow: hidden;\n}\n\n/* ─── 动画:脉冲 ─── */\n.c-skeleton--pulse .c-skeleton__item {\n animation: skeleton-pulse 1.5s ease-in-out infinite;\n}\n@keyframes skeleton-pulse {\n0%, 100% {\n opacity: 1;\n}\n50% {\n opacity: 0.4;\n}\n}\n/* ─── 动画:波浪 ─── */\n.c-skeleton--wave .c-skeleton__item::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--c-skeleton-wave-bg);\n animation: skeleton-wave 1.6s linear infinite;\n}\n@keyframes skeleton-wave {\n0% {\n transform: translateX(-100%);\n}\n100% {\n transform: translateX(100%);\n}\n}\n/* ─── 无动画 ─── */\n.c-skeleton--none .c-skeleton__item {\n animation: none;\n}\n.c-skeleton--none .c-skeleton__item::after {\n display: none;\n}\n\n/* ─── 文本行 ─── */\n.c-skeleton__text {\n margin-bottom: 8px;\n}\n.c-skeleton__line {\n height: var(--c-skeleton-line-height);\n width: 100%;\n}\n.c-skeleton__line--sm {\n height: var(--c-skeleton-line-sm-height);\n margin-top: 6px;\n}\n.c-skeleton__line--mini {\n height: var(--c-skeleton-line-mini-height);\n}\n.c-skeleton__line--label {\n height: var(--c-skeleton-line-sm-height);\n margin-bottom: 8px;\n}\n.c-skeleton__line--input {\n height: 34px;\n border-radius: 6px;\n}\n.c-skeleton__line--btn {\n height: 32px;\n border-radius: 6px;\n}\n\n/* ─── 圆形(头像) ─── */\n.c-skeleton__circle {\n width: var(--c-skeleton-circle-size);\n height: var(--c-skeleton-circle-size);\n border-radius: 50%;\n flex-shrink: 0;\n}\n.c-skeleton__circle--sm {\n width: var(--c-skeleton-circle-sm);\n height: var(--c-skeleton-circle-sm);\n}\n.c-skeleton__circle--lg {\n width: var(--c-skeleton-circle-lg);\n height: var(--c-skeleton-circle-lg);\n}\n\n/* ─── Avatar 预设 ─── */\n.c-skeleton__avatar-group {\n display: flex;\n align-items: center;\n gap: var(--c-skeleton-gap);\n}\n.c-skeleton__avatar-text {\n flex: 1;\n}\n\n/* ─── Image 预设 ─── */\n.c-skeleton__image {\n width: 100%;\n height: var(--c-skeleton-image-height);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__image-icon {\n color: var(--c-skeleton-bg);\n opacity: 0.6;\n filter: brightness(0.8);\n}\n\n/* ─── Card 预设 ─── */\n.c-skeleton__card {\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n margin-bottom: var(--c-skeleton-gap);\n}\n.c-skeleton__card-cover {\n width: 100%;\n height: var(--c-skeleton-card-cover-height);\n border-radius: 0;\n}\n.c-skeleton__card-body {\n padding: 16px;\n}\n.c-skeleton__card-desc {\n margin-top: 8px;\n}\n.c-skeleton__card-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid var(--c-skeleton-bg);\n}\n\n/* ─── Table 预设 ─── */\n.c-skeleton__table {\n width: 100%;\n border: 1px solid var(--c-skeleton-bg);\n border-radius: 8px;\n overflow: hidden;\n}\n.c-skeleton__table-header {\n display: flex;\n padding: 12px 16px;\n background-color: color-mix(in srgb, var(--c-skeleton-bg) 30%, transparent);\n border-bottom: 1px solid var(--c-skeleton-bg);\n}\n.c-skeleton__table-row {\n display: flex;\n padding: 12px 16px;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__table-row:last-child {\n border-bottom: none;\n}\n.c-skeleton__table-cell {\n flex: 1;\n padding: 0 8px;\n}\n.c-skeleton__table-cell--action {\n flex: 0 0 120px;\n}\n.c-skeleton__action-btns {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* ─── Form 预设 ─── */\n.c-skeleton__form {\n display: grid;\n grid-template-columns: repeat(var(--form-cols, 2), 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__form-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__form-actions {\n grid-column: 1/-1;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding-top: 16px;\n}\n\n/* ─── List 预设 ─── */\n.c-skeleton__list-item {\n display: flex;\n align-items: flex-start;\n gap: var(--c-skeleton-gap);\n padding: 12px 0;\n border-bottom: 1px solid color-mix(in srgb, var(--c-skeleton-bg) 50%, transparent);\n}\n.c-skeleton__list-item:last-child {\n border-bottom: none;\n}\n.c-skeleton__list-content {\n flex: 1;\n}\n\n/* ─── Detail 预设 ─── */\n.c-skeleton__detail-header {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-bottom: 24px;\n}\n.c-skeleton__detail-title {\n flex: 1;\n}\n.c-skeleton__detail-body {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px 24px;\n}\n.c-skeleton__detail-field {\n display: flex;\n flex-direction: column;\n}\n.c-skeleton__detail-value {\n margin-top: 4px;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./C_Skeleton.js`);exports.C_Skeleton=e.t;
|