mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-09 10:56:50 +08:00
feat(components): 添加图片裁剪组件
- 新增 RenderCropper组件,用于图片上传和裁剪功能 - 在 knowledge 页面中集成图片裁剪组件 - 在主文件中注册图片裁剪组件- 优化了 label 样式,注释掉行高属性
This commit is contained in:
201
src/components/RenderCropper/index.vue
Normal file
201
src/components/RenderCropper/index.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
:file-list="fileList"
|
||||
:on-change="change"
|
||||
>
|
||||
<i slot="default" class="el-icon-plus"></i>
|
||||
<div slot="file" slot-scope="{ file }">
|
||||
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span class="el-upload-list__item-delete" @click="handleRemove(file)">
|
||||
<i class="el-icon-delete"></i>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
|
||||
<r-dialog
|
||||
title="图片裁剪"
|
||||
:visible.sync="visible"
|
||||
@confirm="confirm"
|
||||
width="600px"
|
||||
>
|
||||
<div class="flex">
|
||||
<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>
|
||||
</r-dialog>
|
||||
</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 = []
|
||||
this.visible = true
|
||||
// setTimeout(() => {
|
||||
// this.cropper = new Cropper('#image', {})
|
||||
// }, 300)
|
||||
},
|
||||
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.fileList.push(res)
|
||||
this.$emit('getFiles', this.fileList)
|
||||
this.visible = false
|
||||
})
|
||||
// 根据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: 50vh;
|
||||
}
|
||||
|
||||
.cropperSelection {
|
||||
//width: 20vw;
|
||||
max-height: 30vw !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user