上传图片到腾讯云、wangeditor富文本的图片上传到腾讯云、上传裁剪头像的图片上传到腾讯云

安装cos-js-sdk-v5

npm i cos-js-sdk-v5 --save

安装spark-md5

npm i spark-md5 --save

1.创建src/utils/upload-file.js文件

import COS from 'cos-js-sdk-v5'
import SparkMD5 from 'spark-md5'
import { cosTmpsecret, cosConfig } from '@/api/upload' // 通过后台获取临时密钥
let key = ''
// 配置
// const cosConfig = {
//   // Bucket: 'xlcp-tong-1253334579',
//   // Region: 'ap-nanjing',
//   Bucket: 'mytong-1259414159',
//   Region: 'ap-nanjing',
//   // Domain: 'mytong-1259414159.cos.ap-nanjing.myqcloud.com'
// }
// 初始化实例
/**
 * 签名计算放在前端会暴露 SecretId 和 SecretKey
 * 我们把签名计算过程放在后端实现,前端通过 ajax 向后端获取签名结果
 * 正式部署时请再后端加一层自己网站本身的权限检验。
 * 异步获取临时密钥
 * mytong-1259414159.cos.ap-nanjing.myqcloud.com
 * mytong-1259414159
 * SecretKey:A3oKYrI2YrsfFX4LL3VgZBXu7HJETRCf
 * SecretId:AKIDrYy7VdZIqMaXVDQjaE7lFjGoAFJAmMgj
 * APPID:1259414159
 *
 */
let cos = new COS({
  async getAuthorization(options, callback) {
    const res = await cosTmpsecret()
    const authdata = res.data
    const auth = {
      TmpSecretId: authdata.tmpSecretId,
      TmpSecretKey: authdata.tmpSecretKey,
      XCosSecurityToken: authdata.sessionToken,
      StartTime: authdata.startTime,
      ExpiredTime: authdata.expiredTime, // 在ExpiredTime时间前,不会再次调用getAuthorization
    }
    callback(auth)
  },
  FileParallelLimit: 3, // 文件并发数
  ChunkParallelLimit: 8, // 同一个上传文件的分块并发数
  ChunkSize: 1024 * 1024 * 8, // 分块上传时,每块的字节数大小
})

//   var cos1 = new COS({
//     SecretId: 'A3oKYrI2YrsfFX4LL3VgZBXu7HJETRCf',
//     SecretKey: 'AKIDrYy7VdZIqMaXVDQjaE7lFjGoAFJAmMgj',
//     FileParallelLimit: 3, // 文件并发数
//     ChunkParallelLimit: 8, // 同一个上传文件的分块并发数
//     ChunkSize: 1024 * 1024 * 8 // 分块上传时,每块的字节数大小
// });

