5

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

 1 year ago
source link: https://www.cnblogs.com/densen2014/p/17125416.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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",""
1980213-20230216080251842-1246346883.png
1980213-20230216080207586-805718608.png

来源

  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

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

<h4>MRW txt 转 Amazon txt</h4>

<PageTitle>MRW txt 转 Amazon txt</PageTitle>

<div @ref="UploadElement" style="padding: 20px; width: 200px; height: 200px; background-color: cornflowerblue; border: 2px dashed #0087F7; border-radius: 5px; ">
    <p>拖放上传文件</p>
    <InputFile OnChange="OnChange" class="form-control" multiple @ref="inputFile" />
</div>

<pre>
<code>
        @uploadstatus
</code>
</pre>

拖放上传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代码

    <script>
        window.downloadFileFromStream = async (fileName, contentStreamReference) => {
            const arrayBuffer = await contentStreamReference.arrayBuffer();
            const blob = new Blob([arrayBuffer]);
            const url = URL.createObjectURL(blob);
            const anchorElement = document.createElement('a');
            anchorElement.href = url;
            anchorElement.download = fileName ?? '';
            anchorElement.click();
            anchorElement.remove();
            URL.revokeObjectURL(url);
        }
    </script>

组件代码Mrw2Amazon.razor.cs

先拉个库MiniExcel

<PackageReference Include="MiniExcel" Version="1.*" />

  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. 另存为目标格式csv
  6. 直接弹出目标文件下载到浏览器
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<Mrw2Amazon>? 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<MrwTicket>(fs, excelType: ExcelType.CSV).ToList();
            var amazonTicket = new List<AmazonTicket>();
            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<IJSObjectReference>("import", "./drag.js");
            wrapper = DotNetObjectReference.Create(this);
            dropInstance = await module.InvokeAsync<IJSObjectReference>("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();
            }
        }

    }

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

1980213-20230216084328850-2142617840.gif

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK