Jelajahi Sumber

添加上传封面

lex 1 tahun lalu
induk
melakukan
d9de57926d

+ 0 - 16
src/views/natural-resources/components/my-resources/index.module.less

@@ -232,22 +232,6 @@
   }
 }
 
-.uploadCover {
-  width: 920px;
-
-  :global {
-
-    .n-card-header {
-      padding-top: 0;
-      padding-bottom: 0;
-
-      .n-card-header__close {
-        margin-top: 65px;
-      }
-    }
-  }
-}
-
 
 .removeVisiable {
   width: 432px;

+ 1 - 12
src/views/natural-resources/components/my-resources/index.tsx

@@ -51,7 +51,6 @@ export default defineComponent({
       tableList: [] as any,
       uploadStatus: false,
       saveStatus: false,
-      uploadCoverStatus: true, // 封面图
       show: false,
       item: {} as any,
       editStatus: false, // 是否编辑
@@ -424,23 +423,13 @@ export default defineComponent({
                   id: null
                 });
               });
-              state.editList = temp;
+              state.editList.push(...temp);
               state.uploadStatus = true;
               state.editStatus = false;
             }}
           />
         </NModal>
 
-        <NModal
-          v-model:show={state.uploadCoverStatus}
-          preset="card"
-          showIcon={false}
-          class={['modalTitle ', styles.uploadCover]}
-          // title={'上传资源'}
-          blockScroll={false}>
-          <UploadCover />
-        </NModal>
-
         {showGuide.value ? <MyResourcesGuide></MyResourcesGuide> : null}
 
         <NModal

+ 15 - 1
src/views/natural-resources/components/my-resources/upload-cover/index.module.less

@@ -83,6 +83,20 @@
     .n-upload {
       width: auto;
     }
+
+    .cropper-view-box {
+      outline-color: #198CFE !important;
+    }
+  }
+}
+
+.imgCropperSection {
+  width: 633px;
+  height: 407px;
+  overflow: hidden;
+
+  img {
+    max-width: 100%;
   }
 }
 
@@ -98,4 +112,4 @@
       min-width: 97px;
     }
   }
-}
+}

+ 176 - 338
src/views/natural-resources/components/my-resources/upload-cover/index.tsx

@@ -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>
     );
   }

+ 28 - 1
src/views/natural-resources/components/my-resources/upload-modal/index.module.less

@@ -66,12 +66,22 @@
       // background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
       width: 100%;
       border-radius: 0 0 10px 10px;
-      justify-content: flex-end;
+      justify-content: space-between;
       padding-right: 12px;
+      padding-left: 12px;
       z-index: 99;
       background: rgba(0, 0, 0, 0.3);
       backdrop-filter: blur(1px);
 
+      .changeCover {
+        background: #FFFFFF;
+        border-radius: 4px;
+        color: #131415 !important;
+        --n-height: 24px !important;
+        --n-padding: 0 8px !important;
+        font-size: max(14px, 12Px);
+      }
+
       :global {
         .n-switch {
           margin-left: 8px;
@@ -167,4 +177,21 @@
       margin-bottom: 20px;
     }
   }
+}
+
+
+.uploadCover {
+  width: 920px;
+
+  :global {
+
+    .n-card-header {
+      padding-top: 0;
+      padding-bottom: 0;
+
+      .n-card-header__close {
+        margin-top: 65px;
+      }
+    }
+  }
 }

+ 51 - 10
src/views/natural-resources/components/my-resources/upload-modal/index.tsx

@@ -13,6 +13,7 @@ import {
   NFormItem,
   NImage,
   NInput,
+  NModal,
   NScrollbar,
   NSelect,
   NSpace,
@@ -30,6 +31,7 @@ import iconUploadDelete from '../../../images/btn-remove.png';
 import { materialSave, materialUpdateAll } from '../../../api';
 import { NaturalTypeEnum } from '@/enums/pageEnum';
 import { scrollToErrorForm } from '/src/utils';
+import UploadCover from '../upload-cover';
 
 // 判断链接后辍
 export const formatUrlType = (url: string) => {
@@ -63,8 +65,8 @@ export default defineComponent({
     const formRef = ref();
     const message = useMessage();
 
-    const uploadRef = ref();
-    const uploadList = ref([] as any);
+    // const uploadRef = ref();
+    // const uploadList = ref([] as any);
     const uploadForms = reactive({
       list: [] as any[],
       uploading: false,
@@ -72,6 +74,12 @@ export default defineComponent({
       name: '',
       subjectIds: [] as any
     });
+    const changeCover = reactive({
+      uploadCoverStatus: false,
+      uploadType: '',
+      uploadImg: null as any,
+      uploadIndex: 0
+    });
 
     // 判断类型
     const formatType = (type: string) => {
@@ -220,14 +228,29 @@ export default defineComponent({
                     />
 
                     <div class={styles.commonType}>
-                      是否公开
-                      <NSwitch
-                        size="small"
-                        v-model:value={item.openFlag}
-                        disabled={
-                          item.sourceFrom === 'TEACHER' && item.type === 'MUSIC'
-                        }
-                      />
+                      <NButton
+                        class={styles.changeCover}
+                        type="default"
+                        bordered={false}
+                        onClick={() => {
+                          changeCover.uploadIndex = index;
+                          changeCover.uploadImg = item.coverImg;
+                          changeCover.uploadType = item.type;
+                          changeCover.uploadCoverStatus = true;
+                        }}>
+                        更换封面
+                      </NButton>
+                      <div>
+                        是否公开
+                        <NSwitch
+                          size="small"
+                          v-model:value={item.openFlag}
+                          disabled={
+                            item.sourceFrom === 'TEACHER' &&
+                            item.type === 'MUSIC'
+                          }
+                        />
+                      </div>
                     </div>
                   </div>
                   <NFormItem
@@ -387,6 +410,24 @@ export default defineComponent({
             确定
           </NButton>
         </NSpace>
+
+        <NModal
+          v-model:show={changeCover.uploadCoverStatus}
+          preset="card"
+          showIcon={false}
+          class={['modalTitle ', styles.uploadCover]}
+          blockScroll={false}>
+          <UploadCover
+            img={changeCover.uploadImg}
+            onClose={() => (changeCover.uploadCoverStatus = false)}
+            onConfirm={(val: any) => {
+              if (changeCover.uploadType === 'IMG') {
+                uploadForms.list[changeCover.uploadIndex].content = val;
+              }
+              uploadForms.list[changeCover.uploadIndex].coverImg = val;
+            }}
+          />
+        </NModal>
       </div>
     );
   }