// 获取cos存储的图片地址,替换为域名地址
export async function getObjectUrl() {
    let response = await cosConfig()
      const url = cos.getObjectUrl({
        Bucket: response.data.bucket,
        Region: response.data.region,
        Key: key,
        Sign: false,
      }, (err, data) => {
      })
      return url
  // 腾讯云的地址替换为域名地址
  // const p = `${cosConfig.Bucket}.cos.${cosConfig.Region}.myqcloud.com`
  // console.log('p:', p)
  // console.log('url:', url)
  // .replace(p, cosConfig.Domain)
}
// 下载对象
export function getObject(path, url) {
  cosConfig().then(response => {
    console.log('response', response)
    let arr = url.split('.com')
    // console.log('arr', arr[1])
    cos.getObject({
      Bucket: response.data.bucket,
      Region: response.data.region,
      Key: arr[1], /* 必须 */
    }, (err, data) => {
      console.log(err || data.Body)
    })
  })
}
// 获得文件md5
function getFileMD5(file, callback) {
    // 声明必要的变量
    const fileReader = new FileReader()
    // 文件每块分割2M,计算分割详情
    const chunkSize = 2 * 1024 * 1024
    const chunks = Math.ceil(file.size / chunkSize)
    let currentChunk = 0

    // 创建md5对象(基于SparkMD5)
    const spark = new SparkMD5()

    // 每块文件读取完毕之后的处理
    fileReader.onload = function (e) {
      // 每块交由sparkMD5进行计算
      spark.appendBinary(e.target.result)
      currentChunk++

      // 如果文件处理完成计算MD5,如果还有分片继续处理
      if (currentChunk < chunks) {
        loadNext()
      } else {
        callback(spark.end())
      }
    }
    // 处理单片文件的上传
    function loadNext() {
      const start = currentChunk * chunkSize
      const end = start + chunkSize >= file.size ? file.size : start + chunkSize
      fileReader.readAsBinaryString(file.slice(start, end))
    }
    loadNext()
}
// 大文件分片上传-通过sliceUploadFile上传
export function uploadFile(path, file, callback, progressBc) {
  return new Promise(resolve => {
    cosConfig().then(response => {
      // 得到md5码
      getFileMD5(file, md5 => {
        // 存储文件的md5码
        file.md5 = md5
        const subfix = file.name.substr(file.name.lastIndexOf('.'))
        key = path + file.md5 + new Date().getSeconds() + subfix
        cos.sliceUploadFile({
          Bucket: response.data.bucket,
          Region: response.data.region,
          Key: key,
          Body: file,
          onProgress(progressData) {
            progressBc(progressData.percent)
          },
        }, async (err, data) => {
          if (err) {
            callback(err)
            resolve(err)
          } else {
            data.fid = await getObjectUrl()
            console.log(' data.fid1111111111', data)
            callback(null, data)
            resolve(data)
          }
        })
      })
    })
  })
}
// 小文件直接上传-通过putObject上传
export function uploadFile2(path, file, callback, progressBc) {
    // 得到md5码
    try {
      cosConfig().then(response => {
        getFileMD5(file, md5 => {
          // 存储文件的md5码
          file.md5 = md5
          const subfix = file.name.substr(file.name.lastIndexOf('.'))
          key = path + file.md5 + new Date().getSeconds() + subfix
          cos.putObject({
            Bucket: response.data.bucket,
            Region: response.data.region,
            Key: key,
            Body: file,
            onProgress(progressData) {
              progressBc(progressData.percent)
            },
          }, async (err, data) => {
            if (err) {
              callback(err)
            } else {
              data.fid = await getObjectUrl()
              console.log(' data.fid1111111111', data.fid)
              callback(null, data)
            }
          })
        })
      })
    } catch (error) {
      console.log(error)
    }
}
// 文件直接删除-通过deleteObject上传
export function deleteFile(path, file, callback, keyName) {
  cosConfig().then(response => {
    console.log('response', response)
    if (keyName) {
      let key = path + keyName
      cos.deleteObject({
        Bucket: response.data.bucket,
        Region: response.data.region,
        Key: key,
    }, (err, data) => {
        if (err) {
          callback(err)
        } else {
          callback(null, data)
        }
      })
    } else {
        key = path + file.name
        cos.deleteObject({
          Bucket: response.data.bucket,
          Region: response.data.region,
          Key: key,
      }, (err, data) => {
          if (err) {
            callback(err)
          } else {
            callback(null, data)
          }
        })
    }
  })
}

2.在vue中上传图片使用

import { uploadFile2 } from '@/utils/upload-file'
import dayjs from 'dayjs'

const { proxy } = getCurrentInstance()
function uploadImg({ file }) {
  const TODAY = dayjs().format('YYYY/MM/DD')
  uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, datas) => {
    if (err) {
      number.value--
      proxy.$modal.closeLoading()
      proxy.$modal.msgError(datas.msg)
      proxy.$refs.imageUpload.handleRemove(file)
      uploadedSuccessfully()
    this.$message.error(`上传失败:${err}`)
    } else {
      uploadList.value.push({ name: datas.fid, url: datas.fid })
      uploadedSuccessfully()
      proxy.$modal.msgSuccess('上传成功!')
    }
  })
}

