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

    @天才卧龙的博客

  • 相关阅读:
    [转]ASP NET 缓存相关介绍及汇总
    比较经典的SQL行转列+分组集联
    平面向量的叉乘
    获得一点到三角形最近点
    检测线段是否有交集
    线段交集点计算
    UE4 移动设备 不显示影子问题
    Unity通过世界坐标系转换到界面坐标位置
    selemium 常用查找方法
    unity导入TexturePacker处理
  • 原文地址:https://www.cnblogs.com/chenwolong/p/14246840.html
Copyright © 2011-2022 走看看