abp框架Excel匯出——基於vue

JerryMouseLi發表於2020-07-29

abp框架Excel匯出——基於vue

1.技術棧

1.1 前端採用vue,官方提供

UI套件用的是iview

1.2 後臺是abp——aspnetboilerplate

即abp v1,https://github.com/aspnetboilerplate/aspnetboilerplate。 下載時選擇的是net core 3.1。

2. Excel匯出需求

管理後臺系統,主要以圖表統計形式歸檔資料,使用者經常會有Excel匯出報表的需求。可以以檔案形式儲存,更加地直觀,符合使用習慣。

3. 升級日誌Excel匯出

物聯網中的裝置是核心資產,而維護裝置經常需要一些升級割接操作,因此,升級日誌(升級失敗,升級成功,升級時間)等是使用者比較關心的資料。

4. 技術實現方案

4.1 後臺

4.1.1 EPPlus匯出靜態方法

需要nuget安裝EPPlus.Core庫。運用了委託的方法方便地實現了對匯出表單進行新增標題,填充內容資料,渲染單元格樣式,委託的一大優勢就是方便呼叫,層次感很明顯。該方法如果看得還不是很明白,請耐心繼續往下看。

    public abstract class EPPlusExcelExporterBase : AbpServiceBase
    {
        protected EPPlusExcelExporterBase( )
        {}
        public static byte[] CreateExcelPackage(string fileName, Action<ExcelPackage> creator)
        {
            var excelPackage = new ExcelPackage();
            creator(excelPackage);
            using (var stream = new MemoryStream())
            {
                excelPackage.SaveAs(stream);
                excelPackage.Dispose();
                return stream.ToArray();
            }
        }

        public static void AddHeader(ExcelWorksheet sheet, params string[] headerTexts)
        {
            if (headerTexts.IsNullOrEmpty())
            {
                return;
            }
            for (var i = 0; i < headerTexts.Length; i++)
            {
                AddHeader(sheet, i + 1, headerTexts[i]);
            }
        }

        protected static void AddHeader(ExcelWorksheet sheet, int columnIndex, string headerText)
        {
            sheet.Cells[1, columnIndex].Value = headerText;
            sheet.Cells[1, columnIndex].Style.Font.Bold = true;
        }

        public static void AddObjects<T>(ExcelWorksheet sheet, int startRowIndex, IList<T> items, params Func<T, object>[] propertySelectors)
        {
            if (items.IsNullOrEmpty() || propertySelectors.IsNullOrEmpty())
            {
                return;
            }

            for (var i = 0; i < items.Count; i++)
            {
                for (var j = 0; j < propertySelectors.Length; j++)
                {
                    sheet.Cells[i + startRowIndex, j + 1].Value = propertySelectors[j](items[i]);
                }
            }
        }
    }

4.1.2 生成升級日誌列表

此部分程式碼與主業務相關,因為原本業務與區域許可權有關,簡化起見,故刪除其他無關程式碼,主要就是從資料庫獲取了升級列表,並且按照了升級時間進行了倒序排列。讀者不同的業務可進行不同操作。需要轉義的轉義,聯表的聯表,過濾的過濾,排序的排序。

var dbQuery = from upgradeLog in _fsuUpgradeResultRepository.GetAll();

var UpgradeLogDtoList = await dbQuery
     .OrderByDescending(x => x.Updatetime)
     .ToListAsync();

4.1.3 將升級日誌列表放到Excel匯出靜態方法中去

           var data= EPPlusExcelExporterBase.CreateExcelPackage(
                "UpgradeLog.xlsx",
                excelPackage =>
                {
                    var sheet = excelPackage.Workbook.Worksheets.Add("UpgradeLog");
                    sheet.OutLineApplyStyle = true;

                    EPPlusExcelExporterBase.AddHeader(
                        sheet,
                        "Fsu資產編碼",
                        "升級結果",
                        "是否反饋",
                        "Fsu IP地址",
                        "更新時間"
                        );

                    EPPlusExcelExporterBase.AddObjects(
                        sheet, 2, UpgradeLogDtoList,
                        _ => _.FsuId,
                        _ => _.Result,
                        _ => _.IsReport,
                        _ => _.FsuIp,
                        _ => _.Updatetime
                        );

                    //Formatting cells
                    var UpdatetimeColumn = sheet.Column(5);
                    UpdatetimeColumn.Style.Numberformat.Format = "yyyy-mm-dd-hh:mm:ss";

                    for (var i = 1; i <= 5; i++)
                    {
                        sheet.Column(i).AutoFit();
                    }
                });