// 上传结束处理
function uploadedSuccessfully() {
  if (number.value > 0 && uploadList.value.length === number.value) {
    fileList.value = fileList.value
      .filter((f) => f.url !== undefined)
      .concat(uploadList.value)
    uploadList.value = []
    number.value = 0
    emit('update:modelValue', listToString(fileList.value))
    proxy.$modal.closeLoading()
  }
}

完整代码:

<template>
  <div class="component-upload-image">
    <el-upload
      multiple
      action="#"
      :http-request="uploadImg"
      list-type="picture-card"
      :before-upload="handleBeforeUpload"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      ref="imageUpload"
      :before-remove="handleDelete"
      :show-file-list="true"
      :file-list="fileList"
      :on-preview="handlePictureCardPreview"
      :class="{ hide: fileList.length >= limit }"
    >
      <el-icon class="avatar-uploader-icon">
        <plus />
      </el-icon>
    </el-upload>
    <!-- 上传提示 -->
    <div class="el-upload__tip" v-if="showTip">
      请上传
      <template v-if="fileSize">
        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
      </template>
      <template v-if="fileType">
        格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
      </template>
      的文件
    </div>

    <el-dialog
      v-model="dialogVisible"
      title="预览"
      width="800px"
      append-to-body
    >
      <img
        :src="dialogImageUrl"
        style="display: block; max-width: 100%; margin: 0 auto"
      />
    </el-dialog>
  </div>
</template>

<script setup>
// import { getToken } from '@/utils/auth'
import { defineEmits } from 'vue'
import { uploadFile2 } from '@/utils/upload-file'
import dayjs from 'dayjs'

const props = defineProps({
  modelValue: [String, Object, Array],
  // 图片数量限制
  limit: {
    type: Number,
    default: 5,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
  // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => ['png', 'jpg', 'jpeg'],
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true,
  },
})

const { proxy } = getCurrentInstance()
const emit = defineEmits(['update:modelValue'])
const number = ref(0)
const uploadList = ref([])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const fileList = ref([])
const showTip = computed(
  () => props.isShowTip && (props.fileType || props.fileSize),
)
watch(
  () => props.modelValue,
  (val) => {
    if (val) {
      // 首先将值转为数组
      const list = Array.isArray(val) ? val : props.modelValue.split(',')
      // 然后将数组转为对象数组
      fileList.value = list.map((item) => {
        console.log(item, 'modelValue item')
        if (typeof item === 'string') {
          item = { name: item, url: item }
        }
        return item
      })
      return fileList.value
    }
      fileList.value = []
      return []
  },
  { deep: true, immediate: true },
)
// 使用腾讯云存储图片
function uploadImg({ file }) {
  const TODAY = dayjs().format('YYYY/MM/DD')
  uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, data) => {
    if (err) {
      number.value--
      proxy.$modal.closeLoading()
      proxy.$modal.msgError(data.msg)
      proxy.$refs.imageUpload.handleRemove(file)
      uploadedSuccessfully()
      this.$message.error(`上传失败:${err}`)
    } else {
      const imageUrl = `http://${data.Location}`
      uploadList.value.push({ name: imageUrl, url: imageUrl })
      proxy.$modal.msgSuccess('上传成功!')
      uploadedSuccessfully()
    }
  })
}
// 上传前loading加载
function handleBeforeUpload(file) {
  let isImg = false
  if (props.fileType.length) {
    let fileExtension = ''
    if (file.name.lastIndexOf('.') > -1) {
      fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
    }
    isImg = props.fileType.some((type) => {
      if (file.type.indexOf(type) > -1) return true
      if (fileExtension && fileExtension.indexOf(type) > -1) return true
      return false
    })
  } else {
    isImg = file.type.indexOf('image') > -1
  }
  if (!isImg) {
    proxy.$modal.msgError(
      `文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`,
    )
    return false
  }
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize
    if (!isLt) {
      proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`)
      return false
    }
  }
  proxy.$modal.loading('正在上传图片,请稍候...')
  number.value++
}

// 文件个数超出
function handleExceed() {
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`)
}

