vue+elementui上传组件自定义封装,包含上传前图片压缩,分页组件封装

一、首先新建NewUpload.vue文件,

<template>
  <div class="images-list1">
    <el-upload
      class="upload-demo"
      :action="uploadUrl"
      :before-upload="handleBeforeUpload"
      :on-success="handleSuccess"
      :on-error="handleUploadError"
      :on-remove="handleRemove"
      :on-exceed="handleExceed"
      :file-list="fileList"
      :multiple="fileLimit > 1"
      :data="paramsData"
      :limit="fileLimit"
      :list-type="listType"
      drag
    >
      <i v-if="listType === 'picture-card'" class="el-icon-plus"></i>
      <i v-else class="el-icon-upload uploIcon"></i>
      <div class="uploName">点击或将文件拖拽到这里上传</div>
      <div v-if="showTip" class="el-upload__tip">
        支持扩展名:{{ fileTypeName || "jpg/png" }}
      </div>
    </el-upload>
  </div>
</template>
<script>
import { imgPreview } from "@/utils/imgPreview.js";
export default {
  name: 'NewUpload',
  props: {
    // 值
    value: [String, Object, Array],
    // 大小限制(MB)
    fileSize: {
      type: Number,
      default: 5,
    },
    // 文件类型, 例如["doc", "xls", "ppt", "txt", "pdf"]
    fileType: {
      type: Array,
      default: () => ['png', 'jpg', 'jpeg'],
    },
    // 文件列表类型 text/picture/picture-card
    listType: {
      type: String,
      default: 'picture'
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
    },
    // 最大允许上传个数
    fileLimit: {
      type: Number,
      default: 99
    }
  },
  data() {
    return {
      uploadUrl: "/api/common/upload", // 上传的图片服务器地址
      paramsData: {
        // 'Authorization': 'Bearer token',
        // 'output': 'json'
        token: ''
      }, // 上传携带的参数,看需求要不要
      fileList: [],
      tempFileList: [] // 因为 fileList为只读属性,所以用了一个中间变量来进行数据改变的交互。
    }
  },
  watch: {
    value: {
      handler: function (newVal) {
        this.tempFileList = newVal
      },
      immediate: true,
      deep: true
    },
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
    fileTypeName() {
      let typeName = ''
      this.fileType.forEach(item => {
        typeName += `${item},`
      })
      return typeName
    },
    fileAccept() {
      let fileAccept = ''
      this.fileType.forEach(element => {
        fileAccept += `.${element},`
      })
      return fileAccept
    }
  },
  created() {
    if (this.value) {
      this.fileList = JSON.parse(JSON.stringify(this.value))
    }
    var token = null
    if (!JSON.parse(sessionStorage.getItem('tokenAll'))) {
      token = null
    } else {
      token = JSON.parse(sessionStorage.getItem('tokenAll')).token
    }
    this.paramsData = {
      token: token
    }
  },
  methods: {
    // 上传前校检格式和大小
    handleBeforeUpload(file) {
      // 校检文件类型
      if (this.fileType && file) {
        const isTypeOk = this.fileType.some((item) => {
          let fileExtension = "";
          if (file.name.lastIndexOf(".") > -1) {
            fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
          }
          // if (file.type.indexOf(item) > -1) return true;
          if (fileExtension && fileExtension.indexOf(item) > -1) return true;
          return false;
        });
        if (!isTypeOk && file) {
          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
          return false;
        }
      }
      // 校检文件大小
      // if (this.fileSize && file) {
      //   const isLt = file.size / 1024 / 1024 < this.fileSize;
      //   if (!isLt) {
      //     this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
      //     return false;
      //   }
      // }
      return new Promise((resolve) => {
        imgPreview(file, (obj) => {
          resolve(obj)
        })
      })
    },
    handleUploadError() {
      this.$message.error("上传失败, 请重试");
    },
    // 文件个数超出
    handleExceed() {
      this.$message.error(`超出上传文件个数,请删除以后再上传!`);
    },
    // 文件上传成功的钩子
    handleSuccess(res, file, fileList) {
      if (res.code === 0) {
        this.$message.success("上传成功")
        this.changeFileList(fileList)
      } else {
        this.$message.error(res.response.errorMessage)
      }
    },
    // 文件列表移除文件时的钩子
    handleRemove(file, fileList) {
      this.changeFileList(fileList)
    },
    // 文件列表改变的时候,更新组件的v-model的文的数据
    changeFileList(fileList) {
      const tempFileList = fileList.map(item => {
        let tempItem = {
          name: item.name,
          url: item.response ? item.response.payload.imgUrl : item.url
        }
        return tempItem
      })
      this.$emit("input", tempFileList)
    }
  },
}
</script>
<style lang="less" scoped>
.images-list1 {
  border-radius: 4px;
  background: #fff;
  ::v-deep .el-upload {
    width: 100%;
    .el-upload-dragger {
      width: 100%;
    }
  }
}
.uploName {
  font-size: 16px;
  color: #333752;
  margin-bottom: 4px;
}
.el-upload__tip {
  font-size: 14px;
  color: #a2a5c4;
}
.uploIcon {
  margin: 16px 0;
}
</style>

 2、Pagenation.vue文件

