huminmin
2026-07-10 64ac7e195332cffa495e84c0e3fed3c1c232d20c
src/components/AttachmentUpload/image/index.vue
@@ -27,6 +27,10 @@
    type: Array,
    default: () => ['png', 'jpg', 'jpeg', 'webp'],
  },
  watermarkText: {
    type: String,
    default: '',
  },
  buttonText: {
    type: String,
    default: '上传图片',
@@ -161,6 +165,67 @@
  return true
}
async function addWatermarkToFile(rawFile) {
  if (!props.watermarkText) {
    return rawFile
  }
  const imageUrl = await readFileAsDataURL(rawFile)
  const image = await loadImage(imageUrl)
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  if (!ctx) {
    return rawFile
  }
  canvas.width = image.width
  canvas.height = image.height
  ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
  const padding = Math.max(16, Math.round(canvas.width * 0.02))
  const fontSize = Math.max(24, Math.round(canvas.width * 0.03))
  const lineHeight = Math.round(fontSize * 1.35)
  const lines = String(props.watermarkText).split('\n').filter(Boolean)
  ctx.fillStyle = 'rgba(0, 0, 0, 0.32)'
  const blockHeight = lines.length * lineHeight + padding * 2
  ctx.fillRect(0, canvas.height - blockHeight, canvas.width, blockHeight)
  ctx.fillStyle = 'rgba(255, 255, 255, 0.96)'
  ctx.font = `${fontSize}px sans-serif`
  ctx.textBaseline = 'bottom'
  lines.forEach((line, index) => {
    ctx.fillText(line, padding, canvas.height - padding - (lines.length - 1 - index) * lineHeight)
  })
  const mimeType = rawFile.type || 'image/jpeg'
  const blob = await new Promise((resolve) => canvas.toBlob(resolve, mimeType, 0.92))
  if (!blob) {
    return rawFile
  }
  return new File([blob], rawFile.name, { type: mimeType, lastModified: Date.now() })
}
function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result)
    reader.onerror = reject
    reader.readAsDataURL(file)
  })
}
function loadImage(src) {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.onload = () => resolve(img)
    img.onerror = reject
    img.src = src
  })
}
function scheduleUpload(uploadFiles) {
  clearTimeout(uploadQueueTimer.value)
  uploadQueueTimer.value = setTimeout(() => {
@@ -196,9 +261,10 @@
  }
  const formData = new FormData()
  validFiles.forEach((file) => {
    formData.append(props.uploadFieldName, file.raw)
  })
  for (const file of validFiles) {
    const uploadFileObj = await addWatermarkToFile(file.raw)
    formData.append(props.uploadFieldName, uploadFileObj)
  }
  uploading.value = true
  proxy.$modal.loading('图片上传中,请稍候...')