• Blazor 拖放上传文件转换格式并推送到浏览器下载


    前言

    昨天有个小伙伴发了一个老外java编写的小工具给我,功能是转换西班牙邮局快递Coreeos express的单据格式成Amazon格式,他的需求是改一下程序为匹配转换另一个快递公司MRW格式到Amazon格式,然而我堂堂一个Blazor发烧友,怎么可能去反编译人家的java修改呢?必须直接撸一个Blazor的啊.

    实现目标

    拖放多文件上传, 不落地(无中间保存临时文件)直接内存流转换格式, 直接推送弹出下载文件.

    分析需求

    原始MRW文件.txt

    "Abonado","Depto.","Fecha","N. Envio","N. Lote","Tipo de Cobro","Bultos","Kg.","Imp Reemb.","Referencia","Destinatario","Direccion","C.P.","Poblacion","Pais","Servicio","Retorno Alb.",""
    "xxx  SL ","N/A","15/02/2023","0263608650029","02636xxx20230214204409","Pagados","1","1","","403-6273741-3115504","Antonia xxx FERNANDEZ","C/MENDEZ NUÑEZ 222","06420","CASTUERA","ESPAÑA","U19E--Urgente 19 Expedición","SinRetorno",""
    "xxx  SL ","N/A","15/02/2023","0263608650028","02636xxx20230214204409","Pagados","1","1","","406-8908494-9500324","Baris xxx","Parque Erreniega Parkea,","31180","CIZUR MAYOR","ESPAÑA","U19E--Urgente 19 Expedición","SinRetorno",""
    

    实体类

    来源

      public class MrwTicket
        {
            public string Abonado { get; set; }
    
            [DisplayName("Depto.")]
            public string Depto { get; set; }
    
            public DateTime Fecha { get; set; }
    
            [DisplayName("N. Envio")]
            public string N_Envio { get; set; }
    
            [DisplayName("N. Lote")]
            public string N_Lote { get; set; }
    
            [DisplayName("Tipo de Cobro")]
            public string TipoDeCobro { get; set; }
    
            public string Bultos { get; set; }
    
            [DisplayName("Kg.")]
            public string Kg { get; set; }
    
            [DisplayName("Imp Reemb.")]
            public string ImpReemb { get; set; }
    
    
            public string Referencia { get; set; }
    
    
            public string Destinatario { get; set; }
    
    
            public string Direccion { get; set; }
    
            [DisplayName("C.P.")]
            public string CP { get; set; }
    
            public string Poblacion { get; set; }
    
            public string Pais { get; set; }
    
            public string Servicio { get; set; }
    
            [DisplayName("Retorno Alb.")]
            public string RetornoAlb { get; set; }
        }
    

    转换目标

        public class AmazonTicket
        {
    
            [DisplayName("order-id")]
            public string Order_id { get; set; }
    
            [DisplayName("order-item-id")]
            public string Order_item_id { get; set; }
    
            [DisplayName("quantity")]
            public string Quantity { get; set; }
    
            [DisplayName("ship-date")]
            public string Ship_date { get; set; }
    
            [DisplayName("carrier-code")]
            public string Carrier_code { get; set; }
    
            [DisplayName("carrier-name")]
            public string Carrier_name { get; set; }
    
            [DisplayName("tracking-number")]
            public string Tracking_number { get; set; }
    
            [DisplayName("ship-method")]
            public string Ship_method { get; set; }
    
        }
    

    建立Blazor页面 Mrw2Amazon.razor

    拖放上传可以参考往期文章 https://www.cnblogs.com/densen2014/p/16128246.html

    组件UI

    @page "/Mrw2Amazon"
    @inherits PublicComponentsBase
    @namespace AmeBlazor.Components
    
    

    MRW txt 转 Amazon txt

    MRW txt 转 Amazon txt

    拖放上传文件

    
            @uploadstatus
    
    

    拖放上传js文件 wwwroot/drag.js

    export function init(wrapper, element, inputFile) {
    
        //阻止浏览器默认行为
        document.addEventListener("dragleave", function (e) {
            e.preventDefault();
        }, false);
        document.addEventListener("drop", function (e) {
            e.preventDefault();
        }, false);
        document.addEventListener("dragenter", function (e) {
            e.preventDefault();
        }, false);
        document.addEventListener("dragover", function (e) {
            e.preventDefault();
        }, false); 
    
        element.addEventListener("drop", function (e) {
    
            try {
                var fileList = e.dataTransfer.files; //获取文件对象
                //检测是否是拖拽文件到页面的操作
                if (fileList.length == 0) {
                    return false;
                }
    
                inputFile.files = e.dataTransfer.files;
                const event = new Event('change', { bubbles: true });
                inputFile.dispatchEvent(event);
            }
            catch (e) {
                wrapper.invokeMethodAsync('DropAlert', e);
            }
        }, false);
    
        element.addEventListener('paste', function (e) {
        
            inputFile.files = e.clipboardData.files;
            const event = new Event('change', { bubbles: true });
            inputFile.dispatchEvent(event);
        }, false);
    
        return {
            dispose: () => {
                element.removeEventListener('dragleave', onDragLeave);
                element.removeEventListener("drop", onDrop);
                element.removeEventListener('dragenter', onDragHover);
                element.removeEventListener('dragover', onDragHover);
                element.removeEventListener('paste', handler);
            }
        }
    }
    

    下载功能

    Pages\_Layout.cshtml < /body >之前添加js代码

        
    

    插播:

    突然想起来 下载功能 里面的js代码有坑, 旧的设备例如安卓手机会不能用. 以前文章有写过, 大家注意一下

    anchorElement.download = fileName ?? ''; 改为以下代码

        if (fileName == null) fileName = ""
        anchorElement.download = fileName;
    

    组件代码Mrw2Amazon.razor.cs

    先拉个库MiniExcel

    1. 动态加载 drag.js 文件.(参考往期文章,js隔离 https://www.cnblogs.com/densen2014/p/16027851.html)
    2. 使用拖放读取到 IBrowserFile 文件流
    3. 转换为 MemoryStream 供给 MiniExcel 读取. (PS:不能直接使用 IBrowserFile 的 stream , 当作课后作业自己了解一下.)
    4. MiniExcel 读取格式: var mrwTicket = MiniExcel.Query(fs, excelType: ExcelType.CSV).ToList();
    5. 转换格式
    6. 另存为目标格式csv
    7. 直接弹出目标文件下载到浏览器
    8. 全程不落地
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Forms;
    using Microsoft.JSInterop;
    using MiniExcelLibs;
    using MiniExcelLibs.Csv;
    
        public partial class Mrw2Amazon : IAsyncDisposable
        {
    
            [Inject]
            IJSRuntime JS { get; set; }
            
            //既然不落地,那就不需要这些了
            //[Inject] 
            //protected Microsoft.AspNetCore.Hosting.IWebHostEnvironment HostEnvironment { get; set; }
    
            protected ElementReference UploadElement { get; set; }
            protected InputFile? inputFile { get; set; }
    
            private DotNetObjectReference? wrapper;
    
            private IJSObjectReference? module;
            private IJSObjectReference? dropInstance;
    
            //既然不落地,那就不需要这些了
            //protected string UploadPath = "";
            
            protected string? uploadstatus;
            long maxFileSize = 1024 * 1024 * 15;
    
            //既然不落地,那就不需要这些了
            //protected override void OnAfterRender(bool firstRender)
            //{
                //if (!firstRender) return;
                //UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "uploads", "temp"); //初始化上传路径
                //if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath); //不存在则新建目录
            //}
    
            protected async Task OnChange(InputFileChangeEventArgs e)
            {
                int i = 0;
                var selectedFiles = e.GetMultipleFiles(100);
                foreach (var item in selectedFiles)
                {
                    i++;
                    await OnSubmit(item);
                    uploadstatus += Environment.NewLine + $"[{i}]: " + item.Name;
                }
            }
    
            protected async Task OnSubmit(IBrowserFile efile)
            {
                try
                {
    
                if (efile == null) return;
                if (efile.ContentType != "text/plain")
                {
                    uploadstatus += Environment.NewLine + $"只接受txt文件.{efile.Name}为{efile.ContentType}";
                    return;
                }
                await using var fs = new MemoryStream();
                using var stream = efile.OpenReadStream(maxFileSize);
    
                await stream.CopyToAsync(fs);
    
                var mrwTicket = MiniExcel.Query(fs, excelType: ExcelType.CSV).ToList();
                var amazonTicket = new List();
                foreach (var item2 in mrwTicket)
                {
                    amazonTicket.Add(new AmazonTicket()
                    {
                        Order_id = item2.Referencia,
                        Ship_date = item2.Fecha.ToString("MM-dd-yyyy"),
                        Carrier_code = "MRW",
                        Tracking_number = item2.N_Envio.Remove(5, 1),
                        Ship_method = "Urgente 19",
                    });
                }
    
                var memoryStream = new MemoryStream();
                memoryStream.SaveAs(amazonTicket, excelType: ExcelType.CSV, configuration: new CsvConfiguration() { Seperator = '\t' });
                memoryStream.Seek(0, SeekOrigin.Begin);
                using var streamRef = new DotNetStreamReference(stream: memoryStream);
    
                await JS.InvokeVoidAsync("downloadFileFromStream", Path.GetFileNameWithoutExtension(efile.Name) + "_amazon.txt", streamRef);
    
                uploadstatus += Environment.NewLine + $"{efile.Name} 转换OK";
    
                }
                catch (Exception e)
                {
                    uploadstatus += Environment.NewLine + $"转换出错 {e.Message}";
                }
                StateHasChanged();
            }
    
    
            protected override async Task OnAfterRenderAsync(bool firstRender)
            {
                if (!firstRender) return;
    
                module = await JS.InvokeAsync("import", "./drag.js");
                wrapper = DotNetObjectReference.Create(this);
                dropInstance = await module.InvokeAsync("init", wrapper, UploadElement, inputFile!.Element);
            }
    
            [JSInvokable]
            public void DropAlert(string msg)
            {
                uploadstatus += Environment.NewLine + $"[!Alert!]: " + msg;
                StateHasChanged();
            }
    
    
            async ValueTask IAsyncDisposable.DisposeAsync()
            {
                if (dropInstance != null)
                {
                    await dropInstance.InvokeVoidAsync("dispose");
                    await dropInstance.DisposeAsync();
                }
    
                if (wrapper != null)
                {
                    wrapper.Dispose();
                }
    
                if (module != null)
                {
                    await module.DisposeAsync();
                }
            }
    
        }
    
    

    运行

    可接受多文件拖放同时转换

    完整代码来的,直接cv应该可以用了.

  • 相关阅读:
    [MAUI 项目实战] 笔记App(二):数据库设计
    Node.js最新版黑马配套笔记
    重装系统以后怎么还原电脑原本的资料
    Web 应用防火墙:Modsecurity 和核心规则集
    Java常用类方法总结
    UDS安全访问之27服务SecurityAccess
    python 模块、原始字符串
    安装升级rancher
    案例:搭建Zabbix监控系统
    【Linux】iptables之防火墙概述及规则匹配+实例(1)
  • 原文地址:https://www.cnblogs.com/densen2014/p/17125416.html