<template>
  <div class="paginaStly">
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pages.currentPage"
      :page-sizes="[10, 20, 50]"
      :page-size="pages.pageSize"
      :layout="layout"
      :total="pages.total"
      background
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  props: {
    pages: {
      type: Object,
      default() {
        return {
          pageSize: 10,
          currentPage: 1,
          total: 0
        }
      }
    },
    layout: {
      type: String,
      default: "total, sizes, prev, pager, next, jumper",
    },
  },
  data() {
    return {

    };
  },
  methods: {
    //页面尺寸改变
    handleSizeChange(val) {
      this.$emit("sizeChange", val);
    },
    //页码改变
    handleCurrentChange(val) {
      this.$emit("currentChange", val);
    },
  },
};
</script>

<style lang="less" scoped>
.paginaStly {
  display: flex;
  justify-content: flex-end;
  background: #fff;
  padding: 32px 24px;
}
</style>

二、在src/utils下新建图片压缩文件imgPreview.js

// 图片压缩
export const imgPreview = (file, callback) => {
  //将base64转换为文件
  function dataURLtoFile(dataurl, file) {
    var arr = dataurl.split(","),
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], file.name, {
      type: file.type
    });
  }
  // 压缩图片
  function compress(img) {
    let canvas = document.createElement("canvas");
    let ctx = canvas.getContext("2d");
    //瓦片canvas
    let tCanvas = document.createElement("canvas");
    let tctx = tCanvas.getContext("2d");
    // let initSize = img.src.length;
    let width = img.width;
    let height = img.height;
    //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
    let ratio;
    if ((ratio = (width * height) / 4000000) > 1) {
      // console.log("大于400万像素");
      ratio = Math.sqrt(ratio);
      width /= ratio;
      height /= ratio;
    } else {
      ratio = 1;
    }
    canvas.width = width;
    canvas.height = height;
    //    铺底色
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    //如果图片像素大于100万则使用瓦片绘制
    let count;
    if ((count = (width * height) / 1000000) > 1) {
      // console.log("超过100W像素");
      count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
      //      计算每块瓦片的宽和高
      let nw = ~~(width / count);
      let nh = ~~(height / count);
      tCanvas.width = nw;
      tCanvas.height = nh;
      for (let i = 0; i < count; i++) {
        for (let j = 0; j < count; j++) {
          tctx.drawImage(
            img,
            i * nw * ratio,
            j * nh * ratio,
            nw * ratio,
            nh * ratio,
            0,
            0,
            nw,
            nh
          );
          ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
        }
      }
    } else {
      ctx.drawImage(img, 0, 0, width, height);
    }
    //进行最小压缩
    let ndata = canvas.toDataURL("image/jpeg", 0.3);
    tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
    return ndata;
  }
  // 看支持不支持FileReader
  if (!file || !window.FileReader) {
    return;
  }
  if (/^image/.test(file.type)) {
    // 创建一个reader
    let reader = new FileReader();
    // 将图片转成 base64 格式
    reader.readAsDataURL(file);
    // 读取成功后的回调
    reader.onloadend = function () {
      let result = this.result;
      let img = new Image();
      img.src = result;
      //判断图片是否小于2M,是就直接上传,反之压缩图片
      if (this.result.length <= 2000 * 1024) {
        // 上传图片
        let imageFile = dataURLtoFile(this.result, file);
        callback(imageFile);
      } else {
        img.onload = function () {
          let data = compress(img);
          // 上传图片
          let imageFile = dataURLtoFile(data, file);
          callback(imageFile);
        };
      }
    }
  } else {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = function () {
      let result = this.result;
      let img = new Image();
      img.src = result;
      let imageFile = dataURLtoFile(this.result, file);
      callback(imageFile);
    }
  }
};

