CzRger 1 anno fa
parent
commit
ded7904b08

+ 1 - 1
src/components/cus/CusForm.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="cus-form">
-    <el-form ref="ref_cusForm" :label-width="labelWidth">
+    <el-form ref="ref_cusForm" :label-width="labelWidth" v-bind="$attrs">
       <el-row style="display:flex; flex-wrap: wrap">
         <slot/>
       </el-row>

+ 16 - 1
src/components/cus/CusFormColumn.vue

@@ -176,6 +176,7 @@
           />
         </template>
       </slot>
+      <div v-if="unit" class="unit">{{unit}}</div>
     </el-form-item>
   </el-col>
 </template>
@@ -244,7 +245,8 @@ export default defineComponent({
     rules: {type: Array, default: () => []},
     maxLength: {type: Number, default: null},
     minLength: {type: Number, default: null},
-    defaultErrorMsg: {default: null}
+    defaultErrorMsg: {default: null},
+    unit: {default: '', type: String}
   },
   setup(props) {
     const store = useStore();
@@ -364,6 +366,19 @@ export default defineComponent({
       align-items: center;
       padding-left: 10px;
     }
+    .el-form-item__content {
+      flex-wrap: unset;
+      >div:first-child {
+        flex: 1;
+      }
+      .unit {
+        margin-left: 6px;
+        font-size: 14px;
+        font-family: PingFang SC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #606266;
+      }
+    }
   }
 }
 </style>

+ 119 - 38
src/components/cus/cus-form-link/upload.vue

@@ -1,5 +1,8 @@
 <template>
-  <div class="cus-form-column-upload-com" :class="{'cus-form-column-upload-com_view': view}" v-loading="loading" :element-loading-background="elementLoadingBackground" style="width: 100%;">
+  <div class="cus-form-column-upload-com"
+       :class="{'cus-form-column-upload-com_view': view, 'cus-form-column-upload-com_list': layout === 'list', 'cus-form-column-upload-com_card': layout === 'card'}"
+       v-loading="loading"
+       :element-loading-background="elementLoadingBackground">
     <el-upload
         class="el-upload-com"
         ref="ref_upload"
@@ -16,8 +19,8 @@
     >
       <el-tooltip :content="acceptTooltipCpt" placement="top" popper-class="upload-tooltip-popper">
         <template v-if="layout === 'card'">
-          <div class="upload-layout-card __hover" >
-            <SvgIcon name="add" color="#0062E9"/>
+          <div class="upload-layout-card __hover" :class="{'limit-disabled': isLimitCpt}">
+            <SvgIcon name="add" color="#0062E9" size="24"/>
             <div>选择{{acceptTypeFormatCpt}}</div>
             <div v-if="limit > 0">(最多{{ limit }}个)</div>
           </div>
@@ -25,31 +28,47 @@
         <template v-else>
           <div class="upload-layout-list_button" :class="{'limit-disabled': isLimitCpt}">
             <SvgIcon name="add" color="#ffffff" size="14"/>
-            选择{{acceptTypeFormatCpt}}<template v-if="limit > 0">(最多{{ limit }}个)</template>
+            选择{{acceptTypeFormatCpt}}
+            <template v-if="limit > 0">(最多{{ limit }}个)</template>
           </div>
         </template>
       </el-tooltip>
       <template #file="{file}">
         <template v-if="layout === 'card'">
-          <div class="upload-layout-card_item" :class="{'item-view': view || !delRule(file)}" @mouseenter="file.hover = true" @mouseleave="file.hover = false">
-            <template v-if="validImgByUrl(file.fUrl)">
-              <img class="img __hover" :src="$util.proxyNginxUrl(file.fUrl)"/>
-            </template>
-            <template v-else>
-              <img class="file" :src="getFileImgByUrl(file.fUrl)"/>
-            </template>
-            <img class="del __hover" src="@/assets/images/cus/file-del.png" v-if="file.hover && !view && delRule(file)" @click.stop="ref_upload.handleRemove(file)"/>
-          </div>
+          <el-tooltip placement="top" :content="file[nameKey] ?? file[urlKey]">
+            <div class="upload-layout-card_item" :class="{'item-view': view || !delRule(file)}" @mouseenter="file.hover = true" @mouseleave="file.hover = false">
+              <template v-if="validImgByUrl(file[urlKey])">
+                <img class="img __hover" :src="$util.proxyNginxUrl(file[urlKey])" @click="viewImg(file[urlKey])"/>
+              </template>
+              <template v-else-if="validVideoByUrl(file[urlKey])">
+                <video class="video __hover" controls :src="$util.proxyNginxUrl(file[urlKey])"/>
+              </template>
+              <template v-else>
+                <img class="file __hover" :src="getFileImgByUrl(file[urlKey])" @click="downloadFileByUrl(file[urlKey], file[nameKey])"/>
+              </template>
+              <img class="del __hover" src="@/assets/images/cus/file-del.png" v-if="file.hover && !view && delRule(file)" @click.stop="ref_upload.handleRemove(file)"/>
+            </div>
+          </el-tooltip>
         </template>
         <template v-else>
-          <div class="upload-layout-list_item __hover" :class="{'item-view': view || !delRule(file)}" @click="downloadFileByUrl(file.fUrl, file.fName)">
-            <img class="file-type-img" :src="getFileImgByUrl(file.fUrl)"/>
-            <CusEllipsis class="label" :value="file.fUrl"/>
+          <div class="upload-layout-list_item __hover" :class="{'item-view': view || !delRule(file)}" @click="validImgByUrl(file[urlKey]) ? viewImg(file[urlKey]) : downloadFileByUrl(file[urlKey], file[nameKey])">
+            <img class="file-type-img" :src="getFileImgByUrl(file[urlKey])"/>
+            <CusEllipsis v-if="file[nameKey] ?? file[urlKey]" class="label" :value="file[nameKey] ?? file[urlKey]"/>
             <SvgIcon v-if="!view && delRule(file)" class="close" name="close_2" size="12" @click.stop="ref_upload.handleRemove(file)"/>
           </div>
         </template>
       </template>
     </el-upload>
+    <el-image-viewer
+        v-if="currentImg.show"
+        :zoom-rate="2"
+        :max-scale="10"
+        :min-scale="0.2"
+        :hide-on-click-modal="true"
+        :url-list="[currentImg.url]"
+        :initial-index="0"
+        @close="imageClose"
+    />
   </div>
 </template>
 
@@ -92,10 +111,15 @@ export default defineComponent({
     layout: {default: 'list', validator(val: string) {
       return ['list', 'card'].includes(val)
     }},
-    acceptType: {default: ''},
-    acceptMax: {default: 0},
+    acceptType: {default: '', type: String},
+    acceptMax: {default: 0, type: Number},
+    acceptFunc: {default: () => (options) => {}},
     view: {default: false},
-    delRule: {default: () => () => false}
+    delRule: {default: () => () => false},
+    cardWidth: {default: '147px'},
+    cardHeight: {default: '128px'},
+    urlKey: {default: 'url'},
+    nameKey: {default: 'name'}
   },
   setup(props, { emit }) {
     const store = useStore();
@@ -106,6 +130,10 @@ export default defineComponent({
       paramVal: <any>props.param,
       loading: true,
       elementLoadingBackground: inject('element-loading-background', null),
+      currentImg: {
+        show: false,
+        url: ''
+      }
     })
     watch(() => state.paramVal, (n) => {
       emit('emitParam', n)
@@ -123,6 +151,15 @@ export default defineComponent({
       }
       return false
     }
+    const validVideoByUrl = (url) => {
+      if (url) {
+        const videoList = ['avi', 'mp4', 'mov', 'wmv', 'flv', 'mkv', 'mpeg', '3gp'];
+        //进行图片匹配
+        let result = [...videoList.map(v => v.toLowerCase()), ...videoList.map(v => v.toUpperCase())].some((t) => url.includes('.' + t));
+        return result
+      }
+      return false
+    }
     const acceptTypeCpt = computed(() => {
       let str = ''
       if (that.$util.isValue(props.acceptType)) {
@@ -223,9 +260,16 @@ export default defineComponent({
       }
       return file
     }
-    const handleRequest = (options) => {
+    const handleRequest = async (options) => {
+      state.loading = true
       if (that.$util.isValue(props.acceptType)) {
-
+        const result: any = await props.acceptFunc(options)
+        if (result?.[props.urlKey] && result?.[props.nameKey]) {
+          state.paramVal = [...state.paramVal, result]
+        } else {
+          state.paramVal = [...state.paramVal]
+        }
+        state.loading = false
       } else {
         if (store.state.app.uploadConfig.imgType.split(',').some(v => options.file.name.includes(v))) {
           const formData = new FormData();
@@ -233,10 +277,13 @@ export default defineComponent({
           that.$api.uploadPicOnly(formData).then(res => {
             if (res?.code === 200) {
               state.paramVal = [...state.paramVal, {
-                fUrl: res.imgPath,
-                fName: res.fileName
+                [props.urlKey]: res.imgPath,
+                [props.nameKey]: res.fileName
               }]
             }
+            state.loading = false
+          }).catch(() => {
+            state.loading = false
           })
         } else if (store.state.app.uploadConfig.fileType.split(',').some(v => options.file.name.includes(v))) {
           const formData = new FormData();
@@ -244,10 +291,13 @@ export default defineComponent({
           that.$api.uploadFile(formData).then(res => {
             if (res?.code === 200) {
               state.paramVal = [...state.paramVal, {
-                fUrl: res.url,
-                fName: res.fileName
+                [props.urlKey]: res.url,
+                [props.nameKey]: res.fileName
               }]
             }
+            state.loading = false
+          }).catch(() => {
+            state.loading = false
           })
         }
       }
@@ -297,6 +347,14 @@ export default defineComponent({
       };
       xhr.send();
     }
+    const viewImg = (url) => {
+      state.currentImg.url = url
+      state.currentImg.show = true
+    }
+    const imageClose = () => {
+      state.currentImg.show = false
+      state.currentImg.url = ''
+    }
     onMounted(() => {
       state.loading = true
       store.dispatch('app/LOAD_UPLOAD_CONFIG').then(() => {
@@ -310,12 +368,15 @@ export default defineComponent({
       handleRequest,
       handleRemove,
       validImgByUrl,
+      validVideoByUrl,
       acceptTooltipCpt,
       acceptTypeFormatCpt,
       getFileImgByUrl,
       ref_upload,
       downloadFileByUrl,
-      isLimitCpt
+      isLimitCpt,
+      viewImg,
+      imageClose
     }
   },
 })
@@ -323,8 +384,9 @@ export default defineComponent({
 
 <style scoped lang="scss">
 .cus-form-column-upload-com {
-  $uploadWidth: 95px;
-  $uploadHeight: 71px;
+  $uploadWidth: v-bind(cardWidth);
+  $uploadHeight: v-bind(cardHeight);
+  width: 100%;
   position: relative;
   .el-upload-com {
     :deep(.el-upload) {
@@ -357,20 +419,20 @@ export default defineComponent({
         line-height: 1;
         align-items: center;
         justify-content: center;
-        > img {
-          margin-bottom: 4px;
+        background-color: rgba(46, 129, 255, 0.04);
+        .svg-icon {
+          margin-bottom: 10px;
+          opacity: 0.5;
         }
         > div {
-          font-size: 20px;
+          font-size: 14px;
           font-family: PingFang SC-Regular, PingFang SC;
           font-weight: 400;
-          color: #FFFFFF;
-          transform: scale(0.5);
-          line-height: 12px;
-
-          &:last-child {
-            color: rgba(255, 255, 255, 0.6);
-          }
+          color: rgba(0,98,233,0.5);
+        }
+        &.limit-disabled {
+          cursor: no-drop;
+          opacity: 0.5;
         }
       }
     }
@@ -406,6 +468,11 @@ export default defineComponent({
             width: 100%;
             height: 100%;
           }
+          .video {
+            width: 100%;
+            height: 100%;
+            object-fit: fill;
+          }
           .file {
             width: 100%;
             height: 100%;
@@ -429,5 +496,19 @@ export default defineComponent({
       }
     }
   }
+  &.cus-form-column-upload-com_card {
+    .el-upload-com {
+      :deep(.el-upload) {
+        width: $uploadWidth;
+        height: $uploadHeight;
+      }
+      :deep(.el-upload-list) {
+        .el-upload-list__item {
+          width: $uploadWidth;
+          height: $uploadHeight;
+        }
+      }
+    }
+  }
 }
 </style>