浏览代码

first commit

liuhairui 2 周之前
父节点
当前提交
fb714b8ea9
共有 1 个文件被更改,包括 92 次插入0 次删除
  1. 92 0
      src/view/TemplateManagement/TemplateDesign.vue

+ 92 - 0
src/view/TemplateManagement/TemplateDesign.vue

@@ -679,6 +679,95 @@ const fetchMaterials = async () => {
   }
 }
 
+// 生成画布预览图(base64)
+const generateCanvasPreview = async () => {
+  if (!canvasWidth.value || !canvasHeight.value) return null
+
+  const exportCanvas = document.createElement('canvas')
+  exportCanvas.width = canvasWidth.value
+  exportCanvas.height = canvasHeight.value
+  const ctx = exportCanvas.getContext('2d')
+  if (!ctx) return null
+
+  // 背景填充为白色
+  ctx.fillStyle = '#ffffff'
+  ctx.fillRect(0, 0, exportCanvas.width, exportCanvas.height)
+
+  // 预加载图片图层
+  const imageLayers = layers.value.filter(l => (l.type || 'image') !== 'text' && l.url)
+  await Promise.all(
+    imageLayers.map(layer => {
+      return new Promise(resolve => {
+        const img = new Image()
+        img.crossOrigin = 'anonymous'
+        img.onload = () => {
+          layer._previewImg = img
+          resolve()
+        }
+        img.onerror = () => resolve()
+        img.src = layer.url
+      })
+    })
+  )
+
+  // 按当前顺序绘制所有可见图层
+  for (const layer of layers.value) {
+    if (!layer.visible) continue
+
+    ctx.save()
+    ctx.globalAlpha = (layer.opacity ?? 100) / 100
+
+    const w = layer.width || 0
+    const h = layer.height || 0
+    const cx = (layer.x || 0) + w / 2
+    const cy = (layer.y || 0) + h / 2
+
+    ctx.translate(cx, cy)
+    ctx.rotate(((layer.rotation || 0) * Math.PI) / 180)
+
+    if ((layer.type || 'image') === 'text') {
+      const fontSize = layer.fontSize || 16
+      const fontFamily = layer.fontFamily || 'Arial'
+      const fontWeight = layer.fontWeight || 'normal'
+      const fontStyle = layer.fontStyle || 'normal'
+      ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`
+      ctx.textAlign = layer.textAlign || 'left'
+      ctx.textBaseline = 'top'
+      ctx.fillStyle = layer.color || '#000000'
+
+      const lineHeightPx = (layer.lineHeight || 1.5) * fontSize
+      const lines = (layer.text || '').split('\n')
+
+      let startX = 0
+      if (ctx.textAlign === 'left') {
+        startX = -w / 2 + 4
+      } else if (ctx.textAlign === 'right') {
+        startX = w / 2 - 4
+      } // center 默认 0
+
+      let y = -h / 2 + 4
+      for (const line of lines) {
+        ctx.fillText(line, startX, y)
+        y += lineHeightPx
+      }
+    } else {
+      const img = layer._previewImg
+      if (img) {
+        ctx.drawImage(img, -w / 2, -h / 2, w, h)
+      }
+    }
+
+    ctx.restore()
+  }
+
+  // 清理临时图片引用
+  for (const layer of imageLayers) {
+    delete layer._previewImg
+  }
+
+  return exportCanvas.toDataURL('image/png')
+}
+
 let materialSearchTimer = null
 const handleMaterialSearchInput = () => {
   if (materialSearchTimer) clearTimeout(materialSearchTimer)
@@ -784,10 +873,13 @@ const saveTemplate = async () => {
     return
   }
 
+  const previewImage = await generateCanvasPreview()
+
   const templateData = {
     canvasWidth: canvasWidth.value,
     canvasHeight: canvasHeight.value,
     canvasRatio: canvasRatio.value,
+    previewImage, // 画布整体预览图(base64)
     layers: layers.value.map(layer => ({
       id: layer.id,
       name: layer.name,