zoukankan      html  css  js  c++  java
  • Vue+antd 上传附件a-upload组件化,附送C#异步上传文件代码【NetFrm4.5+】+Vue 增删改查代码

    十年河东,十年河西,莫欺少年穷

    学无止境,精益求精

    这是一个后端开发人员的倔强

    因项目需要,我从一个纯后端变成了前端+后端,也俗称全栈。

    在实际项目中,上传附件几乎是必不可少的,因此,我们有必要将上传控件进行组件化。

    设计理念,通过vue的父子传值进行封装,上传组件为子组件,调用方为父组件,由父组件传值给子组件,用来校验上传的文件扩展名及大小。

    子组件

    <template>
      <a-upload
        :beforeUpload="beforeUpload"
        :multiple="false"
        @change="filechange"
        :customRequest="customRequest"
        :fileList="fileList"
        :remove="fileRemove"
      >
        <a-button> <a-icon type="upload" /> 选择文件 </a-button>
      </a-upload>
    </template>
    <script>
    export default {
      props: ["fileinfo"],
      created() {},
      data() {
        return {
          fileList: [],
        };
      },
      methods: {
        beforeUpload(file) {
          var that = this;
          //console.log(file);
          return new Promise((resolve, reject) => {
            const isLt100M = file.size / 1024 / 1024 > that.fileinfo.maxsize;
            if (isLt100M) {
              this.$message.warning(
                "上传附件大小不能超过" + that.fileinfo.maxsize + "M。"
              );
              return reject(false);
            }
            var index = file.name.lastIndexOf(".");
            var suffix = file.name.substring(index + 1);
            if( that.fileinfo.filetype.indexOf(suffix)<0){
                  this.$message.warning(
                "上传的文件格式不符合要求"
              );
              return reject(false);
            }
            return resolve(true);
          });
        },
        filechange(info) {
          //console.log(info);
          this.fileList = info.fileList;
          //console.log(this.fileList);
    
          if (info.file.status == "uploading") {
          }
          if (info.file.status === "done") {
          } else if (info.file.status === "error") {
          }
        },
        customRequest(data) {
          // 上传提交
          const formData = new FormData();
          formData.append("file", data.file);
          this.saveFile(formData);
        },
        saveFile(formData) {
          let that = this;
    
          this.$axios({
            url: "/api/File/UploadFileStream",
            method: "post",
            data: formData,
          })
            .then(function (result) {
              //console.log(result);
              //that.fileList.push(result.Data)
              if (result.IsSuccess) {
                for (var i = 0; i < that.fileList.length; i++) {
                  that.fileList[i].status = "done";
                }
                console.log(that.fileinfo.uploadfiles);
                that.fileinfo.uploadfiles.push(result.Data);
    
                that.$message.success("上传附件成功。");
              } else {
                //that.fileList = [];
                for (var i = 0; i < that.fileList.length; i++) {
                  if (that.fileList[i].status != "done") {
                    that.fileList.splice(i, 1);
                  }
                }
                that.$message.warning(result.ResultMessage);
              }
            })
            .catch(function (error) {
              console.log(error);
            });
        },
        fileRemove(file) {
          //console.log(file);
          var that = this;
          for (var i = 0; i < that.fileinfo.uploadfiles.length; i++) {
            if (
              that.fileinfo.uploadfiles[i].oldfilename == file.name &&
              that.fileinfo.uploadfiles[i].filesize == file.size
            ) {
              that.fileinfo.uploadfiles.splice(i, 1);
              //alert(1)
            }
          }
        },
      },
    };
    </script>
    View Code

    父组件

    <template>
      <div>
        <a-row align="middle" class="arowLat">
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  OTA固件包
                </a-checkable-tag>
               <file-upload  v-bind:fileinfo="fileinfo"></file-upload>
              </a-col>
              <a-col :span="12"> 
                 <a-button @click="submit">提交</a-button>
              </a-col>
            </a-row>
      </div>
    </template>
    
    <script>
    
    export default {
      name: "Echarts",
      data() {
        return {
          checked:false,
          fileinfo: {
            maxsize: 1024 * 1024 * 100,
            filetype: ["jpg", "png"],
            uploadfiles: [],
          },
        };
      },
      methods: {
        submit() {
          console.log(this.fileinfo.uploadfiles);
        }
      },
      mounted() {},
    };
    </script>
    <style scoped>
    .img {
       100%;
      height: auto;
    }
    .arow {
      text-align: left;
    }
    
    .arowLat {
      text-align: left;
      margin-top: 25px;
    }
    </style>
    View Code

    下面来简单分析下上述源码

    父组件Data中fileinfo的属性用来校验文件大小,扩展名

      data() {
        return {
          checked:false,
          fileinfo: {
            maxsize: 1024 * 1024 * 100,
            filetype: ["jpg", "png"],
            uploadfiles: [],
          },
        };
      }

    注:uploadfiles 用于接收子组件请求后台的结果,我的后台返回值为:

    {
        Data {
            LocalFilePath: "E:IOTIotApiContentOTA4dccdff9bc17413c96d98031a8a451ec.bin",
            filedata: [80, 19, 0, 32, 1, 33, 0, 8, 1, 139, 0, 8, 69, 114, 0, 8, 229, 138, 0, 8, 43, 74, 0, 8, 219, 182, 0, 8, 0, 0...],
            filename: "4dccdff9bc17413c96d98031a8a451ec.bin",
            filepath: "~/Content/OTA/4dccdff9bc17413c96d98031a8a451ec.bin",
            filesize: 49336,
            oldfilename: "LBS-1522-YQ4501.jpg",
        }
    IsSuccess:
    true, ResultCode: 0, ResultMessage: "请求成功...", }

    fileinfo 用于传值给子组件,子组件中有对应的 props,如下

      props: ["fileinfo"],

    a-upload 组件中有个名叫 beforeUpload 的钩子函数,我们用来校验上传的文件,如果通过校验,则上传

    beforeUpload(file) {
          var that = this;
          //console.log(file);
          return new Promise((resolve, reject) => {
            const isLt100M = file.size / 1024 / 1024 > that.fileinfo.maxsize;
            if (isLt100M) {
              this.$message.warning(
                "上传附件大小不能超过" + that.fileinfo.maxsize + "M。"
              );
              return reject(false);
            }
            var index = file.name.lastIndexOf(".");
            var suffix = file.name.substring(index + 1);
            if( that.fileinfo.filetype.indexOf(suffix)<0){
                  this.$message.warning(
                "上传的文件格式不符合要求"
              );
              return reject(false);
            }
            return resolve(true);
          });
        },

    fileRemove 方法用来同步移除 uploadfiles 的元素,保持和组件显示的上传文件一致。

        fileRemove(file) {
          //console.log(file);
          var that = this;
          for (var i = 0; i < that.fileinfo.uploadfiles.length; i++) {
            if (
              that.fileinfo.uploadfiles[i].oldfilename == file.name &&
              that.fileinfo.uploadfiles[i].filesize == file.size
            ) {
              that.fileinfo.uploadfiles.splice(i, 1);
              //alert(1)
            }
          }
        },

    在组件开发阶段,遇到一个问题,上传成功后,上传的状态一直是 uploading ,为了解决这个问题,我们需要在 filechange、customRequest、saveFile 一起解决。

    主要是在 filechange 中给filelist赋值,在 saveFile 中当文件上传成功后,修改状态为done,如果上传失败,我们需要将filelist中上传失败的元素移除。

        filechange(info) {
          //console.log(info);
          this.fileList = info.fileList;
          //console.log(this.fileList);
    
          if (info.file.status == "uploading") {
          }
          if (info.file.status === "done") {
          } else if (info.file.status === "error") {
          }
        },
        customRequest(data) {
          // 上传提交
          const formData = new FormData();
          formData.append("file", data.file);
          this.saveFile(formData);
        },
        saveFile(formData) {
          let that = this;
    
          this.$axios({
            url: "/api/File/UploadFileStream",
            method: "post",
            data: formData,
          })
            .then(function (result) {
              //console.log(result);
              //that.fileList.push(result.Data)
              if (result.IsSuccess) {
                for (var i = 0; i < that.fileList.length; i++) {
                  that.fileList[i].status = "done";
                }
                console.log(that.fileinfo.uploadfiles);
                that.fileinfo.uploadfiles.push(result.Data);
    
                that.$message.success("上传附件成功。");
              } else {
                //that.fileList = [];
                for (var i = 0; i < that.fileList.length; i++) {
                  if (that.fileList[i].status != "done") {
                    that.fileList.splice(i, 1);
                  }
                }
                that.$message.warning(result.ResultMessage);
              }
            })
            .catch(function (error) {
              console.log(error);
            });
        },
    View Code

    以上便是整个上传组件。效果图有点丑

     在父组件,点击提交,即可得到请求上传接口的返回值

     这样整个组件也就做完了,有了这个组件,以后我们只需在父组件中引用子组件,并添加Props传值对象fileinfo即可,从而节省了大量的重复代码。

    下面是C#的后端,不做解释,只贴代码。详细可参考:https://www.cnblogs.com/chenwolong/p/Uplode.html
    using Iot.Common;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Cors;
    
    namespace Iot.WebSite.Controllers.Apis
    {
        [RoutePrefix("api/file")]
        [EnableCors(origins: "*", headers: "*", methods: "GET,POST,PUT,DELETE")]
        public class FileController : ApiController
        {
            /// <summary>
            /// 上传文件
            /// </summary>
            /// <returns></returns>
            [HttpPost]
            public async Task<BaseResponse> UploadFileStream()
            {
                var returns = CommonBaseResponse.SetResponse<fileInfoModel>(null, false);
                string fileType = "OTA";//要创建的子文件夹的名字
                var uploadPath = "~/Content";
                string filePath = System.Web.HttpContext.Current.Server.MapPath(uploadPath + "/" + fileType + "/");//绝对路径
                //string filePath = uploadPath + "\" + fileType + "\";  //E:Fileup  居家
                if (Directory.Exists(filePath) == false)
                {
                    Directory.CreateDirectory(filePath);
                }
                try
                {
                    var provider = new ReNameMultipartFormDataStreamProvider(filePath);
                    await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(o =>
                    {
    
                        foreach (var file in provider.FileData)
                        {
                            string orfilename = file.Headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"');//待上传的文件名
                            FileInfo fileinfo = new FileInfo(file.LocalFileName);
                            //判断开始
                            string oldName = orfilename;//选择的文件的名称
                            string fileExt = orfilename.Substring(orfilename.LastIndexOf('.'));
                            string Extension = fileExt;
                            string CreateTime = DateTime.Now.ToString("yyyyMMddHHmmss");
    
                            fileInfoModel fileResult = new fileInfoModel()
                            {
                                oldfilename = oldName,
                                LocalFilePath = file.LocalFileName,
                                filesize = fileinfo.Length,
                                filename = fileinfo.Name,
                                filepath = uploadPath + "/" + fileType + "/" + fileinfo.Name
                            };
    
                            var fs = fileinfo.OpenRead();
                            byte[] buffur = new byte[fs.Length];
                            fs.Read(buffur, 0, (int)fs.Length);
                            fileResult.filedata = buffur.ToList();
                            returns = CommonBaseResponse.SetResponse<fileInfoModel>(fileResult, true);
                        }
                    });
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog("上传附件出错:" + ex.ToString());
                }
                return returns;
            }
        }
        /// <summary>
        /// 重命名上传的文件
        /// </summary>
        public class ReNameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
        {
            public ReNameMultipartFormDataStreamProvider(string root)
                : base(root)
            { }
    
            public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
            {
    
                string extension = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? Path.GetExtension(GetValidFileName(headers.ContentDisposition.FileName)) : "";
                return Guid.NewGuid().ToString().Replace("-", "") + extension;
            }
    
            private string GetValidFileName(string filePath)
            {
                char[] invalids = System.IO.Path.GetInvalidFileNameChars();
                return String.Join("_", filePath.Split(invalids, StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.');
            }
    
        }
    
        public class fileInfoModel
        {
            /// <summary>
            /// 新文件名称
            /// </summary>
            public string filename { get; set; }
            /// <summary>
            /// 老文件名称
            /// </summary>
            public string oldfilename { get; set; }
            /// <summary>
            /// 服务器绝对地址
            /// </summary>
            public string LocalFilePath { get; set; }
            /// <summary>
            /// 文件大小 字节
            /// </summary>
            public long filesize { get; set; }
            /// <summary>
            /// 问价数据
            /// </summary>
            public List<byte> filedata { get; set; }
            /// <summary>
            /// 文件相对路径
            /// </summary>
            public string filepath { get; set; }
        }
    }
    View Code

    增删改查代码,只做记录,方便自己以后查看

    <template>
      <div>
        <a-card
          hoverable="true"
          title=""
          headStyle="text-align:left;color:#606266;font-size:14px"
          bodyStyle="border:none"
        >
          <a slot="extra" href="#" style="float: left">
            <a-breadcrumb separator=">">
              <a-breadcrumb-item>OTA升级</a-breadcrumb-item>
    
              <a-breadcrumb-item>电池OTA升级 </a-breadcrumb-item>
            </a-breadcrumb>
          </a>
          <div>
            <a-row align="middle" class="arow">
              <a-col :span="6">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  OTA版本号
                </a-checkable-tag>
                <a-input
                  placeholder="请输入OTA版本号"
                  style=" 180px"
                  v-model="SearchInfo.SoftWare"
                />
              </a-col>
              <a-col :span="6">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  BMS版本号
                </a-checkable-tag>
                <a-input
                  placeholder="请输入BMS版本号"
                  style=" 180px"
                  v-model="SearchInfo.OldSoftWare"
                />
              </a-col>
              <a-col :span="6"> </a-col>
              <a-col :span="6">
                <a-button type="primary" @click="Search"> 查询 </a-button>
                &nbsp;
                <a-button type="danger" @click="() => setModal1Visible(true)">
                  新增
                </a-button>
              </a-col>
            </a-row>
    
            <a-table
              :columns="columns"
              :data-source="data"
              style="margin-top: 20px"
            >
              <template slot="action" slot-scope="text, record">
                <a slot="action" href="javascript:;" @click="deleterow(record)"
                  >删除</a
                >
                <a slot="action"  href="javascript:;" @click="onEdit(record)" >编辑</a> 
                <!-- <span slot="action" slot-scope="text" href="javascript:;" @click="onEdit()" >删除</span> -->
              </template>
            </a-table>
          </div>
        </a-card>
    
        <a-modal
          title="新增OTA升级信息"
          :width="760"
          :okText="提交"
          :cancelText="取消"
          :dialog-style="{ top: '20px' }"
          :visible="modal1Visible"
          @ok="() => Save()"
          @cancel="() => setModal1Visible(false)"
        >
          <a-card
            hoverable="true"
            title=""
            headStyle="text-align:left;color:#606266;font-size:14px"
            bodyStyle="border:none"
          >
            <a-row align="middle" class="arow">
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  OTA版本号
                </a-checkable-tag>
                <a-input
                  placeholder="请输入OTA版本号"
                  style=" 180px"
                  v-model="OtaModel.SoftWare"
                />
              </a-col>
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  单包大小
                </a-checkable-tag>
                <a-input-number
                  v-model="OtaModel.SigPackSize"
                  placeholder="请输入单包大小"
                  :min="64"
                  :max="2048"
                  style=" 180px"
                />
              </a-col>
            </a-row>
            <a-row align="middle" class="arowLat">
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  BMS版本号
                </a-checkable-tag>
                <a-input
                  placeholder="请输入BMS版本号"
                  style=" 180px"
                  v-model="OtaModel.OldSoftWare"
                />
              </a-col>
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  升级描述
                </a-checkable-tag>
                <a-input
                  placeholder="请输入升级描述"
                  style=" 180px"
                  v-model="OtaModel.OtaFileInfo"
                />
              </a-col>
            </a-row>
            <a-row align="middle" class="arowLat">
              <a-col :span="12">
                <a-checkable-tag v-model="checked" @change="handleChange">
                  OTA固件包
                </a-checkable-tag>
                <file-upload v-bind:fileinfo="fileinfo"></file-upload>
              </a-col>
              <a-col :span="12"> </a-col>
            </a-row>
          </a-card>
        </a-modal>
      </div>
    </template>
    
    <script>
    import moment from "moment";
    import "moment/locale/zh-cn";
    import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
    const formatterTime = (val) => {
      alert(val);
      return val ? moment(val).format("YYYY-MM-DD HH:mm:ss") : "";
    };
    const columns = [
      {
        title: "升级描述",
         200,
        dataIndex: "OtaFileInfo",
        key: "OtaFileInfo",
        align: "center",
      },
      { title: "固件大小(字节)", dataIndex: "FileSize", key: "1", align: "center" },
      { title: "BMS版本号", dataIndex: "OldSoftWare", key: "2", align: "center" },
      { title: "OTA版本号", dataIndex: "SoftWare", key: "3", align: "center" },
      {
        title: "单包大小(字节)",
        dataIndex: "SigPackSize",
        key: "4",
        align: "center",
      },
      {
        title: "创建日期",
        dataIndex: "CreateTime",
        key: "8",
        align: "center",
        customRender: function (val) {
          return val ? moment(val).format("YYYY-MM-DD") : "";
        },
      },
      {
        title: "操作",
        key: "operation",
        align: "center",
         100,
        scopedSlots: { customRender: "action"},
      },
    ];
    
    const data = [];
    
    export default {
      name: "Echarts",
      data() {
        return {
          locale,
          checked: false,
          checkedmodal: true,
          dateFormat: "YYYY/MM/DD",
          monthFormat: "YYYY/MM",
          data,
          columns,
          modal1Visible: false,
          fileinfo: {
            maxsize: 1024 * 1024 * 10,
            filetype: ["bin"],
            uploadfiles: [],
          },
          OtaModel: {
            OldSoftWare: "",
            SoftWare: "",
            SigPackSize: 512,
            OtaFileInfo: "",
            FileName: "",
            oldfilename: "",
            LocalFilePath: "",
            filesize: 0,
            filedata: [],
            FilePath: "",
          },
          SearchInfo: {
            SoftWare: "",
            OldSoftWare: "",
            PageNumber: 1,
            PageSize: 1,
            Stime: "2020-01-01",
            Etime: "2030-01-01",
          },
        };
      },
      methods: {
        moment,
        onChange(dates, dateStrings) {
          console.log("From: ", dates[0], ", to: ", dates[1]);
          console.log("From: ", dateStrings[0], ", to: ", dateStrings[1]);
        },
        handleChange(checked) {},
        setModal1Visible(modal1Visible) {
          this.modal1Visible = modal1Visible;
        },
        Save() {
          let that = this;
          if (!that.OtaModel.OldSoftWare) {
            that.$message.error("请输入BMS版本号。");
            return;
          } else if (!that.OtaModel.SoftWare) {
            that.$message.error("请输入OTA版本号。");
            return;
          } else if (!that.OtaModel.SigPackSize) {
            that.$message.error("请输入单包大小。");
            return;
          } else if (!that.OtaModel.OtaFileInfo) {
            that.$message.error("请输入OTA版本描述");
            return;
          } else if (
            !that.fileinfo.uploadfiles ||
            that.fileinfo.uploadfiles.length != 1
          ) {
            that.$message.error("请上传升级固件包【有且仅能上传一个固件包】");
            return;
          } else {
            that.OtaModel.FileName = that.fileinfo.uploadfiles[0].filename;
            that.OtaModel.oldfilename = that.fileinfo.uploadfiles[0].oldfilename;
            that.OtaModel.LocalFilePath =
              that.fileinfo.uploadfiles[0].LocalFilePath;
            that.OtaModel.filesize = that.fileinfo.uploadfiles[0].filesize;
            that.OtaModel.filedata = that.fileinfo.uploadfiles[0].filedata;
            that.OtaModel.FilePath = that.fileinfo.uploadfiles[0].filepath;
            //console.log(that.OtaModel);
    
            that
              .$axios({
                url: "/api/BatteryOta/CreateBatteryOtaSoftWareInfo",
                method: "post",
                data: that.OtaModel,
              })
              .then(function (result) {
                if (result.IsSuccess) {
                  that.OtaModel = {
                    OldSoftWare: "",
                    SoftWare: "",
                    SigPackSize: 512,
                    OtaFileInfo: "",
                    FileName: "",
                    oldfilename: "",
                    LocalFilePath: "",
                    filesize: 0,
                    filedata: [],
                    FilePath: "",
                  };
                  that.modal1Visible = false;
                } else {
                  that.$message.error(result.ResultMessage);
                  that.OtaModel = {
                    OldSoftWare: "",
                    SoftWare: "",
                    SigPackSize: 512,
                    OtaFileInfo: "",
                    FileName: "",
                    oldfilename: "",
                    LocalFilePath: "",
                    filesize: 0,
                    filedata: [],
                    FilePath: "",
                  };
                }
              })
              .catch(function (error) {
                console.log(error);
              });
          }
        },
        Search() {
          let that = this;
          that
            .$axios({
              url: "/api/BatteryOta/SearchOtaSoftWareInfo",
              method: "post",
              data: that.SearchInfo,
            })
            .then(function (result) {
              console.log(result);
              if (result.IsSuccess) {
                that.data = result.Data.Data;
              } else {
                that.$message.error(result.ResultMessage);
              }
            })
            .catch(function (error) {
              console.log(error);
            });
        },
        deleterow(record) {
          console.log(record);
        },
      },
      mounted() {},
      created() {
        this.Search();
      },
    };
    </script>
    <style scoped>
    .img {
       100%;
      height: auto;
    }
    .arow {
      text-align: left;
    }
    
    .arowLat {
      text-align: left;
      margin-top: 25px;
    }
    </style>
    View Code

    @天才卧龙的博客

  • 相关阅读:
    Fidder4 顶部提示 “The system proxy was changed,click to reenable fiddler capture”。
    redis 哨兵 sentinel master slave 连接建立过程
    虚拟点赞浏览功能的大数据量测试
    python基础练习题(题目 字母识词)
    python基础练习题(题目 回文数)
    python基础练习题(题目 递归求等差数列)
    python基础练习题(题目 递归输出)
    python基础练习题(题目 递归求阶乘)
    python基础练习题(题目 阶乘求和)
    python基础练习题(题目 斐波那契数列II)
  • 原文地址:https://www.cnblogs.com/chenwolong/p/14246840.html
Copyright © 2011-2022 走看看