feat(intelligent-agent): 添加智能体头像上传功能

- 新增 cropper 组件用于图片裁剪
- 在智能体信息组件中集成 cropper 组件
- 添加图片上传和裁剪的相关逻辑和接口
- 优化智能体列表和详情页面的头像显示
This commit is contained in:
陈昱达
2025-04-29 15:01:15 +08:00
parent dcf80a26b1
commit f7e20fe0c4
3 changed files with 340 additions and 27 deletions

View File

@@ -0,0 +1,220 @@
<template>
<div style="width: 100%;height: 100%">
<el-upload
class="upload-picture-action"
v-show="fileList.length <= 0"
action="#"
drag
list-type="picture-card"
:show-file-list="false"
:auto-upload="false"
:limit="1"
:file-list="fileList"
:on-change="change"
>
<p>点击上传图片或者将图片拖拽到此处</p>
</el-upload>
<div
v-if="fileList.length > 0"
class="flex"
style="width: 100%;height: 100%"
>
<cropper-canvas style="width: 100%;flex:1" cover image>
<cropper-image
:src="file.url"
alt="Picture"
rotatable
scalable
skewable
translatable
></cropper-image>
<cropper-shade hidden></cropper-shade>
<cropper-handle action="select" plain></cropper-handle>
<cropper-selection
id="cropperSelection"
movable
resizable
x="150"
y="100"
width="275"
height="275"
ref="selection"
>
<cropper-handle
action="move"
theme-color="rgba(255, 255, 255, 0.35)"
></cropper-handle>
<cropper-handle action="n-resize"></cropper-handle>
<cropper-handle action="e-resize"></cropper-handle>
<cropper-handle action="s-resize"></cropper-handle>
<cropper-handle action="w-resize"></cropper-handle>
<cropper-handle action="ne-resize"></cropper-handle>
<cropper-handle action="nw-resize"></cropper-handle>
<cropper-handle action="se-resize"></cropper-handle>
<cropper-handle action="sw-resize"></cropper-handle>
</cropper-selection>
</cropper-canvas>
<div
class="cropperSelection"
style="flex:0;border-radius: 8px; border: 1px solid #ccc;overflow: hidden"
>
<!-- 修改: 添加 selection 属性并绑定到 file.url -->
<cropper-viewer
style="width: 100%;height: 100%"
selection="#cropperSelection"
initial-aspect-ratio="1.5"
initial-coverage="0.5"
></cropper-viewer>
</div>
</div>
</div>
</template>
<script>
import Cropper from 'cropperjs'
export default {
name: 'index',
data() {
return {
fileList: [],
cropper: null,
imageUrl: '',
visible: false,
file: {
url: ''
}
}
},
props: {},
watch: {},
components: {},
filters: {},
methods: {
handleRemove() {
this.fileList = []
},
change(file) {
this.file = file
this.fileList = [file]
// this.fileList = []
// this.visible = true
// setTimeout(() => {
// this.cropper = new Cropper('#image', {})
// }, 300)
},
reset() {
this.fileList = []
this.file = {}
},
confirm() {
this.$refs.selection.$toCanvas().then(canvas => {
// 根据canvas 生成一个图片 并转换成file
const image = canvas.toDataURL()
this.dataURLtoFile(image, this.file.name).then(res => {
// 文件生成 bolburl
const blobUrl = URL.createObjectURL(res)
res.url = blobUrl
this.file = {}
this.fileList = []
// this.fileList.push(res)
this.$emit('getFiles', [res])
// this.fileList = []
})
// 根据canvas 生成一个图片
})
},
// 修改: 优化 base64 转文件的逻辑,增加压缩功能
dataURLtoFile(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)
}
// 创建临时 canvas 元素用于压缩图片
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
// 返回一个 Promise确保异步操作完成后再返回文件
return new Promise(resolve => {
img.src = dataurl
img.onload = () => {
// 限制最大宽度或高度为 800px可根据需求调整
const maxWidthOrHeight = 800
let width = img.width
let height = img.height
if (width > height) {
if (width > maxWidthOrHeight) {
height *= maxWidthOrHeight / width
width = maxWidthOrHeight
}
} else {
if (height > maxWidthOrHeight) {
width *= maxWidthOrHeight / height
height = maxWidthOrHeight
}
}
canvas.width = width
canvas.height = height
ctx.drawImage(img, 0, 0, width, height)
// 将 canvas 转换为 base64质量设置为 0.8(可根据需求调整)
const compressedDataUrl = canvas.toDataURL(mime, 0.8)
// 将压缩后的 base64 转换为文件
const compressedArr = compressedDataUrl.split(',')
const compressedBstr = atob(compressedArr[1])
const compressedN = compressedBstr.length
const compressedU8arr = new Uint8Array(compressedN)
for (let i = 0; i < compressedN; i++) {
compressedU8arr[i] = compressedBstr.charCodeAt(i)
}
resolve(new File([compressedU8arr], filename, { type: mime }))
}
})
}
},
created() {},
mounted() {},
computed: {}
}
</script>
<style lang="scss">
cropper-canvas {
height: 100%;
}
.cropperSelection {
//width: 20vw;
//max-height: 30vw !important;
}
.upload-picture-action {
height: 100%;
width: 100%;
& .el-upload--picture-card {
height: 100%;
width: 100%;
& .el-upload-dragger {
border: unset;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
& el-upload-dragger {
}
}
}
</style>