// 删除图片
function handleDelete(file) {
  console.log(file, 'file')
  const findex = fileList.value.map((f) => f.name).indexOf(file.name)
  if (findex > -1 && uploadList.value.length === number.value) {
    fileList.value.splice(findex, 1)
    emit('update:modelValue', getUrlToString(fileList.value))
    return false
  }
}

// 上传结束处理
function uploadedSuccessfully() {
  if (number.value > 0 && uploadList.value.length === number.value) {
    fileList.value = fileList.value
      .filter((f) => f.url !== undefined)
      .concat(uploadList.value)
    uploadList.value = []
    number.value = 0
    emit('update:modelValue', getUrlToString(fileList.value))
    proxy.$modal.closeLoading()
  }
}

// 上传失败
function handleUploadError() {
  proxy.$modal.msgError('上传图片失败')
  proxy.$modal.closeLoading()
}

// 预览
function handlePictureCardPreview(file) {
  dialogImageUrl.value = file.url
  dialogVisible.value = true
}
// 数组转换字符串,用于传参给后端
function getUrlToString(arr = [], separator = ',') {
if (Array.isArray(arr)) {
 return arr.map(i => i.url).join(separator)
}
return console.error('不是数组')
}




</script>

<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
  display: none;
}
</style>

3.在富文本使用

// 编辑器配置
const editorConfig = ref({
  placeholder: computed(() => props.placeholder),
  MENU_CONF: {
    uploadImage: {
      customUpload(file, insertFn) {
        console.log(file, insertFn, 'upload')
        const TODAY = dayjs().format('YYYY/MM/DD')
        uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, data) => {
          console.log(data, 'datas')
          console.log(file, 'datas')
          if (err) {
            ElMessage({
              message: `${file.name} 上传失败`,
              type: 'error',
            })
          } else {
            // 成功后,调用插入图片的函数
            const imageUrl = `http://${data.Location}`
            // console.log(data.Location, 'image')
            // console.log(imageUrl, 'image')
            insertFn(imageUrl, '', '')
          }
        })
      },
      // server: () => {

      // },
      // form-data fieldName ,默认值 'wangeditor-uploaded-image'
      fieldName: 'file',
      // 单个文件的最大体积限制,默认为 2M
      maxFileSize: 5 * 1024 * 1024, // 3M
      // 最多可上传几个文件,默认为 100
      maxNumberOfFiles: 10,
      // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['image/*'],
      // 自定义增加 http  header
      headers: {
        Authorization: `Bearer ${getToken()}`,
      },
      // 跨域是否传递 cookie ,默认为 false
      withCredentials: true,
      // 超时时间,默认为 10 秒
      timeout: 5 * 1000, // 5 秒
      // 上传失败
      onFailed(file) {
        ElMessage({
          message: `${file.name} 上传失败`,
          type: 'error',
        })
      },
      // 上传出错
      onError(file, err) {
        errorTips(err)
      },
      // 自定义插入
      customInsert(res, insertFn) {
        // 从 res 中找到 url alt href ,然后插入图片
        insertFn(res.url, '', '')
      },
    },
    uploadVideo: {
      customUpload(file, insertFn) {
        console.log(file, insertFn, 'upload')
        const TODAY = dayjs().format('YYYY/MM/DD')
        uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, data) => {
          console.log(data, 'datas')
          console.log(file, 'datas')
          if (err) {
            ElMessage({
              message: `${file.name} 上传失败`,
              type: 'error',
            })
          } else {
            // 成功后,调用插入图片的函数
            const videoUrl = `http://${data.Location}`
            // console.log(data.Location, 'videoUrl')
            // console.log(videoUrl, 'videoUrl')
            insertFn(videoUrl, '', '')
          }
        })
      },
      // server: `${import.meta.env.VITE_APP_BASE_API}/common/upload`,
      // form-data fieldName ,默认值 'wangeditor-uploaded-image'
      fieldName: 'file',
      // 单个文件的最大体积限制,默认为 2M
      maxFileSize: 20 * 1024 * 1024, // 10M
      // 最多可上传几个文件,默认为 100
      maxNumberOfFiles: 10,
      // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['video/*'],
      // 自定义增加 http  header
      headers: {
        Authorization: `Bearer ${getToken()}`,
      },
      // 跨域是否传递 cookie ,默认为 false
      withCredentials: true,
      // 超时时间,默认为 10 秒
      timeout: 15 * 1000, // 5 秒
      // 上传失败
      onFailed(file) {
        ElMessage({
          message: `${file.name} 上传失败`,
          type: 'error',
        })
      },
      // 上传出错
      onError(file, err) {
        errorTips(err)
      },
      // 自定义插入
      customInsert(res, insertFn) {
        // 从 res 中找到 url alt href ,然后插入
        insertFn(res.url, '', '')
      },
    },
  },
})

