123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- // import { ElImage, ElMessage, ElUpload } from 'element-plus'
- import { defineComponent } from 'vue'
- import styles from './index.module.less'
- import iconUpload from '../col-upload/images/icon_upload.png'
- // import Cropper from './cropper'
- import { VueCropper } from 'vue-cropper'
- import umiRequest from 'umi-request'
- import 'vue-cropper/dist/index.css'
- import {
- ElButton,
- ElCol,
- ElDialog,
- ElIcon,
- ElImage,
- ElMessage,
- ElUpload,
- ElRow
- } from 'element-plus'
- import { CirclePlus, Remove } from '@element-plus/icons-vue'
- import iconRate from '../col-upload/images/icon_rate.png'
- import request from '@/helpers/request'
- export default defineComponent({
- name: 'col-cropper',
- props: {
- modelValue: {
- type: String,
- default: ''
- },
- options: {
- // 裁切需要参数
- type: Object,
- default: {
- autoCrop: true, //是否默认生成截图框
- enlarge: 1, // 图片放大倍数
- autoCropWidth: 200, //默认生成截图框宽度
- autoCropHeight: 200, //默认生成截图框高度
- fixedBox: true, //是否固定截图框大小 不允许改变
- previewsCircle: true, //预览图是否是原圆形
- title: '上传图片'
- }
- },
- // 显示图片原始图片
- showSize: {
- type: Boolean,
- default: false
- },
- disabled: {
- type: Boolean,
- default: false
- },
- bucket: {
- type: String,
- default: 'daya'
- },
- size: {
- type: Number,
- default: 5 // 默认5M
- },
- accept: {
- type: String,
- default: 'images/*'
- },
- tips: {
- type: String,
- default: '请上传图片'
- },
- extraTips: {
- type: String,
- default: '图片最大不能超过5MB'
- },
- cropUploadSuccess: {
- type: Function,
- default: (data: string) => {}
- }
- },
- data() {
- return {
- isStopRun: false,
- loading: false,
- ossUploadUrl: 'https://ks3-cn-beijing.ksyuncs.com/' + this.bucket,
- dataObj: {
- policy: '',
- signature: '',
- key: '',
- KSSAccessKeyId: '',
- acl: 'public-read',
- name: ''
- },
- visible: false,
- img: null,
- optionsList: {
- img: '', //裁剪图片的地址
- autoCrop: true, //是否默认生成截图框
- autoCropWidth: 180, //默认生成截图框宽度
- autoCropHeight: 180, //默认生成截图框高度
- fixedBox: false, //是否固定截图框大小 不允许改变
- full: false,
- enlarge: 1, // 是否按照截图框比例输出 默认为1
- previewsCircle: true, //预览图是否是原圆形
- centerBox: true,
- outputType: 'png',
- title: '修改头像',
- name: null // 文件名称
- },
- previews: {} as any,
- url: {
- upload: '/sys/common/saveToImgByStr'
- },
- submitLoading: false
- }
- },
- methods: {
- onDelete() {
- // 删除图片
- this.$emit('update:modelValue', '')
- },
- //从本地选择文件
- async handleChange(info: any) {
- if (this.isStopRun) {
- return
- }
- this.loading = true
- const options = this.options
- this.getBase64(info.file, (imageUrl: any) => {
- const target = Object.assign({}, options, {
- img: imageUrl,
- name: info.file.name // 上传文件名
- })
- // ;(this as any).$refs.CropperModal.edit(target)
- this.edit(target)
- })
- },
- // 上传之前 格式与大小校验
- beforeUpload(file) {
- this.isStopRun = false
- var fileType = file.type
- if (fileType.indexOf('image') < 0) {
- ElMessage.warning('请上传图片')
- this.isStopRun = true
- return false
- }
- // const isJpgOrPng = this.acceptArray.includes(file.type)
- // if (!isJpgOrPng) {
- // ElMessage.error('你上传图片格式不正确!')
- // this.isStopRun = true
- // }
- console.log(this.size)
- const size = this.size || 0
- const isLtSize = file.size < size * 1024 * 1024
- if (!isLtSize) {
- ElMessage.error('图片大小不能超过' + this.size + 'MB!')
- this.isStopRun = true
- }
- return isLtSize
- },
- error() {
- this.remove()
- this.loading = false
- },
- remove() {
- this.onDelete()
- },
- //获取服务器返回的地址
- handleCropperSuccess(data: any) {
- //将返回的数据回显
- this.loading = false
- console.log(data, 'success')
- this.$emit('update:modelValue', data)
- // this.cropUploadSuccess(data)
- // this.$emit('cropUploadSuccess', data)
- // console.log(this.modelValue, 'modelValue')
- },
- // 取消上传
- handleCropperClose() {
- this.loading = false
- this.remove()
- },
- getBase64(img, callback) {
- const reader = new FileReader()
- reader.addEventListener('load', () => callback(reader.result))
- reader.readAsDataURL(img)
- },
- edit(record: any) {
- const { options } = this
- this.visible = true
- this.optionsList = Object.assign({}, options, record)
- console.log(this.options)
- },
- /**
- * 取消截图
- */
- cancelHandel() {
- this.visible = false
- // this.cropperNo()
- this.loading = false
- this.remove()
- },
- /**
- * 确认截图
- */
- okHandel() {
- ;(this as any).$refs.cropperRef.getCropBlob(async data => {
- this.submitLoading = true
- const options: any = this.options
- const fileName =
- (options.name ? options.name.split('.')[0] : +new Date()) + '.png'
- try {
- let key = new Date().getTime() + fileName
- let obj = {
- filename: fileName,
- bucketName: this.bucket,
- postData: {
- filename: fileName,
- acl: 'public-read',
- key: key,
- unknowValueField: []
- }
- }
- const res = await request.post('/api-website/getUploadSign', {
- data: obj
- })
- this.dataObj = {
- policy: res.data.policy,
- signature: res.data.signature,
- key: key,
- KSSAccessKeyId: res.data.kssAccessKeyId,
- acl: 'public-read',
- name: fileName
- }
- let formData = new FormData()
- for (let key in this.dataObj) {
- formData.append(key, this.dataObj[key])
- }
- formData.append('file', this.blobToFile(data, fileName), fileName)
- await umiRequest(this.ossUploadUrl, {
- method: 'POST',
- data: formData
- })
- console.log(this.ossUploadUrl + '/' + key)
- const uploadUrl = this.ossUploadUrl + '/' + key
- // this.cropperOk(uploadUrl)
- this.$emit('update:modelValue', uploadUrl)
- } catch (err: any) {
- ElMessage.error(err)
- } finally {
- this.submitLoading = false
- this.cancelHandel()
- }
- })
- },
- //转成blob
- blobToFile(Blob: any, fileName: any) {
- //兼容IE
- Blob.lastModifiedDate = new Date()
- Blob.name = fileName
- return Blob
- },
- base64ToFile(urlData: any, fileName: any) {
- let arr = urlData.split(',')
- let mime = arr[0].match(/:(.*?);/)[1]
- let bytes = atob(arr[1]) // 解码base64
- let n = bytes.length
- let ia = new Uint8Array(n)
- while (n--) {
- ia[n] = bytes.charCodeAt(n)
- }
- return new File([ia], fileName, { type: mime })
- },
- //移动框的事件
- realTime(data: any) {
- this.previews = data
- },
- //图片缩放
- changeScale(num: number) {
- num = num || 1
- ;(this as any).$refs.cropperRef.changeScale(num)
- },
- //向左旋转
- rotateLeft() {
- ;(this as any).$refs.cropperRef.rotateLeft()
- },
- //向右旋转
- rotateRight() {
- ;(this as any).$refs.cropperRef.rotateRight()
- }
- },
- render() {
- return (
- <div class={[styles.colUpload, 'w-full']}>
- <ElUpload
- disabled={this.disabled}
- showFileList={false}
- accept={this.accept}
- beforeUpload={this.beforeUpload}
- // @ts-ignore
- httpRequest={this.handleChange}
- // limit={1}
- ref="uploadRef"
- >
- <div
- ref="uploadDom"
- class={[styles.uploadClass, 'w-full']}
- style={{ height: '106px' }}
- >
- {this.modelValue ? (
- <ElImage
- src={this.modelValue}
- fit="cover"
- class={styles.uploadSection}
- />
- ) : (
- <div
- class={[
- styles.uploadSection,
- 'flex items-center flex-col justify-center'
- ]}
- >
- <img src={iconUpload} class="w-8 h-7 mb-3" />
- <p>{this.tips}</p>
- </div>
- )}
- </div>
- </ElUpload>
- <p class="text-3 text-[#999999] leading-6 pt-1">{this.extraTips}</p>
- <ElDialog
- modelValue={this.visible}
- onUpdate:modelValue={val => (this.visible = val)}
- appendToBody
- title={this.options.title}
- closeOnClickModal={false}
- width={'800px'}
- v-slots={{
- footer: () => (
- <span class="dialog-footer !text-center block">
- <ElButton
- onClick={this.cancelHandel}
- disabled={this.submitLoading}
- >
- 取消
- </ElButton>
- <ElButton
- type="primary"
- onClick={this.okHandel}
- loading={this.submitLoading}
- >
- 保 存
- </ElButton>
- </span>
- )
- }}
- >
- <ElRow>
- <ElCol xs={24} md={12} style={{ width: '350px' }}>
- <VueCropper
- ref="cropperRef"
- img={this.optionsList.img}
- info={true}
- autoCrop={this.optionsList.autoCrop}
- autoCropWidth={this.optionsList.autoCropWidth}
- full={this.optionsList.full}
- outputType={this.optionsList.outputType}
- autoCropHeight={this.optionsList.autoCropHeight}
- fixedBox={this.optionsList.fixedBox}
- enlarge={this.optionsList.enlarge}
- onRealTime={this.realTime}
- style={{ height: '350px' }}
- />
- <div class="flex pt-2">
- <div
- onClick={() => {
- this.changeScale(1)
- }}
- class="mr-2 cursor-pointer"
- title="放大"
- >
- <ElIcon size={30} color="#333">
- <CirclePlus />
- </ElIcon>
- </div>
- <div
- onClick={() => {
- this.changeScale(-1)
- }}
- class="mr-2 cursor-pointer"
- title="缩小"
- >
- <ElIcon size={30} color="#333">
- <Remove />
- </ElIcon>
- </div>
- <div
- onClick={this.rotateRight}
- title="向右旋转"
- class="cursor-pointer"
- >
- <img src={iconRate} class="w-[30px] h-[30px]" />
- </div>
- </div>
- </ElCol>
- <ElCol xs={24} md={12} style={{ height: '350px' }}>
- <div class={styles.previewImg}>
- <span>预览图片</span>
- <div
- class={
- this.optionsList.previewsCircle
- ? styles['avatar-upload-preview']
- : styles['avatar-upload-preview_range']
- }
- style={{
- width: this.optionsList.autoCropWidth + 'px',
- height: this.optionsList.autoCropHeight + 'px'
- }}
- >
- <ElImage src={this.previews.url} style={this.previews.img} />
- </div>
- </div>
- </ElCol>
- </ElRow>
- </ElDialog>
- </div>
- )
- }
- })
|