|
@@ -5,61 +5,44 @@ import {
|
|
|
NSpin,
|
|
|
NUpload,
|
|
|
NUploadDragger,
|
|
|
- UploadCustomRequestOptions,
|
|
|
- UploadFileInfo,
|
|
|
useMessage
|
|
|
} from 'naive-ui';
|
|
|
-import { defineComponent, watch, PropType, reactive, ref } from 'vue';
|
|
|
-import { policy } from '@/components/upload-file/api';
|
|
|
-import Copper from '@/components/upload-file/copper';
|
|
|
-import axios from 'axios';
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ reactive,
|
|
|
+ ref,
|
|
|
+ nextTick,
|
|
|
+ onMounted,
|
|
|
+ watch,
|
|
|
+ computed
|
|
|
+} from 'vue';
|
|
|
+import Cropper from 'cropperjs';
|
|
|
+import 'cropperjs/dist/cropper.css';
|
|
|
import styles from './index.module.less';
|
|
|
import iconUploadAdd from '../../../images/icon-upload2.png';
|
|
|
-import { NaturalTypeEnum, PageEnum } from '@/enums/pageEnum';
|
|
|
+import { NaturalTypeEnum } from '@/enums/pageEnum';
|
|
|
+import { getUploadSign, onOnlyFileUpload } from '/src/helpers/oss-file-upload';
|
|
|
import { formatUrlType } from '../upload-modal';
|
|
|
|
|
|
/**
|
|
|
* 1. 图片上传可以进行裁剪
|
|
|
- * 2. 视频上传可以选择某一帧做为封面
|
|
|
- * 3. 音频只用限制某一种格式
|
|
|
- * 4. 只支持单个上传,因为多个上传没有办法去处理,即有视频,图片等
|
|
|
*/
|
|
|
export default defineComponent({
|
|
|
name: 'upload-file',
|
|
|
props: {
|
|
|
- fileList: {
|
|
|
+ img: {
|
|
|
type: String,
|
|
|
default: ''
|
|
|
},
|
|
|
- imageList: {
|
|
|
- type: Array,
|
|
|
- default: () => []
|
|
|
- },
|
|
|
accept: {
|
|
|
// 支持类型
|
|
|
type: String,
|
|
|
default: '.jpg,.png,.jpeg,.gif'
|
|
|
},
|
|
|
- max: {
|
|
|
- type: Number as PropType<number>,
|
|
|
- default: 1
|
|
|
- },
|
|
|
- multiple: {
|
|
|
- type: Boolean as PropType<boolean>,
|
|
|
- default: false
|
|
|
- },
|
|
|
- disabled: {
|
|
|
- type: Boolean as PropType<boolean>,
|
|
|
- default: false
|
|
|
- },
|
|
|
bucketName: {
|
|
|
type: String,
|
|
|
default: 'gyt'
|
|
|
},
|
|
|
- directoryDnd: {
|
|
|
- type: Boolean as PropType<boolean>,
|
|
|
- default: false
|
|
|
- },
|
|
|
path: {
|
|
|
type: String,
|
|
|
default: ''
|
|
@@ -68,11 +51,6 @@ export default defineComponent({
|
|
|
type: String,
|
|
|
default: ''
|
|
|
},
|
|
|
- cropper: {
|
|
|
- // 是否裁切, 只有图片才支持 - 失效(不支持)
|
|
|
- type: Boolean as PropType<boolean>,
|
|
|
- default: false
|
|
|
- },
|
|
|
options: {
|
|
|
type: Object,
|
|
|
default: () => {
|
|
@@ -80,8 +58,8 @@ export default defineComponent({
|
|
|
viewMode: 0,
|
|
|
autoCrop: true, //是否默认生成截图框
|
|
|
enlarge: 1, // 图片放大倍数
|
|
|
- autoCropWidth: 200, //默认生成截图框宽度
|
|
|
- autoCropHeight: 200, //默认生成截图框高度
|
|
|
+ autoCropWidth: 640, //默认生成截图框宽度
|
|
|
+ autoCropHeight: 360, //默认生成截图框高度
|
|
|
fixedBox: false, //是否固定截图框大小 不允许改变
|
|
|
previewsCircle: true, //预览图是否是原图形
|
|
|
title: '上传图片'
|
|
@@ -89,68 +67,33 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
- emits: [
|
|
|
- 'update:fileList',
|
|
|
- 'close',
|
|
|
- 'readFileInputEventAsArrayBuffer',
|
|
|
- 'remove',
|
|
|
- 'finished'
|
|
|
- ],
|
|
|
- setup(props, { emit, expose, slots }) {
|
|
|
+ emits: ['close', 'confirm'],
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const imgCropper = ref();
|
|
|
const ossUploadUrl = `https://${props.bucketName}.ks3-cn-beijing.ksyuncs.com/`;
|
|
|
const message = useMessage();
|
|
|
const visiable = ref<boolean>(false);
|
|
|
const btnLoading = ref<boolean>(false);
|
|
|
- const tempFiileBuffer = ref();
|
|
|
const uploadRef = ref();
|
|
|
- const state = reactive([
|
|
|
- // {
|
|
|
- // policy: '',
|
|
|
- // signature: '',
|
|
|
- // key: '',
|
|
|
- // KSSAccessKeyId: '',
|
|
|
- // acl: 'public-read',
|
|
|
- // name: ''
|
|
|
- // }
|
|
|
- ]) as any;
|
|
|
+ const copperOptions = ref({
|
|
|
+ img: '', //裁剪图片的地址
|
|
|
+ autoCrop: true, //是否默认生成截图框
|
|
|
+ autoCropWidth: 180, //默认生成截图框宽度
|
|
|
+ autoCropHeight: 180, //默认生成截图框高度
|
|
|
+ fixedBox: true, //是否固定截图框大小 不允许改变
|
|
|
+ full: false,
|
|
|
+ enlarge: 1, // 是否按照截图框比例输出 默认为1
|
|
|
+ previewsCircle: true, //预览图是否是原圆形
|
|
|
+ centerBox: true,
|
|
|
+ outputType: 'png',
|
|
|
+ title: '修改头像',
|
|
|
+ name: null // 文件名称
|
|
|
+ } as any);
|
|
|
+ const state = reactive({
|
|
|
+ myCropper: null as any,
|
|
|
+ cropperReady: false
|
|
|
+ }) as any;
|
|
|
|
|
|
- const fileListRef = ref<UploadFileInfo[]>([]);
|
|
|
- const initFileList = () => {
|
|
|
- if (props.fileList) {
|
|
|
- const splitName = props.fileList.split('/');
|
|
|
- fileListRef.value = [
|
|
|
- {
|
|
|
- id: new Date().getTime().toString(),
|
|
|
- name: splitName[splitName.length - 1],
|
|
|
- status: 'finished',
|
|
|
- url: props.fileList
|
|
|
- }
|
|
|
- ];
|
|
|
- } else {
|
|
|
- fileListRef.value = [];
|
|
|
- }
|
|
|
- };
|
|
|
- initFileList();
|
|
|
- watch(
|
|
|
- () => props.imageList,
|
|
|
- () => {
|
|
|
- initFileList();
|
|
|
- }
|
|
|
- );
|
|
|
- watch(
|
|
|
- () => props.fileList,
|
|
|
- () => {
|
|
|
- initFileList();
|
|
|
- }
|
|
|
- );
|
|
|
- const handleClearFile = () => {
|
|
|
- uploadRef.value?.clear();
|
|
|
- };
|
|
|
- expose({
|
|
|
- handleClearFile
|
|
|
- });
|
|
|
-
|
|
|
- const CropperModal = ref();
|
|
|
const onBeforeUpload = async (options: any) => {
|
|
|
const file = options.file;
|
|
|
// 文件大小
|
|
@@ -161,76 +104,22 @@ export default defineComponent({
|
|
|
: file.type.includes('audio')
|
|
|
? NaturalTypeEnum.SONG
|
|
|
: NaturalTypeEnum.VIDEO;
|
|
|
- if (!file.type.includes('image')) {
|
|
|
+ if (type !== NaturalTypeEnum.IMG) {
|
|
|
message.error('上传文件格式错误');
|
|
|
return false;
|
|
|
}
|
|
|
- const size = type === 'IMG' ? 2 : type === 'SONG' ? 20 : 500;
|
|
|
+ const size = 10; //type === 'IMG' ? 10 : type === 'SONG' ? 20 : 500;
|
|
|
if (size) {
|
|
|
isLt2M = file.file.size / 1024 / 1024 < size;
|
|
|
if (!isLt2M) {
|
|
|
- message.error(`文件大小不能超过${size}M`);
|
|
|
+ message.error(`图片大小不能超过${size}M`);
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if (!isLt2M) {
|
|
|
- return isLt2M;
|
|
|
- }
|
|
|
- // 是否裁切
|
|
|
- // if (props.cropper && type === 'IMG') {
|
|
|
- // getBase64(file.file, (imageUrl: any) => {
|
|
|
- // const target = Object.assign({}, props.options, {
|
|
|
- // img: imageUrl,
|
|
|
- // name: file.file.name // 上传文件名
|
|
|
- // });
|
|
|
- // visiable.value = true;
|
|
|
-
|
|
|
- // setTimeout(() => {
|
|
|
- // CropperModal.value?.edit(target);
|
|
|
- // }, 100);
|
|
|
- // });
|
|
|
- // return false;
|
|
|
- // }
|
|
|
-
|
|
|
- // try {
|
|
|
- // btnLoading.value = true;
|
|
|
- // const name = file.file.name;
|
|
|
- // const suffix = name.slice(name.lastIndexOf('.'));
|
|
|
- // const fileName = `${props.path}${
|
|
|
- // props.fileName || Date.now() + suffix
|
|
|
- // }`;
|
|
|
- // const obj = {
|
|
|
- // filename: fileName,
|
|
|
- // bucketName: props.bucketName,
|
|
|
- // postData: {
|
|
|
- // filename: fileName,
|
|
|
- // acl: 'public-read',
|
|
|
- // key: fileName,
|
|
|
- // unknowValueField: []
|
|
|
- // }
|
|
|
- // };
|
|
|
- // const { data } = await policy(obj);
|
|
|
-
|
|
|
- // state.push({
|
|
|
- // id: file.id,
|
|
|
- // tempFiileBuffer: file.file,
|
|
|
- // policy: data.policy,
|
|
|
- // signature: data.signature,
|
|
|
- // acl: 'public-read',
|
|
|
- // key: fileName,
|
|
|
- // KSSAccessKeyId: data.kssAccessKeyId,
|
|
|
- // name: fileName
|
|
|
- // });
|
|
|
-
|
|
|
- // // tempFiileBuffer.value = file.file;
|
|
|
- // } catch {
|
|
|
- // //
|
|
|
- // // message.error('上传失败')
|
|
|
- // btnLoading.value = false;
|
|
|
- // return false;
|
|
|
- // }
|
|
|
- return true;
|
|
|
+ getBase64(file.file, (imageUrl: any) => {
|
|
|
+ cropperBefore(imageUrl, file.file.name);
|
|
|
+ });
|
|
|
+ return false;
|
|
|
};
|
|
|
const getBase64 = async (img: any, callback: any) => {
|
|
|
const reader = new FileReader();
|
|
@@ -238,107 +127,57 @@ export default defineComponent({
|
|
|
reader.readAsDataURL(img);
|
|
|
};
|
|
|
|
|
|
- const onFinish = (options: any) => {
|
|
|
- console.log(options, 'onFinish');
|
|
|
- onFinishAfter(options);
|
|
|
- };
|
|
|
- const onFinishAfter = async (options: any) => {
|
|
|
- const item = state.find((c: any) => c.id == options.file.id);
|
|
|
- const url = ossUploadUrl + item.key;
|
|
|
- const type = formatUrlType(url);
|
|
|
- let coverImg = '';
|
|
|
- if (type === 'IMG') {
|
|
|
- coverImg = url;
|
|
|
- } else if (type === 'SONG') {
|
|
|
- coverImg = PageEnum.SONG_DEFAULT_COVER;
|
|
|
- } else if (type === 'VIDEO') {
|
|
|
- // 获取视频封面图
|
|
|
- coverImg = await getVideoCoverImg(item.tempFiileBuffer);
|
|
|
- }
|
|
|
- emit('update:fileList', url);
|
|
|
- emit('readFileInputEventAsArrayBuffer', item.tempFiileBuffer);
|
|
|
- console.log(url, 'url onFinishAfter');
|
|
|
- emit('finished', {
|
|
|
- coverImg,
|
|
|
- content: url
|
|
|
+ const cropperBefore = (imageUrl: string, name?: string) => {
|
|
|
+ const target = Object.assign({}, props.options, {
|
|
|
+ img: imageUrl,
|
|
|
+ name // 上传文件名
|
|
|
});
|
|
|
|
|
|
- options.file.url = url;
|
|
|
- visiable.value = false;
|
|
|
- btnLoading.value = false;
|
|
|
- };
|
|
|
- const getVideoMsg = (file: any) => {
|
|
|
- return new Promise(resolve => {
|
|
|
- // let dataURL = '';
|
|
|
- const videoElement = document.createElement('video');
|
|
|
- videoElement.currentTime = 1;
|
|
|
- videoElement.src = URL.createObjectURL(file);
|
|
|
- videoElement.addEventListener('loadeddata', function () {
|
|
|
- const canvas: any = document.createElement('canvas'),
|
|
|
- width = videoElement.videoWidth, //canvas的尺寸和图片一样
|
|
|
- height = videoElement.videoHeight;
|
|
|
- canvas.width = width;
|
|
|
- canvas.height = height;
|
|
|
- canvas.getContext('2d').drawImage(videoElement, 0, 0, width, height); //绘制canvas
|
|
|
- // dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
|
|
|
- console.log(canvas);
|
|
|
- canvas.toBlob((blob: any) => {
|
|
|
- // console.log(blob);
|
|
|
- resolve(blob);
|
|
|
- });
|
|
|
- });
|
|
|
+ visiable.value = true;
|
|
|
+ copperOptions.value = Object.assign({}, copperOptions.value, target);
|
|
|
+ nextTick(() => {
|
|
|
+ initImgCropper();
|
|
|
});
|
|
|
};
|
|
|
|
|
|
- const getVideoCoverImg = async (file: any) => {
|
|
|
+ const initImgCropper = () => {
|
|
|
try {
|
|
|
- btnLoading.value = true;
|
|
|
- const imgBlob: any = await getVideoMsg(file || tempFiileBuffer.value);
|
|
|
- const fileName = `${props.path}${Date.now() + '.png'}`;
|
|
|
- const obj = {
|
|
|
- filename: fileName,
|
|
|
- bucketName: props.bucketName,
|
|
|
- postData: {
|
|
|
- filename: fileName,
|
|
|
- acl: 'public-read',
|
|
|
- key: fileName,
|
|
|
- unknowValueField: []
|
|
|
+ state.cropperReady = true;
|
|
|
+ state.myCropper = new Cropper(imgCropper.value, {
|
|
|
+ viewMode: 1, //定义裁剪器的视图模式。如果将viewMode设置为0,则裁剪框可以延伸到画布外部,而值为1、2或3将限制裁剪框的大小为画布的大小。viewMode为2或3会将画布限制为容器。请注意,如果画布和容器的比例相同,则2和3之间没有差别。
|
|
|
+ dragMode: 'move', //定义的拖动模式裁剪器.canvas和容器一样,2和3没有区别。move:移动画布 crop:创建新的裁剪框(默认) none:什么也不做
|
|
|
+ //定义裁剪框的固定纵横比。默认情况下,裁剪框为自由比率。
|
|
|
+ aspectRatio:
|
|
|
+ copperOptions.value.autoCropWidth /
|
|
|
+ copperOptions.value.autoCropHeight,
|
|
|
+ initialAspectRatio: 1,
|
|
|
+ autoCropArea: 1, //定义0到1之间的fA编号。定义自动裁剪区域大小(百分比)。默认0.8
|
|
|
+ cropBoxMovable: false, //允许通过拖动移动裁剪框。默认true
|
|
|
+ cropBoxResizable: false, //以通过拖动来调整裁剪框的大小 默认true
|
|
|
+ background: true, //显示容器的网格背景
|
|
|
+ movable: true, //移动图像
|
|
|
+ modal: true,
|
|
|
+ preview: '.before',
|
|
|
+ ready: () => {
|
|
|
+ state.cropperReady = false;
|
|
|
}
|
|
|
- };
|
|
|
- const { data } = await policy(obj);
|
|
|
-
|
|
|
- const fileParams = {
|
|
|
- policy: data.policy,
|
|
|
- signature: data.signature,
|
|
|
- key: fileName,
|
|
|
- acl: 'public-read',
|
|
|
- KSSAccessKeyId: data.kssAccessKeyId,
|
|
|
- name: fileName
|
|
|
- } as any;
|
|
|
- const formData = new FormData();
|
|
|
- for (const key in fileParams) {
|
|
|
- formData.append(key, fileParams[key]);
|
|
|
- }
|
|
|
-
|
|
|
- formData.append('file', imgBlob);
|
|
|
- await axios.post(ossUploadUrl, formData);
|
|
|
-
|
|
|
- const url = ossUploadUrl + fileName;
|
|
|
- return url;
|
|
|
- } finally {
|
|
|
- btnLoading.value = false;
|
|
|
+ });
|
|
|
+ } catch {
|
|
|
+ //
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- const onRemove = async () => {
|
|
|
- emit('update:fileList', '');
|
|
|
- emit('remove');
|
|
|
- btnLoading.value = false;
|
|
|
- };
|
|
|
-
|
|
|
- // 裁切失败
|
|
|
- // const cropperNo = () => {}
|
|
|
// 裁切成功
|
|
|
+ const onSubmit = () => {
|
|
|
+ state.myCropper
|
|
|
+ .getCroppedCanvas({
|
|
|
+ imageSmoothingQuality: 'high'
|
|
|
+ })
|
|
|
+ .toBlob((blob: any) => {
|
|
|
+ btnLoading.value = true;
|
|
|
+ cropperOk(blob);
|
|
|
+ });
|
|
|
+ };
|
|
|
const cropperOk = async (blob: any) => {
|
|
|
try {
|
|
|
const fileName = `${props.path}${
|
|
@@ -350,120 +189,119 @@ export default defineComponent({
|
|
|
postData: {
|
|
|
filename: fileName,
|
|
|
acl: 'public-read',
|
|
|
- key: fileName,
|
|
|
- unknowValueField: []
|
|
|
+ key: fileName
|
|
|
}
|
|
|
};
|
|
|
- const { data } = await policy(obj);
|
|
|
-
|
|
|
- state.policy = data.policy;
|
|
|
- state.signature = data.signature;
|
|
|
- state.key = fileName;
|
|
|
- state.KSSAccessKeyId = data.kssAccessKeyId;
|
|
|
- state.name = fileName;
|
|
|
-
|
|
|
- const formData = new FormData();
|
|
|
- for (const key in state) {
|
|
|
- formData.append(key, state[key]);
|
|
|
- }
|
|
|
- formData.append('file', blob);
|
|
|
|
|
|
- await axios.post(ossUploadUrl, formData).then(() => {
|
|
|
- const url = ossUploadUrl + state.key;
|
|
|
- const splitName = url.split('/');
|
|
|
- fileListRef.value = [
|
|
|
- {
|
|
|
- id: new Date().getTime().toString(),
|
|
|
- name: splitName[splitName.length - 1],
|
|
|
- status: 'finished',
|
|
|
- url: url
|
|
|
- }
|
|
|
- ];
|
|
|
- emit('update:fileList', url);
|
|
|
- emit('finished', {
|
|
|
- coverImg: url,
|
|
|
- content: url
|
|
|
- });
|
|
|
- visiable.value = false;
|
|
|
- });
|
|
|
+ const { data } = await getUploadSign(obj);
|
|
|
+ const formData = {
|
|
|
+ policy: data.policy,
|
|
|
+ signature: data.signature,
|
|
|
+ acl: 'public-read',
|
|
|
+ key: fileName,
|
|
|
+ KSSAccessKeyId: data.kssAccessKeyId,
|
|
|
+ name: fileName,
|
|
|
+ file: blob
|
|
|
+ };
|
|
|
+ const res = await onOnlyFileUpload(ossUploadUrl, formData);
|
|
|
+ emit('confirm', res);
|
|
|
+ emit('close');
|
|
|
} catch {
|
|
|
- return false;
|
|
|
+ //
|
|
|
}
|
|
|
+ btnLoading.value = false;
|
|
|
};
|
|
|
|
|
|
- const onCustomRequest = ({
|
|
|
- file,
|
|
|
- // data,
|
|
|
- // headers,
|
|
|
- // withCredentials,
|
|
|
- action,
|
|
|
- onFinish,
|
|
|
- onError,
|
|
|
- onProgress
|
|
|
- }: UploadCustomRequestOptions) => {
|
|
|
- // const item = state.find((c: any) => {
|
|
|
- // return c.id == file.id;
|
|
|
- // });
|
|
|
-
|
|
|
- // item.file = file;
|
|
|
- // onFileUpload({ file, action, data: item, onProgress, onFinish, onError });
|
|
|
- console.log(file);
|
|
|
- };
|
|
|
+ watch(
|
|
|
+ () => props.img,
|
|
|
+ () => {
|
|
|
+ if (props.img && formatUrlType(props.img) === NaturalTypeEnum.IMG) {
|
|
|
+ cropperBefore(props.img);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
|
|
|
+ onMounted(() => {
|
|
|
+ if (props.img && formatUrlType(props.img) === NaturalTypeEnum.IMG) {
|
|
|
+ cropperBefore(props.img);
|
|
|
+ }
|
|
|
+ });
|
|
|
return () => (
|
|
|
<div class={styles.uploadFile}>
|
|
|
<div class={styles.uploadHeader}>
|
|
|
<div class={styles.headerItem}>上传封面</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class={styles.uploadContainer}>
|
|
|
- <NUpload
|
|
|
- ref={uploadRef}
|
|
|
- action={ossUploadUrl}
|
|
|
- customRequest={onCustomRequest}
|
|
|
- v-model:fileList={fileListRef.value}
|
|
|
- accept=".jpg,jpeg,.png"
|
|
|
- multiple={false}
|
|
|
- max={1}
|
|
|
- showFileList={false}
|
|
|
- showPreviewButton
|
|
|
- onBeforeUpload={(options: any) => onBeforeUpload(options)}
|
|
|
- onFinish={(options: any) => {
|
|
|
- onFinish(options);
|
|
|
- }}
|
|
|
- onRemove={(options: any) => onRemove()}>
|
|
|
- <NUploadDragger>
|
|
|
- <div class={styles.uploadBtn}>
|
|
|
- <img src={iconUploadAdd} class={styles.iconUploadAdd} />
|
|
|
- <p>点击或将图片拖至此区域</p>
|
|
|
- <span>(建议比例16:9)</span>
|
|
|
+ {!visiable.value ? (
|
|
|
+ <div class={styles.uploadContainer}>
|
|
|
+ <NUpload
|
|
|
+ ref={uploadRef}
|
|
|
+ accept={props.accept}
|
|
|
+ multiple={false}
|
|
|
+ max={1}
|
|
|
+ showFileList={false}
|
|
|
+ showPreviewButton
|
|
|
+ onBeforeUpload={(options: any) => onBeforeUpload(options)}
|
|
|
+ // onFinish={(options: any) => {
|
|
|
+ // onFinish(options);
|
|
|
+ // }}
|
|
|
+ // onRemove={(options: any) => onRemove()}
|
|
|
+ >
|
|
|
+ <NUploadDragger>
|
|
|
+ <div class={styles.uploadBtn}>
|
|
|
+ <img src={iconUploadAdd} class={styles.iconUploadAdd} />
|
|
|
+ <p>点击或将图片拖至此区域</p>
|
|
|
+ <span>(建议比例16:9)</span>
|
|
|
+ </div>
|
|
|
+ </NUploadDragger>
|
|
|
+ </NUpload>
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <div class={styles.uploadContainer}>
|
|
|
+ <NSpin show={state.cropperReady}>
|
|
|
+ <div class={styles.imgCropperSection}>
|
|
|
+ {copperOptions.value?.img && (
|
|
|
+ <img
|
|
|
+ ref={imgCropper}
|
|
|
+ src={copperOptions.value?.img}
|
|
|
+ style={{
|
|
|
+ opacity: state.myCropper?.ready ? '1' : '0'
|
|
|
+ }}
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ )}
|
|
|
</div>
|
|
|
- </NUploadDragger>
|
|
|
- </NUpload>
|
|
|
- </div>
|
|
|
+ </NSpin>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
|
|
|
<div class={styles.uploadBtnGroup}>
|
|
|
- <NButton type="default">重新选择</NButton>
|
|
|
+ {visiable.value ? (
|
|
|
+ <NButton
|
|
|
+ type="default"
|
|
|
+ onClick={() => {
|
|
|
+ copperOptions.value.img = '';
|
|
|
+ visiable.value = false;
|
|
|
+ }}>
|
|
|
+ 重新选择
|
|
|
+ </NButton>
|
|
|
+ ) : (
|
|
|
+ <span></span>
|
|
|
+ )}
|
|
|
|
|
|
<NSpace>
|
|
|
- <NButton type="default">取消</NButton>
|
|
|
- <NButton type="primary">保存封面</NButton>
|
|
|
+ <NButton type="default" onClick={() => emit('close')}>
|
|
|
+ 取消
|
|
|
+ </NButton>
|
|
|
+ <NButton
|
|
|
+ type="primary"
|
|
|
+ onClick={() => onSubmit()}
|
|
|
+ disabled={!visiable.value}
|
|
|
+ loading={btnLoading.value}>
|
|
|
+ 保存封面
|
|
|
+ </NButton>
|
|
|
</NSpace>
|
|
|
</div>
|
|
|
- <NModal
|
|
|
- v-model:show={visiable.value}
|
|
|
- preset="dialog"
|
|
|
- showIcon={false}
|
|
|
- class={['modalTitle background']}
|
|
|
- title="上传图片"
|
|
|
- style={{ width: '800px' }}>
|
|
|
- {/* @cropper-no="error" @cropper-ok="success" */}
|
|
|
- <Copper
|
|
|
- ref={CropperModal}
|
|
|
- onClose={() => (visiable.value = false)}
|
|
|
- onCropperOk={cropperOk}
|
|
|
- />
|
|
|
- </NModal>
|
|
|
</div>
|
|
|
);
|
|
|
}
|