From e1b028d486713eaf55aaf35fbf334aa568059c0d Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期二, 14 四月 2026 15:46:54 +0800
Subject: [PATCH] 项目复制

---
 src/views/components/UploadBtn.vue |  287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 287 insertions(+), 0 deletions(-)

diff --git a/src/views/components/UploadBtn.vue b/src/views/components/UploadBtn.vue
new file mode 100644
index 0000000..5e4647b
--- /dev/null
+++ b/src/views/components/UploadBtn.vue
@@ -0,0 +1,287 @@
+<template>
+  <el-upload
+    ref="upload"
+    class="my-3 uploader" action="#"
+    v-model:file-list="list"
+    :accept="acceptType"
+    :list-type="listType"
+    :http-request="uploadRequest"
+    :multiple="true"
+    :limit="limitFileCount"
+    :on-preview="handlePreview"
+    :on-remove="handleRemove"
+    :before-remove="beforeRemove"
+    :on-exceed="handleExceed"
+    :disabled="disabled"
+    :class="{ hideUpload: hideUpload }"
+  >
+    <template #default>
+      <template v-if="listType=='picture-card'">
+        <el-icon v-if="!disabled"><Plus /></el-icon>
+        <el-text v-if="disabled&&list.length==0">鏆傛湭涓婁紶</el-text>
+      </template>
+      <template v-else>
+        <el-row v-if="!disabled">
+          <el-button type="primary">
+            <el-row align="middle">
+              <Icon icon="material-symbols:upload-rounded" width="20" height="20"  style="color: #fff" />
+              <el-text class="text-white ml-1">{{ againUploadFlag ? '閲嶆柊涓婁紶' : '绔嬪嵆涓婁紶' }}</el-text>
+            </el-row>
+          </el-button>
+          <el-text style="color: #666666" class="ml-4">
+            {{ tip }}
+          </el-text>
+        </el-row>
+        <el-row v-else>
+          <el-text class="ml-4" style="color: #a8abb2" v-if="disabled&&list.length==0">鏈笂浼犳枃浠�</el-text>
+        </el-row>
+      </template>
+    </template>
+    <template #file="{ file, index }">
+      <template v-if="listType=='picture-card'">
+        <el-image
+          ref="previewImg"
+          :src="file.url?.includes('http') ? file.url : $qxueyou.qxyRes + file.url"
+          :initial-index="initialPreviewImgIndex"
+          :preview-src-list="filterPreviewImgList"
+        >
+        </el-image>
+        <span class="el-upload-list__item-actions">
+          <span @click="previewImage(index)">
+            <el-icon><zoom-in /></el-icon>
+          </span>
+          <span @click="deleteFileItem(index)">
+            <el-icon><delete /></el-icon>
+          </span>
+        </span>
+      </template>
+      <template v-else>
+        <div class="file-box cursor-p" :style="{ 'margin-top': disabled && index==0 ? '-30px' : '' }">
+          <Icon
+            v-if="!disabled"
+            @click.stop="deleteFileItem(index)"
+            class="cursor-p mr-3" 
+            icon="eva:close-fill" 
+            width="18" 
+            height="18" 
+            style="color: #666666" 
+          />
+          <FilePreview 
+            :name="file.name" 
+            :url="file.url"
+            :list="list"
+            :index="index"
+          ></FilePreview>
+        </div>
+      </template>
+    </template>
+  </el-upload>
+  
+  <ElImageViewer
+    v-if="showImageViewer"
+    :url-list="filterPreviewImgList"
+    :initial-index="initialPreviewImgIndex"
+    @close="showImageViewer=false"
+  >
+  </ElImageViewer>
+
+  <el-dialog v-model="pdfPreviewFlag" top="5vh">
+    <div style="height: 84vh;">
+      <PdfPreview v-if="previewUrl&&pdfPreviewFlag" :url="previewUrl"></PdfPreview>
+    </div>
+  </el-dialog>
+  
+</template>
+
+<script>
+const pdf = 'application/pdf'
+const xls = 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+const doc = 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+const image = 'image/*'
+const jpg = 'image/jpeg'
+const png = 'image/png'
+const zip = 'application/zip,application/x-zip-compressed'
+import { genFileId, ElImageViewer } from 'element-plus'
+import { getFileUrlName, getFileUrlType } from '@/utils/tool.js'
+import FilePreview from '@/views/components/FilePreview.vue'
+import PdfPreview from '@/views/components/PdfPreview.vue'
+export default {
+  components: {
+    ElImageViewer,
+    PdfPreview,
+    FilePreview
+  },
+  data() {
+    return {
+      list: [],
+      previewUrl: '',
+      pdfPreviewFlag: false,
+      initialPreviewImgIndex: 0,
+      showImageViewer: false,
+    }
+  },
+  props: {
+    listType: {
+      type: String,
+      default: 'text'
+    },
+    accept: {
+      type: Array,
+      default: () => {
+        return ['pdf', 'xls', 'doc', 'image', 'jpg', 'png', 'zip']
+      }
+    },
+    limitFileCount: {
+      type: Number,
+      default: 1
+    },
+    modelValue: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  watch: {
+    modelValue: {
+      handler: function() {
+        this.list = this.modelValue || []
+        this.list.forEach(ele => {
+          if (!ele.name) {
+            ele.name = getFileUrlName(ele.url)
+          }
+        })
+      },
+      immediate: true,
+      deep: true
+    },
+    list: {
+      handler: function(val) {
+        this.$emit('update:modelValue', val)
+      },
+      immediate: true,
+      deep: true
+    }
+  },
+  computed: {
+    acceptType() {
+      let obj = { pdf, xls, doc, image, jpg, png, zip }
+      return this.accept.map(ele => obj[ele]).join(',')
+    },
+    tip() {
+      let obj = {
+        pdf: 'PDF',
+        xls: 'EXCEL',
+        doc: 'WORD',
+        image: '鍥剧墖',
+        jpg: 'JPEG/JPG',
+        png: 'PNG',
+        zip: 'ZIP'
+      }
+      let tip = this.accept.map(ele => obj[ele]).join('銆�')
+      return `鏀寔${tip}绫诲瀷鏂囦欢` 
+    },
+    againUploadFlag() {
+      return this.limitFileCount == 1  && this.list.length == 1
+    },
+    filterPreviewImgList() {
+      let list = this.list.map(ele => ele.url?.includes('http') ? ele.url : this.$qxueyou.qxyRes + ele.url )
+      return list
+    },
+    hideUpload() {
+      return this.list.length >= this.limitFileCount
+    }
+  },
+  methods: {
+    uploadRequest(UploadRequestOptions) {
+      const data = {
+        file: UploadRequestOptions.file,
+        directory: ''
+      }
+      this.$axios.post('/infra/file/exam/upload', data, { 
+        headers: { 'Content-Type': "multipart/form-data" }
+      }).then(res => {
+        let index = this.list.findIndex(ele => ele.uid == data.file.uid)
+        if (res.data.code == 0) {
+          let index = this.list.findIndex(ele => ele.uid == data.file.uid)
+          if (index != -1) {
+            this.list[index].uploadStatus = 'success'
+            let url = res.data.data
+            this.list[index].url = url
+          }
+          this.$message.success('涓婁紶鎴愬姛')
+        } else {
+          if (index != -1) {
+            this.list[index].uploadStatus = 'fail'
+          }
+          this.$message.error(res.data.msg || '涓婁紶澶辫触')
+        }
+      })
+    },
+    deleteFileItem(index) {
+      this.list.splice(index, 1)
+    },
+    previewImage(index) {
+      this.initialPreviewImgIndex = index
+      this.$refs.previewImg?.showPreview()
+    },
+    replaceUpload() {},
+    handleRemove() {},
+    beforeRemove() {},
+    handlePreview() {},
+    handleExceed(file) {
+      if (this.againUploadFlag) {
+        this.$refs.upload?.clearFiles()
+        let newFile = file[0]
+        newFile.uid = genFileId()
+        this.$refs.upload?.handleStart(newFile)
+        this.$refs.upload?.submit()
+      } else {
+        this.$message.error(`鏈�澶氭敮鎸佷笂浼� ${this.limitFileCount} 涓枃浠禶)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.uploader .avatar {
+  width: 178px;
+  height: 178px;
+  display: block;
+}
+.hideUpload :deep(.el-upload--picture-card) {
+  display: none !important;
+}
+.file-box {
+  display: flex;
+  color: #007AFF;
+  align-content: center;
+  background-color: #ECF5FF;
+  padding: 8px;
+  font-size: 15px;
+  line-height: 16px;
+}
+.el-upload-list__item-actions {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5); /* 鍗婇�忔槑榛戣壊钂欑増 */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  opacity: 0; /* 榛樿閫忔槑 */
+  transition: opacity .3s; /* 娣诲姞杩囨浮鍔ㄧ敾鏁堟灉 */
+}
+
+/* 榧犳爣鎮仠鏃舵樉绀鸿挋鐗� */
+.el-upload-list__item:hover .el-upload-list__item-actions {
+  opacity: 1;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.8.0