完整代码:

<template>
  <div style="border: 1px solid #ccc">
    <!-- 工具栏 -->
    <Toolbar
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      style="border-bottom: 1px solid #ccc"
    />
    <!-- 编辑器 -->
    <Editor
      v-model="valueHtml"
      :defaultConfig="editorConfig"
      :style="`height: ${height}px; overflow-y: hidden`"
      @onCreated="handleCreated"
    />
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, ref, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/auth'
import { uploadFile2 } from '@/utils/upload-file'
import dayjs from 'dayjs'

const props = defineProps({
  html: {
    type: String,
    default: '',
  },
  // 富文本高度
  height: {
    type: Number,
    default: 400,
  },
  // 是否为禁用状态
  disabled: {
    type: Boolean,
    default: false,
  },
  placeholder: {
    type: String,
    default: '请输入内容',
  },
})

// 编辑器实例,必须用 shallowRef,重要!
const editorRef = shallowRef()

// 内容 HTML
const valueHtml = ref()
watch(
  () => props.html,
  () => {
    valueHtml.value = props.html
  },
)

// 工具栏配置
const toolbarConfig = ref({})

// 编辑器配置
const editorConfig = ref({
  placeholder: computed(() => props.placeholder),
  MENU_CONF: {
    uploadImage: {
      customUpload(file, insertFn) {
        console.log(file, insertFn, 'upload')
        const TODAY = dayjs().format('YYYY/MM/DD')
        uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, data) => {
          console.log(data, 'datas')
          console.log(file, 'datas')
          if (err) {
            ElMessage({
              message: `${file.name} 上传失败`,
              type: 'error',
            })
          } else {
            // 成功后,调用插入图片的函数
            const imageUrl = `http://${data.Location}`
            console.log(data.Location, 'image')
            console.log(imageUrl, 'image')
            insertFn(imageUrl, '', '')
          }
        })
      },
      // server: () => {

      // },
      // form-data fieldName ,默认值 'wangeditor-uploaded-image'
      fieldName: 'file',
      // 单个文件的最大体积限制,默认为 2M
      maxFileSize: 5 * 1024 * 1024, // 3M
      // 最多可上传几个文件,默认为 100
      maxNumberOfFiles: 10,
      // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['image/*'],
      // 自定义增加 http  header
      headers: {
        Authorization: `Bearer ${getToken()}`,
      },
      // 跨域是否传递 cookie ,默认为 false
      withCredentials: true,
      // 超时时间,默认为 10 秒
      timeout: 5 * 1000, // 5 秒
      // 上传失败
      onFailed(file) {
        ElMessage({
          message: `${file.name} 上传失败`,
          type: 'error',
        })
      },
      // 上传出错
      onError(file, err) {
        errorTips(err)
      },
      // 自定义插入
      customInsert(res, insertFn) {
        // 从 res 中找到 url alt href ,然后插入图片
        insertFn(res.url, '', '')
      },
    },
    uploadVideo: {
      server: `${import.meta.env.VITE_APP_BASE_API}/common/upload`,
      // form-data fieldName ,默认值 'wangeditor-uploaded-image'
      fieldName: 'file',
      // 单个文件的最大体积限制,默认为 2M
      maxFileSize: 20 * 1024 * 1024, // 10M
      // 最多可上传几个文件,默认为 100
      maxNumberOfFiles: 10,
      // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
      allowedFileTypes: ['video/*'],
      // 自定义增加 http  header
      headers: {
        Authorization: `Bearer ${getToken()}`,
      },
      // 跨域是否传递 cookie ,默认为 false
      withCredentials: true,
      // 超时时间,默认为 10 秒
      timeout: 15 * 1000, // 5 秒
      // 上传失败
      onFailed(file) {
        ElMessage({
          message: `${file.name} 上传失败`,
          type: 'error',
        })
      },
      // 上传出错
      onError(file, err) {
        errorTips(err)
      },
      // 自定义插入
      customInsert(res, insertFn) {
        // 从 res 中找到 url alt href ,然后插入
        insertFn(res.url, '', '')
      },
    },
  },
})

