fuliqi
2025-02-11 da7b9833e734332d47a42fb8ba30daf263864b27
文件上传组件图片预览、工单详情页图片预览
2个文件已修改
131 ■■■■ 已修改文件
src/components/FileUpload/index.vue 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/work-order/detail/index.vue 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue
@@ -28,17 +28,32 @@
    <!-- 文件列表 -->
    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
      <li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
        <!-- 图片文件 -->
        <template v-if="isImage(file)">
          <div class="image-preview" @click="handlePreview(file)">
            <img :src="getImageUrl(file.url)" class="thumbnail" />
            <span class="filename">{{ getFileName(file.name) }}</span>
          </div>
        </template>
        <!-- 非图片文件 -->
        <template v-else>
        <el-link @click="handleDownload(file.url)" :underline="false" target="_blank">
          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link>
        <!-- <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link> -->
        </template>
        <div class="ele-upload-list__item-content-action">
          <template v-if="isImage(file)">
            <el-link :underline="false" @click="handleDownload(file.url)" type="primary" class="action-link">下载</el-link>
          </template>
          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
        </div>
      </li>
    </transition-group>
    <!-- 图片预览弹窗 -->
    <el-dialog :visible.sync="previewVisible" append-to-body title="图片预览" width="800px">
      <img :src="previewUrl" style="width: 100%;" />
    </el-dialog>
  </div>
