头像图片上传和裁切

<script setup>
import { message } from 'ant-design-vue'
import Cropper from 'cropperjs'
import { upload } from '@/api/workOrder/hotService'

const props = defineProps({
  modelValue: String,
})
const emit = defineEmits(['update:modelValue', 'submit'])

const modelValue = useVModel(props, 'modelValue', emit)
const [visible, toggle] = useToggle(false)

const imgRef = ref()
const previewRef = ref()
const fileRef = ref()

const cropper = ref()

function init() {
  cropper.value = new Cropper(unrefElement(imgRef), {
    aspectRatio: 1,
    dragMode: 'move',
    preview: unrefElement(previewRef),
    restore: false,
    center: false,
    highlight: false,
    cropBoxMovable: true,
    toggleDragModeOnDblclick: true,
  })
}

function getImageBase64(e) {
  const file = e.target.files[0]
  if (!file) return
  const reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onload = () => {
    if (!cropper.value) init()
    cropper.value.replace(reader.result)
  }
}

function submit() {
  const file = cropper.value?.getCroppedCanvas()?.toDataURL()
  if (!file) {
    message.info('请选择图片')
    return
  }

  if (file.length > 250 * 1024) {
    message.warning('选择的区域太大,超过了250K。请缩小选择区域!')
    return
  }
  modelValue.value = file
  let newfile = base64ToFile(file, '头像')
  const formData = new window.FormData()
  formData.append('files', newfile)
  upload(formData).then((res) => {
    if (res?.code == 200) {
      message.success('上传成功')
      if (res.data && res.data !== null && res.data.length) {
        emit('submit', res.data)
      }
    }
  })
  toggle(false)
}
function base64ToFile(dataurl, filename) {
  let arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], filename, { type: mime })
}

function upload1() {
  fileRef.value?.click()
}
function reset() {
  cropper.value?.reset()
}
function remove() {
  cropper.value?.destroy()
  cropper.value = null
}
function zoomIn() {
  cropper.value?.zoom(0.1)
}
function zoomOut() {
  cropper.value?.zoom(-0.1)
}
</script>

<template>
  <div>
    <div class="btn">
      <a-button @click="toggle()">本地上传</a-button>
    </div>
    <a-modal
      v-model:visible="visible"
      title="修改头像"
      width="640px"
      :closable="false"
      :maskClosable="false"
      @ok="submit()"
    >
      <div class="flex justify-between">
        <div class="w-96 border border-solid border-gray-300">
          <img ref="imgRef" />
        </div>

        <div class="flex flex-col items-center space-y-2.5">
          <div
            ref="previewRef"
            class="w-44 h-44 border border-solid border-gray-300 overflow-hidden"
          />

          <a-space>
            <a-button-group>
              <input
                ref="fileRef"
                type="file"
                accept="image/png, image/jpeg, image/gif, image/jpg"
                class="hidden"
                @change="getImageBase64"
              />
              <a-button type="primary" @click="upload1()">
                <template #icon>
                  <UploadOutlined />
                </template>
              </a-button>
              <a-button type="primary" @click="reset()">
                <template #icon>
                  <SyncOutlined />
                </template>
              </a-button>
              <a-button type="primary" @click="remove()">
                <template #icon>
                  <DeleteOutlined />
                </template>
              </a-button>
            </a-button-group>

            <a-button-group>
              <a-button type="primary" @click="zoomIn()">
                <template #icon>
                  <ZoomInOutlined />
                </template>
              </a-button>
              <a-button type="primary" @click="zoomOut()">
                <template #icon>
                  <ZoomOutOutlined />
                </template>
              </a-button>
            </a-button-group>
          </a-space>
        </div>
      </div>
    </a-modal>
  </div>
</template>

<style scoped>
@import 'cropperjs';

img {
  display: block;
  max-width: 100%;
}

.btn {
  margin-top: 10px;
}
</style>
posted @ 2025-03-27 14:15  abcByme  阅读(28)  评论(0)    收藏  举报