123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- import { PropType, computed, defineComponent, reactive, ref } from 'vue';
- import styles from './index.module.less';
- import {
- NButton,
- NSpace,
- NUpload,
- NUploadDragger,
- UploadCustomRequestOptions,
- UploadFileInfo,
- useMessage
- } from 'naive-ui';
- // import iconUploadAdd from '../../../images/icon-upload-add.png';
- import { NaturalTypeEnum, PageEnum } from '/src/enums/pageEnum';
- // import { policy } from '/src/components/upload-file/api';
- import { formatUrlType } from '../upload-modal';
- // import axios from 'axios';
- import {
- getUploadSign,
- onFileUpload,
- onOnlyFileUpload
- // ossSwitch
- } from '/src/helpers/oss-file-upload';
- export default defineComponent({
- name: 'save-modal',
- props: {
- fileList: {
- type: String,
- default: ''
- },
- imageList: {
- type: Array,
- default: () => []
- },
- accept: {
- // 支持类型
- type: String,
- default: '.jpg,.png,.jpeg,.gif'
- },
- showType: {
- type: String as PropType<'default' | 'custom'>,
- default: 'default'
- },
- showFileList: {
- type: Boolean,
- default: true
- },
- 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: ''
- },
- fileName: {
- type: String,
- default: ''
- }
- },
- emits: ['close', 'confrim'],
- setup(props, { emit }) {
- 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([]) as any;
- const fileListRef = ref<UploadFileInfo[]>([]);
- const uploadList = ref([] as any);
- // 获取文件后缀名
- function getFileExtension(filename: string) {
- return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2);
- }
- // 判断是否是允许的文件类型
- function isAllowedFileType(filename: string, allowedExtensions: any) {
- const extension = getFileExtension(filename).toLowerCase();
- return allowedExtensions.includes(extension);
- }
- const onBeforeUpload = async (options: any) => {
- const file = options.file;
- // 文件大小
- let isLt2M = true;
- const allowedExtensions = [
- 'jpg',
- 'jpeg',
- 'png',
- 'mp4',
- 'ppt',
- 'pptx',
- 'mp3'
- ];
- if (!isAllowedFileType(file.file.name, allowedExtensions)) {
- message.error('文件格式不支持');
- return false;
- }
- const type = file.type.includes('image')
- ? NaturalTypeEnum.IMG
- : file.type.includes('audio')
- ? NaturalTypeEnum.SONG
- : file.type.includes('video')
- ? NaturalTypeEnum.VIDEO
- : file.type.includes(
- 'vnd.openxmlformats-officedocument.presentationml.presentation'
- ) || file.type.includes('vnd.ms-powerpoint')
- ? NaturalTypeEnum.PPT
- : 'other';
- if (type === 'other') {
- message.error(`文件格式不支持`);
- return false;
- }
- const size = type === 'IMG' ? 2 : type === 'SONG' ? 20 : 500;
- if (size) {
- isLt2M = file.file.size / 1024 / 1024 < size;
- if (!isLt2M) {
- const typeStr =
- type === 'IMG' ? '图片' : type === 'SONG' ? '音频' : '视频';
- message.error(`${typeStr}大小不能超过${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}${Date.now() + file.id + suffix}`;
- const obj = {
- filename: fileName,
- bucketName: props.bucketName,
- postData: {
- filename: fileName,
- acl: 'public-read',
- key: fileName,
- unknowValueField: []
- }
- };
- // const { data } = await policy(obj);
- const { data } = await getUploadSign(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
- });
- } catch {
- //
- // message.error('上传失败')
- btnLoading.value = false;
- return false;
- }
- return true;
- };
- // const getBase64 = async (img: any, callback: any) => {
- // const reader = new FileReader();
- // reader.addEventListener('load', () => callback(reader.result));
- // reader.readAsDataURL(img);
- // };
- const onFinish = (options: any) => {
- onFinishAfter(options);
- };
- const onFinishAfter = async (options: any) => {
- console.log(options, 'onFinishAfter');
- const item = state.find((c: any) => c.id == options.file.id);
- const type = formatUrlType(options.file.url);
- let coverImg = '';
- if (type === 'IMG') {
- coverImg = options.file.url;
- } else if (type === 'SONG') {
- coverImg = PageEnum.SONG_DEFAULT_COVER;
- } else if (type === 'PPT') {
- coverImg = PageEnum.PPT_DEFAULT_COVER;
- } else if (type === 'VIDEO') {
- // 获取视频封面图
- coverImg = await getVideoCoverImg(item.tempFiileBuffer);
- }
- uploadList.value.push({
- coverImg,
- content: options.file.url,
- id: options.file.id,
- name: options.file.name
- ? options.file.name.slice(0, options.file.name.lastIndexOf('.'))
- : ''
- });
- visiable.value = false;
- btnLoading.value = false;
- };
- const getVideoMsg = (file: any) => {
- return new Promise((resolve, reject) => {
- // let dataURL = '';
- const videoElement = document.createElement('video');
- videoElement.setAttribute('crossOrigin', 'Anonymous'); // 处理跨域
- videoElement.setAttribute('preload', 'auto'); // auto|metadata|none
- videoElement.muted = true;
- videoElement.autoplay = true;
- videoElement.src = URL.createObjectURL(file);
- // Listen for 'canplay' to ensure the video is ready for frame capture
- videoElement.addEventListener('loadedmetadata', () => {
- // 这里开始播放
- videoElement.play();
- setTimeout(() => {
- // 过500ms 暂停, 解决空白问题
- videoElement.currentTime = 0;
- videoElement.pause();
- // 创建canvas元素
- const canvas: any = document.createElement('canvas');
- canvas.width = videoElement.videoWidth;
- canvas.height = videoElement.videoHeight;
- // 将视频帧绘制到canvas上
- // const ctx = canvas.getContext('2d');
- // console.log(videoElement);
- // ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
- canvas
- .getContext('2d')
- .drawImage(videoElement, 0, 0, canvas.width, canvas.height);
- // 将canvas图像转换为base64格式的数据URI
- // const dataUrl = canvas.toDataURL('image/png');
- // 返回base64格式的数据URI
- // resolve(dataUrl);
- canvas.toBlob((blob: any) => {
- resolve(blob);
- });
- }, 500);
- });
- // 如果视频加载出错,则返回错误信息
- videoElement.addEventListener('error', (e: any) => {
- reject(e);
- });
- // return new Promise((resolve, reject) => {
- // videoElement.addEventListener('loadedmetadata', () => {
- // // 这里开始播放
- // videoElement.play()
- // setTimeout(() => {
- // // 过500ms 暂停, 解决空白问题
- // videoElement.pause()
- // // 创建canvas元素
- // const canvas = document.createElement('canvas');
- // canvas.width = videoElement.videoWidth;
- // canvas.height = videoElement.videoHeight;
- // // 将视频帧绘制到canvas上
- // const ctx = canvas.getContext('2d');
- // console.log(videoElement);
- // ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
- // // 将canvas图像转换为base64格式的数据URI
- // const dataUrl = canvas.toDataURL('image/png');
- // console.log(dataUrl);
- // thumbnail.src = dataUrl;
- // thumbnail.style.display = 'inline';
- // // 返回base64格式的数据URI
- // resolve(dataUrl);
- // }, 500);
- // });
- // // 如果视频加载出错,则返回错误信息
- // videoElement.addEventListener('error', () => {
- // reject(`Failed to load video: ${videoUrl}`);
- // });
- // });
- // videoElement.addEventListener('canplay', function () {
- // console.log('Video can play');
- // const canvas: any = document.createElement('canvas'),
- // width = videoElement.videoWidth,
- // height = videoElement.videoHeight;
- // canvas.width = width;
- // canvas.height = height;
- // canvas.getContext('2d').drawImage(videoElement, 0, 0, width, height);
- // canvas.toBlob((blob: any) => {
- // resolve(blob);
- // });
- // });
- // videoElement.addEventListener('error', function (e) {
- // console.error('Error loading video:', e);
- // reject(e);
- // });
- });
- };
- const getVideoCoverImg = async (file: any) => {
- 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: []
- }
- };
- const { data } = await getUploadSign(obj);
- const fileParams = {
- policy: data.policy,
- signature: data.signature,
- key: fileName,
- acl: 'public-read',
- KSSAccessKeyId: data.kssAccessKeyId,
- name: fileName,
- file: imgBlob
- } as any;
- const res = await onOnlyFileUpload(ossUploadUrl, fileParams);
- return res;
- } finally {
- btnLoading.value = false;
- }
- };
- const onRemove = async (file: any) => {
- const index = uploadList.value.findIndex(
- (update: any) => update.id === file.file.id
- );
- uploadList.value.splice(index, 1);
- btnLoading.value = false;
- return true;
- };
- const uploadStatus = computed(() => {
- let status = false;
- fileListRef.value.forEach((file: any) => {
- if (file.status !== 'finished') {
- status = true;
- }
- });
- return status || fileListRef.value.length <= 0;
- });
- 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 });
- };
- const onSubmit = async () => {
- const list: any = [];
- fileListRef.value.forEach((file: any) => {
- const item = uploadList.value.find(
- (child: any) => child.id === file.id
- );
- if (item) {
- list.push(item);
- }
- });
- emit('confrim', list);
- };
- return () => (
- <div class={styles.saveModal}>
- <NUpload
- ref={uploadRef}
- action={ossUploadUrl}
- // data={(file: any) => {
- // return { ...more };
- // }}
- customRequest={onCustomRequest}
- v-model:fileList={fileListRef.value}
- accept=".jpg,jpeg,.png,audio/mp3,video/mp4,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation"
- multiple={true}
- max={10}
- // disabled={props.disabled}
- showFileList={true}
- showPreviewButton
- onBeforeUpload={(options: any) => onBeforeUpload(options)}
- onFinish={(options: any) => {
- onFinish(options);
- }}
- onRemove={(options: any) => onRemove(options)}>
- <NUploadDragger>
- <div class={styles.uploadBtn}>
- <div class={styles.iconUploadAdd} />
- <h3>点击或者拖动文件到该区域来上传</h3>
- <p>
- 仅支持JPG、PNG、MP3、MP4、PPT格式文件,单次最多支持
- <br />
- 上传10个文件
- </p>
- </div>
- </NUploadDragger>
- </NUpload>
- <NSpace class={styles.btnGroup} justify="center">
- <NButton round onClick={() => emit('close')}>
- 取消
- </NButton>
- <NButton
- round
- type="primary"
- disabled={uploadStatus.value || btnLoading.value}
- onClick={onSubmit}>
- 确定
- </NButton>
- </NSpace>
- </div>
- );
- }
- });
|