三、在其他vue文件中引用封装的NewUpload组件,Pagenation组件

<template>
  <div id="joinOrder">
    <el-breadcrumb separator="/" style="margin-bottom: 12px">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>工单管理</el-breadcrumb-item>
      <el-breadcrumb-item>文档管理</el-breadcrumb-item>
    </el-breadcrumb>
    <el-row class="tableRow">
      <div class="tableTop">
        <div class="tableText"><span class="bgInfo"></span>文档管理信息</div>
        <div class="tableBtn">
          <el-button
            type="primary"
            icon="el-icon-plus"
            class="primBtn"
            @click="addDocument"
            >新增</el-button
          >
          <!-- <el-button plain class="plainBtn" @click="deleteClick('all')"
            >删除</el-button
          > -->
        </div>
      </div>
      <div class="tableAllpa">
        <el-table
          ref="multipleTable"
          :data="tableData"
          tooltip-effect="dark"
          @selection-change="handleSelectionChange"
          class="selecStyl"
          v-loading="tableFlag"
        >
          <el-table-column type="selection" width="55"> </el-table-column>
          <el-table-column prop="sort" label="序号"> </el-table-column>
          <el-table-column prop="name" label="文档名称"> </el-table-column>
          <el-table-column prop="fileTypeText" label="文档类型">
          </el-table-column>
          <el-table-column prop="orderTypeText" label="工单类型">
          </el-table-column>
          <el-table-column fixed="right" label="操作" width="130">
            <template slot-scope="scope">
              <el-button
                @click="documEdit(scope.row)"
                type="text"
                size="small"
                class="tableBtnStyl"
                >编辑</el-button
              >
              <el-button
                type="text"
                size="small"
                @click="deleteClick(scope.row)"
                >删除</el-button
              >
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-row>
    <Pagenation
      :pages="pages"
      @sizeChange="handleSizeChange"
      @currentChange="handleCurrentChange"
    />
    <el-dialog
      :title="!editFlag ? '添加文档管理' : '编辑文档管理'"
      :visible.sync="feedFlag"
      :close-on-click-modal="false"
      :append-to-body="true"
    >
      <el-form
        :model="feedForm"
        :rules="feedrules"
        ref="feedForm"
        label-width="120px"
        label-position="left"
        class="demo-ruleForm"
      >
        <el-row :gutter="16">
          <el-col :md="24" :lg="24" :xl="24">
            <el-form-item label="文档类型:" prop="docuType">
              <el-select
                v-model="feedForm.docuType"
                placeholder="请选择"
                clearable
              >
                <el-option value="">请选择</el-option>
                <el-option
                  v-for="item in orginList"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                >
                </el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="工单类型:" prop="orderType">
              <el-select
                v-model="feedForm.orderType"
                placeholder="请选择"
                clearable
              >
                <el-option value="">请选择</el-option>
                <el-option
                  v-for="item in orderList"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                >
                </el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="文档路径:" prop="">
              <NewUpload
                v-model="docuList"
                :fileSize="5"
                :fileLimit="1"
                listType="text"
                :fileType="[
                  'pdf',
                  'doc',
                  'docx',
                  'xls',
                  'xlsx',
                  'png',
                  'jpg',
                  'jpeg',
                ]"
                ref="refName"
              />
            </el-form-item>
            <el-form-item label="文档名称:" prop="docuName">
              <el-input
                v-model.trim="feedForm.docuName"
                placeholder="请输入文档名称"
                clearable
              ></el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <div>
          <el-button @click="feedFlag = false" plain>取 消</el-button>
          <el-button
            type="primary"
            @click="feedSubmit('feedForm')"
            :loading="saveFlag"
            >确认</el-button
          >
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { documentPage, documentSave, documentDel, documentDtl } from '@/api/orderApi/index.js'
import Pagenation from '@/components/comChild/Pagenation.vue'
import NewUpload from '@/components/comChild/NewUpload.vue'
export default {
  data() {
    return {
      saveFlag: false,
      editFlag: false,
      feedFlag: false,
      feedForm: {
        docuName: '',
        docuType: '',
        orderType: ''
      },
      docuList: [],
      docuListNew: [],
      feedrules: {
        docuName: [
          { required: true, message: '请输入文档名称', trigger: 'change' }
        ],
        docuType: [
          { required: true, message: '请选择文档类型', trigger: 'change' }
        ],
        orderType: [
          { required: true, message: '请选择工单类型', trigger: 'change' }
        ]
      },
      searchFlag: false,
      tableFlag: false,
      formLine: {
        organName: '',
        orginType: ''
      },
      orginList: [
        {
          value: 1,
          label: '验收结果'
        },
        {
          value: 2,
          label: '现场验收'
        },
        {
          value: 3,
          label: '线上(远程)验收'
        },
      ],
      orderList: [
        {
          value: 1,
          label: '验收申请工单'
        }
      ],
      tableData: [],
      pages: {
        pageSize: 10,
        currentPage: 1,
        total: 0,
      },
      id: '',
      multipleId: []
    }
  },
  components: {
    Pagenation, NewUpload
  },
  watch: {
    docuList: {
      handler(newVal) {
        if (newVal.length > 0 && !this.id) {
          this.feedForm.docuName = newVal[0].name
        }
      }
    }
  },
  mounted() {
    this.getNewsList()
  },
  methods: {
    addDocument() {
      this.feedFlag = true
      this.editFlag = false
      this.id = ''
      this.feedForm = {
        docuName: '',
        docuType: '',
        orderType: ''
      }
      if (this.$refs.refName) {
        this.$refs.refName.fileList = []
      }
      if (this.$refs['feedForm']) {
        this.$refs['feedForm'].resetFields();
      }
    },
    feedSubmit(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.docuListNew = []
          this.docuList.forEach((item) => {
            this.docuListNew.push(item.url)
          })
          this.getDocumSave()
        } else {
          return false;
        }
      });
    },
    async getDocumDtl() {
      const data = {
        id: this.id
      }
      await documentDtl(data).then(
        (resp) => {
          if (resp.code === 0) {
            this.feedForm.docuType = resp.payload.fileType
            this.feedForm.orderType = resp.payload.orderType
            this.feedForm.docuName = resp.payload.name
            let obj = {}
            obj = {
              name: resp.payload.name,
              url: resp.payload.fileUrls
            }
            this.docuList = [obj]
            this.$refs.refName.fileList = this.docuList
          } else {
            this.$message.error(resp.errorMessage)
          }
        },
        (error) => {
          this.$message.error(error)
        }
      )
    },
    getDocumSave() {
      const data = {
        fileType: this.feedForm.docuType,
        orderType: this.feedForm.orderType,
        fileUrls: this.docuListNew.join(','),
        name: this.feedForm.docuName,
        id: this.id
      }
      this.saveFlag = true
      documentSave(data).then(
        (resp) => {
          if (resp.code === 0) {
            if (!this.editFlag) {
              this.$message({
                message: '新增成功',
                type: 'success'
              })
            } else {
              this.$message({
                message: '编辑成功',
                type: 'success'
              })
            }
            this.feedFlag = false
            this.getNewsList()
          } else {
            this.$message.error(resp.errorMessage)
          }
          this.saveFlag = false
        },
        (error) => {
          this.saveFlag = false
          this.$message.error(error)
        }
      )
    },
    deleteClick(row) {
      if (row == 'all') {
        this.$message.error('该功能暂未开发')
        return
      }
      this.$confirm('此操作将永久删除该条数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        cancelButtonClass: 'deleteBtn',
        type: 'warning'
      }).then(async () => {
        await this.getDocumentDel(row)
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    getDocumentDel(item) {
      let newUserId = ''
      if (item == 'all') {
        newUserId = this.multipleId.join(',')
      } else {
        newUserId = item.id
      }
      const data = {
        data1: {
          id: newUserId
        }
      }
      documentDel(data).then(
        (resp) => {
          if (resp.code === 0) {
            this.$message({
              type: 'success',
              message: '删除成功!'
            });
            this.getNewsList()
          } else {
            this.$message.error(resp.errorMessage)
          }
        },
        (error) => {
          this.$message.error(error)
        }
      )
    },
    handleSelectionChange(val) {
      this.multipleId = []
      val.forEach((item) => {
        this.multipleId.push(item.id)
      })
    },
    clearTable() {
      this.formLine = {
        organName: '',
        orginType: ''
      }
      this.pages = {
        pageSize: 10,
        currentPage: 1,
        total: 0,
      },
        this.getNewsList()
    },
    searchTable() {
      this.pages = {
        pageSize: 10,
        currentPage: 1,
        total: 0,
      },
        this.getNewsList(true)
    },
    async documEdit(row) {
      this.feedFlag = true
      this.editFlag = true
      this.id = row.id
      await this.getDocumDtl()
    },
    getNewsList(isSearch) {
      if (isSearch) {
        this.searchFlag = true
      }
      this.tableFlag = true
      const data = {
        data1: {
          pageNo: this.pages.currentPage,
          pageSize: this.pages.pageSize
        },
        data2: {
          name: this.formLine.organName,
          fileType: this.formLine.orginType,
          orderType: ''
        }
      }
      documentPage(data).then(
        (resp) => {
          if (resp.code === 0) {
            this.tableData = resp.payload.records
            this.tableData.forEach((item) => {
              switch (item.fileType) {
                case 1:
                  item.fileTypeText = '验收结果'
                  break
                case 2:
                  item.fileTypeText = '现场验收'
                  break
                case 3:
                  item.fileTypeText = '线上(远程)验收'
                  break
                default:
                  break
              }
              switch (item.orderType) {
                case 1:
                  item.orderTypeText = '验收申请工单'
                  break
                case 2:
                  item.orderTypeText = '网络接入工单'
                  break
                default:
                  break
              }
            })
            this.pages.total = resp.payload.total
            if (isSearch) {
              this.$message({
                message: '查询成功',
                type: 'success'
              })
            }
          } else {
            this.$message.error(resp.errorMessage)
          }
          this.searchFlag = false
          this.tableFlag = false
        },
        (error) => {
          this.searchFlag = false
          this.tableFlag = false
          this.$message.error(error)
        }
      )
    },
    handleSizeChange(newSize) {
      this.pages.pageSize = newSize;
      this.getNewsList();
    },
    //页码改变
    handleCurrentChange(newPage) {
      this.pages.currentPage = newPage;
      this.getNewsList();
    },
    toggleSelection(rows) {
      if (rows) {
        rows.forEach(row => {
          this.$refs.multipleTable.toggleRowSelection(row);
        });
      } else {
        this.$refs.multipleTable.clearSelection();
      }
    }
  }
}
</script>

<style lang="less" scoped>

</style>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值