function errorTips(err) {
  err = String(err)
  err = err.replace(/Error: /g, '错误:')
  err = err.replace(
    /exceeds maximum allowed size of/g,
    '超过了允许的最大上传大小',
  )
  ElMessage({
    message: `${err}`,
    type: 'error',
  })
}

// 获取 HTML 内容
const getHtml = () => {
  const res = editorRef.value.getHtml()
  if (res !== '<p><br></p>') {
    return res
  }
  return ''
}

// 暴露出去给父组件获取
defineExpose({
  getHtml,
})

const handleCreated = (editor) => {
  editorRef.value = editor // 记录 editor 实例,重要!
}

// 组件销毁时,及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})
</script>

<!-- 引入样式 -->
<style src="@wangeditor/editor/dist/css/style.css"></style>

4.裁剪图片头像使用

import { uploadFile2 } from '@/utils/upload-file'
/** 上传图片 */
function uploadImg() {
  proxy.$refs.cropper.getCropBlob(data => {
    console.log(data, 'data')
    const file = blobToFile(data, 'avatar.png')
    console.log(file, 'data')
    const TODAY = dayjs().format('YYYY/MM/DD')
    uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, datas) => {
      if (err) {
        proxy.$modal.error(`上传失败:${err}`)
      } else {
        open.value = false
        const imageUrl = `http://${datas.Location}`
        options.img = imageUrl
        emit('update:modelValue', options.img)
        userStore.avatar = options.img
        proxy.$modal.msgSuccess('修改成功')
        visible.value = false
      }
    })
  })
}

完整代码

<template>
  <div class="user-info-head" @click="editCropper()">
    <img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
    <el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
      <el-row>
        <el-col :xs="24" :md="12" :style="{ height: '350px' }">
          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            :outputType="options.outputType"
            @realTime="realTime"
            v-if="visible"
          />
        </el-col>
        <el-col :xs="24" :md="12" :style="{ height: '350px' }">
          <div class="avatar-upload-preview">
            <img :src="options.previews.url" :style="options.previews.img" />
          </div>
        </el-col>
      </el-row>
      <br />
      <el-row>
        <el-col :lg="2" :md="2">
          <el-upload
            action="#"
            :http-request="requestUpload"
            :show-file-list="false"
            :before-upload="beforeUpload"
          >
            <el-button>
              选择
              <el-icon class="el-icon--right"><Upload /></el-icon>
            </el-button>
          </el-upload>
        </el-col>
        <el-col :lg="{ span: 1, offset: 2 }" :md="2">
          <el-button icon="Plus" @click="changeScale(1)"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :md="2">
          <el-button icon="Minus" @click="changeScale(-1)"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :md="2">
          <el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
        </el-col>
        <el-col :lg="{ span: 1, offset: 1 }" :md="2">
          <el-button icon="RefreshRight" @click="rotateRight()"></el-button>
        </el-col>
        <el-col :lg="{ span: 2, offset: 6 }" :md="2">
          <el-button type="primary" @click="uploadImg()">提 交</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script setup>
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'
// import { uploadAvatar } from '@/api/system/user'
import useUserStore from '@/store/modules/user'
import { uploadFile2 } from '@/utils/upload-file'
import dayjs from 'dayjs'

