Vue 学习随笔系列二十五 -- 多文件上传并支持修改

发布于:2025-09-10 ⋅ 阅读:(22) ⋅ 点赞:(0)

多文件上传表格展示


1、实现效果

新增/修改附件信息
在这里插入图片描述

展示附件信息
在这里插入图片描述

2、源码实现

<template>
  <el-dialog
    :title="title"
    :visible.sync="visible"
    :before-close="handleClose"
    width="80%"
    :close-on-click-modal="false"
  >
    <div v-if="type!=='review'" class="content-box">
      <h3>附件信息</h3>
      <el-table 
        border 
        stripe 
        :data="reportFileInfoList"
      >
        <el-table-column type="index" label="序号" width="55" align="center">
        </el-table-column>
        <el-table-column
          v-for="(item, index) in attachmentColumns"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          :min-width="item.width"
          align="center"
        >
          <template v-slot="scope">
            <div v-if="item.prop == 'fileName'">
              <el-tag 
                v-for="(item, index) in scope.row.fileName"
                :key="item"
                type=""
                closable
                @close="handleRemoveTag(scope.row, item)"
              > 
              {{item}}
              </el-tag>
            </div>
            <span v-else> {{ scope.row[item.prop] }} </span>
          </template>
        </el-table-column>
        <el-table-column
          label="上传附件"
          width="120"
          align="center"
        >
        <template v-slot="scope">
          <!-- <span class="opr-btn">上传附件</span> -->
          <el-upload
              class="upload-demo"
              action="#"
              :auto-upload="true"
              :before-upload="beforeUpload"
              :file-list="fileList"
              :show-file-list="false"
            >
              <el-button size="mini" type="text" @click="selectRow(scope.row)">点击上传</el-button>
            </el-upload>
        </template>
        </el-table-column>
      </el-table>
    </div>

    <!-- 查看详情部分 -->
  <div v-if="type == 'review'" class="content-box">
    <h3>附件信息</h3>
    <el-table 
      border 
      stripe 
      v-if="type == 'review'"
      :data="reportFileInfoListTemp"
    >
      <el-table-column type="index" label="序号" width="55" align="center">
      </el-table-column>
      <el-table-column
        v-for="(item, index) in attachmentColumnsReview"
        :key="index"
        :prop="item.prop"
        :label="item.label"
        :min-width="item.width"
        align="center"
      >
      </el-table-column>
    </el-table>
    </div>

    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="handleClose">取 消</el-button>
      <el-button size="small" type="primary" @click="handleSubmit">确 定</el-button>
    </div>
  </el-dialog>
</template>

<script>

import { uploadFile } from "@/api/xxxx/index.js"

export default {

  data() {
    return {
      visible: false,
      type: "add",
      fileType: "",
      reportFileInfoListTemp: [],
      reportFileInfoList: [
        {
          type: "发票",
          fileName: [],
          fileId: [],
        },
        {
          type: "附件信息",
          fileName: [],
          fileId: [],
        },
        {
          type: "电子附件",
          fileName: [],
          fileId: [],
        },
      ],
      attachmentColumns: [
        {
          prop: "type",
          label: "附件类型",
          width: 120,
        },
        {
          prop: "fileName",
          label: "附件信息",
          width: 260,
        },
      ],
      attachmentColumnsReview: [
        {
          prop: "type",
          label: "附件类型",
          width: 120,
        },
        {
          prop: "fileName",
          label: "附件信息",
          width: 260,
        },
        {
          prop: "fileFlowNo",
          label: "文件流水号",
          width: 120,
        },
        {
          prop: "fileStatus",
          label: "文件状态",
          width: 100,
        },
      ],
      fileList: [],
      reportDealHisList: [],
    };
  },
  computed: {
    disabled() {
      return this.type === "review";
    },
    title() {
      if(this.type == "review") {
        return "查看信息"
      } else if(this.type == "add") {
        return "新增信息" 
      } else {
        return "修改信息"
      }
    },
  },
  methods: {
    handleClose() {
      this.visible = false;
      this.reportFileInfoList = [
        {
          type: "发票",
          fileName: [],
          fileId: [],
        },
        {
          type: "附件信息",
          fileName: [],
          fileId: [],
        },
        {
          type: "电子附件",
          fileName: [],
          fileId: [],
        },
      ],
    },
    // 合并 reportFileInfoList
    mergeReportFileInfoList(originalList) {
      const mergedMap = new Map();
      // 合并原始数据
      originalList.forEach(item => {
        if (mergedMap.has(item.type)) {
          const mergedItem = mergedMap.get(item.type);
          mergedItem.fileName.push(item.fileName);
          mergedItem.fileId.push(item.fileId);
        } else {
          mergedMap.set(item.type, {
            type: item.type,
            fileName: [item.fileName],
            fileId: [item.fileId]
          });
        }
      });

      // 确保包含 "发票", "附件信息", "电子附件" 类型
      const defaultTypes = ["发票", "附件信息", "电子附件"];
      defaultTypes.forEach(type => {
        if (!mergedMap.has(type)) {
          mergedMap.set(type, {
            type: type,
            fileName: [],
            fileId: []
          });
        }
      });

      return Array.from(mergedMap.values());
    },
    handleOpen(val) {
      this.visible = true;
      this.type = val.type;
      if(this.type == "add") {
        this.reportExpensesInfo.reportingPeriod = this.$moment().format("YYYY-MM");
        return
      }
      this.reportFileInfoListTemp = val.row.reportFileInfoList || [];
      const originalReportFileInfoList = val.row.reportFileInfoList || [];
      // 调用合并方法
      this.reportFileInfoList = this.mergeReportFileInfoList(originalReportFileInfoList);

    },
    handleSubmit() {
      this.$refs.form.validate((valid) => {
        if (!valid)  return
        const params = { 
          reportFileInfoList: this.reportFileInfoListTemp,
        }
        this.$emit("handleSubmit", params);
        this.handleClose();
      })
    },
    beforeUpload(file) {
      const params = new FormData()
      params.append('file', file)
      uploadFile(params).then(res => {
        if(res.code == 200) {
          this.$message.success(res.msg)
          this.reportFileInfoListTemp.push({
            type: this.fileType,
            fileName: res.data.fileName,
            fileId: res.data.fileId,
          })
          this.reportFileInfoList = this.reportFileInfoList.map(item => {
            if(item.type == this.fileType) {
              item.fileId.push(res.data.fileId);
              item.fileName.push(res.data.fileName)
              
            } 
            return item
          })
        }
      })
      return false;
    },
    selectRow(row) {
      this.fileType = row.type
    },
    // 移除文件
    handleRemoveTag(row, tag){
      // 删除 reportFileInfoListTemp 中 filename 和 tag 匹配的项
      this.reportFileInfoListTemp = this.reportFileInfoListTemp.filter(item => item.fileName !== tag);
      // 删除表格中 filename 与 tag 匹配的项
      this.reportFileInfoList= this.reportFileInfoList.map(item => {
        if(item.type == row.type) {
          const index = item.fileName.indexOf(tag);
          if (index > -1) {
            // 移除对应的文件名
            item.fileName.splice(index, 1);
            // 移除对应的文件ID
            item.fileId.splice(index, 1); 
          }
        }
        return item
      })
    }
  },
};
</script>

<style lang="scss" scoped>
.dialog-footer {
  text-align: center;
}

.opr-btn {
  cursor: pointer;
  color: #409eff;
}
h3 {
  margin: 10px 0;
}
.el-tag {
  margin: 0 5px;
}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到