</template>
@@ -48,24 +63,19 @@
export default {
  name: "FileUpload",
  props: {
    // 值
    value: [String, Object, Array],
    // 数量限制
    limit: {
      type: Number,
      default: 5,
    },
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 20,
    },
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
      type: Array,
      default: () => ["docx", "xlsx", "ppt", "txt", "pdf","png","jpg"],
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
@@ -76,11 +86,14 @@
      number: 0,
      uploadList: [],
      baseUrl: process.env.VUE_APP_BASE_API,
      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传文件服务器地址
      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload",
      headers: {
        Authorization: "Bearer " + getToken(),
      },
      fileList: [],
      previewVisible: false,
      previewUrl: "",
      imageTypes: ['png', 'jpg', 'jpeg', 'gif']
    };
  },
  watch: {
@@ -88,9 +101,7 @@
      handler(val) {
        if (val) {
          let temp = 1;
          // 首先将值转为数组
          const list = Array.isArray(val) ? val : this.value.split(',');
          // 然后将数组转为对象数组
          this.fileList = list.map(item => {
            if (typeof item === "string") {
              item = { name: item, url: item };
@@ -108,15 +119,24 @@
    }
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
  },
  methods: {
    // 上传前校检格式和大小
    isImage(file) {
      const fileName = file.name.split('.');
      const fileExt = fileName[fileName.length - 1].toLowerCase();
      return this.imageTypes.includes(fileExt);
    },
    getImageUrl(url) {
      return url.startsWith('http') ? url : `${this.baseUrl}${url}`;
    },
    handlePreview(file) {
      this.previewUrl = this.getImageUrl(file.url);
      this.previewVisible = true;
    },
    handleBeforeUpload(file) {
      // 校检文件类型
      if (this.fileType) {
        const fileName = file.name.split('.');
        const fileExt = fileName[fileName.length - 1];
@@ -126,7 +146,6 @@
          return false;
        }
      }
      // 校检文件大小
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize;
        if (!isLt) {
@@ -138,16 +157,13 @@
      this.number++;
      return true;
    },
    // 文件个数超出
    handleExceed() {
      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
    },
    // 上传失败
    handleUploadError(err) {
      this.$modal.msgError("上传文件失败,请重试");
      this.$modal.closeLoading();
    },
    // 上传成功回调
    handleUploadSuccess(res, file) {
      if (res.code === 200) {
        this.uploadList.push({ name: res.fileName, url: res.fileName });
@@ -160,12 +176,10 @@
        this.uploadedSuccessfully();
      }
    },
    // 删除文件
    handleDelete(index) {
      this.fileList.splice(index, 1);
      this.$emit("input", this.listToString(this.fileList));
    },
    // 上传结束处理
    uploadedSuccessfully() {
      if (this.number > 0 && this.uploadList.length === this.number) {
        this.fileList = this.fileList.concat(this.uploadList);
@@ -175,16 +189,13 @@
        this.$modal.closeLoading();
      }
    },
    // 获取文件名称
    getFileName(name) {
      // 如果是url那么取最后的名字 如果不是直接返回
      if (name.lastIndexOf("/") > -1) {
        return name.slice(name.lastIndexOf("/") + 1);
      } else {
        return name;
      }
    },
    // 对象转成指定字符串分隔
    listToString(list, separator) {
      let strs = "";
      separator = separator || ",";
@@ -193,7 +204,6 @@
      }
      return strs != '' ? strs.substr(0, strs.length - 1) : '';
    },
    /** 下载按钮操作 */
    handleDownload (data) {
      this.$download.resource(data);
    }
@@ -220,4 +230,26 @@
.ele-upload-list__item-content-action .el-link {
  margin-right: 10px;
}
.image-preview {
  display: flex;
  align-items: center;
  cursor: pointer;
  .thumbnail {
    width: 60px;
    height: 60px;
    object-fit: cover;
    margin-right: 10px;
    border-radius: 4px;
  }
  .filename {
    color: #606266;
  }
}
.action-link {
  margin-right: 10px;
}
</style>
src/views/system/work-order/detail/index.vue
@@ -109,10 +109,24 @@
                  <el-tag :type="report.reportType === '事前报备' ? 'warning' : 'danger'">{{report.reportType}}</el-tag>
                </div>
                <div style="margin: 8px 0">
                  <el-link
                  <div
                    v-for="item in report.reportMaterials != null ? report.reportMaterials.split(',') : report.reportMaterials"
                    :underline="false" type="primary" :key="item" @click="handleDownload(item)">{{ item.substring(item.lastIndexOf("/") + 1)
                    }}</el-link>
                    :key="item">
                    <el-image
                      v-if="isImageFile(item)"
                      :src="getPreview(item)"
                      :preview-src-list="[getPreview(item)]"
                      fit="cover"
                      style="width: 100px; height: 100px; margin: 5px;"
                    >
                    </el-image>
                    <el-link
                      v-else
                      :underline="false" type="primary" @click="handleDownload(item)">{{
                        item.substring(item.lastIndexOf("/") + 1)
                      }}
                    </el-link>
                  </div>
                </div>
                <div v-html="report.reportContent"></div>
              </div>
@@ -131,10 +145,24 @@
              :timestamp="yw.createTime">
              <div>
                <div style="margin: 8px 0">
                  <el-link
                  <div
                    v-for="item in yw.ywProofMaterials != null ? yw.ywProofMaterials.split(',') : yw.ywProofMaterials"
                    :underline="false" type="primary" :key="item" @click="handleDownload(item)">{{ item.substring(item.lastIndexOf("/") + 1)
                    }}</el-link>
                    :key="item">
                    <el-image
                      v-if="isImageFile(item)"
                      :src="getPreview(item)"
                      :preview-src-list="[getPreview(item)]"
                      fit="cover"
                      style="width: 100px; height: 100px; margin: 5px;"
                    >
                    </el-image>
                    <el-link
                      v-else
                      :underline="false" type="primary" @click="handleDownload(item)">{{
                        item.substring(item.lastIndexOf("/") + 1)
                      }}
                    </el-link>
                  </div>
                </div>
                <div v-html="yw.ywCondition"></div>
              </div>
@@ -223,7 +251,16 @@
    this.getWorkOrder()
  },
  methods: {
    getPreview(url) {
      // 使用全局配置的图片前缀
      return this.$img + url;
    },
    isImageFile(url) {
      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
      return imageExtensions.some(ext =>
        url.toLowerCase().endsWith(ext)
      );
    },
    closeAuditing() {
      this.auditingOpen = false
    },