const userStore = useUserStore()
const { proxy } = getCurrentInstance()

const open = ref(false)
const visible = ref(false)
const title = ref('修改头像')
const emit = defineEmits(['update:modelValue'])

// 图片裁剪数据
const options = reactive({
  img: userStore.avatar, // 裁剪图片的地址
  autoCrop: true, // 是否默认生成截图框
  autoCropWidth: 200, // 默认生成截图框宽度
  autoCropHeight: 200, // 默认生成截图框高度
  fixedBox: true, // 固定截图框大小 不允许改变
  outputType: 'png', // 默认生成截图为PNG格式
  previews: {}, // 预览数据
})

/** 编辑头像 */
function editCropper() {
  open.value = true
}
/** 打开弹出层结束时的回调 */
function modalOpened() {
  visible.value = true
}
/** 覆盖默认上传行为 */
function requestUpload() {
}
/** 向左旋转 */
function rotateLeft() {
  proxy.$refs.cropper.rotateLeft()
}
/** 向右旋转 */
function rotateRight() {
  proxy.$refs.cropper.rotateRight()
}
/** 图片缩放 */
function changeScale(num) {
  num = num || 1
  proxy.$refs.cropper.changeScale(num)
}
/** 上传预处理 */
function beforeUpload(file) {
  if (file.type.indexOf('image/') == -1) {
    proxy.$modal.msgError('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
  } else {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => {
      options.img = reader.result
    }
  }
}
/** 上传图片 */
function uploadImg() {
  proxy.$refs.cropper.getCropBlob(data => {
    console.log(data, 'data')
    const file = blobToFile(data, 'avatar.png')
    console.log(file, 'data')
    const TODAY = dayjs().format('YYYY/MM/DD')
    uploadFile2(`/upload/company-products/${TODAY}/`, file, (err, datas) => {
      if (err) {
        proxy.$modal.error(`上传失败:${err}`)
      } else {
        open.value = false
        const imageUrl = `http://${datas.Location}`
        options.img = imageUrl
        emit('update:modelValue', options.img)
        userStore.avatar = options.img
        proxy.$modal.msgSuccess('修改成功')
        visible.value = false
      }
    })
  })
}
// 将 Blob 数据转换为 File 对象
function blobToFile(blob, filename) {
  return new File([blob], filename, { type: blob.type })
}
// /** 上传图片 */
// function uploadImg() {
//   proxy.$refs.cropper.getCropBlob(data => {
//     let formData = new FormData()
//     formData.append('avatarfile', data)
//     uploadAvatar(formData).then(response => {
//       console.log(formData, 'formData')
//       open.value = false
//       options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl
//       userStore.avatar = options.img
//       proxy.$modal.msgSuccess('修改成功')
//       visible.value = false
//     })
//   })
// }
/** 实时预览 */
function realTime(data) {
  options.previews = data
}
/** 关闭窗口 */
function closeDialog() {
  options.img = userStore.avatar
  options.visible = false
}
</script>

<style lang='scss' scoped>
.user-info-head {
  position: relative;
  display: inline-block;
  height: 120px;
}

.user-info-head:hover:after {
  content: "+";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  color: #eee;
  background: rgba(0, 0, 0, 0.5);
  font-size: 24px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  cursor: pointer;
  line-height: 110px;
  border-radius: 50%;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值