安装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>