委託裡面流程分下:新增報表表頭,新增內容,設定顯示樣式(時間格式),新增樣式(設定單元格自適應內容大小)。
通過CreateExcelPackage方法放回了檔案位元流。

4.1.4 abp框架中前後端分離模式檔案流傳輸

以FileResult形式返回前端傳來的請求。需要注意的是FileResult是 Microsoft.AspNetCore.Mvc.Core中的一個類。

        public async Task<FileResult> GetUpgradeReport()
        {
 var dbQuery = from upgradeLog in _fsuUpgradeResultRepository.GetAll();

            var UpgradeLogDtoList = await dbQuery
                 .OrderByDescending(x => x.Updatetime)
                 .ToListAsync();

            foreach (var item in UpgradeLogDtoList)
            {
                ConvertDto(item);//對升級結果,是否上報鐵塔平臺進行解析
            }

           var data= EPPlusExcelExporterBase.CreateExcelPackage(
                "UpgradeLog.xlsx",
                excelPackage =>
                {
                    var sheet = excelPackage.Workbook.Worksheets.Add("UpgradeLog");
                    sheet.OutLineApplyStyle = true;

                    EPPlusExcelExporterBase.AddHeader(
                        sheet,
                        "Fsu資產編碼",
                        "升級結果",
                        "是否反饋",
                        "Fsu IP地址",
                        "更新時間"
                        );

                    EPPlusExcelExporterBase.AddObjects(
                        sheet, 2, UpgradeLogDtoList,
                        _ => _.FsuId,
                        _ => _.Result,
                        _ => _.IsReport,
                        _ => _.FsuIp,
                        _ => _.Updatetime
                        );

                    //Formatting cells
                    var UpdatetimeColumn = sheet.Column(5);
                    UpdatetimeColumn.Style.Numberformat.Format = "yyyy-mm-dd-hh:mm:ss";

                    for (var i = 1; i <= 5; i++)
                    {
                        sheet.Column(i).AutoFit();
                    }
                });

            var fileContentResult = new FileContentResult(data, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
            {
                FileDownloadName = "升級日誌報表.xlsx"
            };

            return fileContentResult;
        }

4.2 前端

4.2.1 vuex的action中新增請求方法

程式碼如下:

    actions = {
        async getUpgradeLogReport(context: ActionContext<UpgradeLogState, any>) {
            let data= await Ajax.get('/api/services/app/Upgrade/GetUpgradeReport',{
                responseType: 'blob',
                headers: {
                  'Content-Type': 'application/json'
                }});
                return data;
        }
    }

告訴後臺以blob形式返回。當然請求方法你也可以直接普通形式封裝,不一定封裝在vuex裡,這裡封裝在vuex的一個好處是有些狀態資料可以儲存在vuex,所有頁面可以共享該資料。

4.2.2 upgradeLog.vue升級頁面

4.2.2.1 增加下載方法

   async  downloadUpgradeLogReport(){
       await this.$store.dispatch({
      type: "upgradelog/getUpgradeLogReport"
    }).then(res => {
      if (res.status == "200") {
        var excelBlob = new Blob([res.data], {
          type: "application/vnd.ms-excel"
        });
        var fileName = "升級日誌報表.xlsx";
        
          var oa = document.createElement("a");
          oa.href = URL.createObjectURL(excelBlob);
          oa.download = fileName;
          document.body.appendChild(oa);
          oa.click();
        
      }
    });
    }

建立一個blob物件,以建立url方式將此物件下載。

4.2.2.2 點選匯出報表按鈕呼叫下載方法

 <Button @click="downloadUpgradeLogReport()">匯出升級日誌報表</Button>

5. 最終效果

5.1 點選按鈕

5.2 報表展示

6.小結

  • 筆者下載使用過多個開源方案匯出Excel,此種方式方法比較輕量,使用比較簡潔;
  • 在abp中返回Excel的形式需要思考,因為如果無法繼承ControllerBase,就無法使用ActionResult這種萬能返回形式(C#中只能繼承一個基類,可以繼承多個介面);
  • vue中ajax接收Excel返回資料時需要注意設定返回型別為Blob,否則將會下載不成功;
  • 這裡Excel匯出是借鑑了Abp Zero 8.1的思路,他是類以瞬時模式注入容器,我是寫成了靜態方法。但是Abp Zero Excel匯出的思路大有不同,首先是生成檔案在Cache裡,然後返回檔案GUID(Token),使用者再拿著GUID(Token)通過fileController從cache匯出需要下載的檔案。快取有效期1分鐘,目的是為了防止有人拿到連結攻擊,不停下載。

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。
本文連結:https://www.cnblogs.com/JerryMouseLi/p/13399027.html

相關文章