|
| 1 | +namespace TSystems.LoveOTC.AdminHub; |
| 2 | + |
| 3 | +using System.Collections.Immutable; |
| 4 | +using System.Text; |
| 5 | +using DocumentFormat.OpenXml; |
| 6 | +using DocumentFormat.OpenXml.Packaging; |
| 7 | +using DocumentFormat.OpenXml.Spreadsheet; |
| 8 | +using Entities; |
| 9 | +using Microsoft.AspNetCore.SignalR; |
| 10 | +using Microsoft.EntityFrameworkCore; |
| 11 | + |
| 12 | +internal partial class AdminHub { |
| 13 | + private static DateTime lastExport = DateTime.MinValue; |
| 14 | + |
| 15 | + private static readonly IImmutableList<string> headers = new[] { |
| 16 | + "Order Id", |
| 17 | + "Order Time", |
| 18 | + "Recipient Name", |
| 19 | + "E-Mail", |
| 20 | + "Phone", |
| 21 | + "Address", |
| 22 | + "Product Name", |
| 23 | + "Types", |
| 24 | + "Quantity" |
| 25 | + }.ToImmutableArray(); |
| 26 | + |
| 27 | + /** |
| 28 | + * <remarks> |
| 29 | + * @author Aloento |
| 30 | + * @since 1.2.0 |
| 31 | + * @version 0.1.0 |
| 32 | + * </remarks> |
| 33 | + */ |
| 34 | + public async IAsyncEnumerable<byte[]> ExportOrder() { |
| 35 | + if (DateTime.Now - lastExport < TimeSpan.FromMinutes(3)) |
| 36 | + throw new HubException("The time interval between two exports shall not be less than 3 minutes."); |
| 37 | + |
| 38 | + lastExport = DateTime.Now; |
| 39 | + |
| 40 | + using var stream = new MemoryStream(); |
| 41 | + using var document = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook, true); |
| 42 | + |
| 43 | + var workbookPart = document.AddWorkbookPart(); |
| 44 | + workbookPart.Workbook = new(); |
| 45 | + |
| 46 | + var worksheetPart = workbookPart.AddNewPart<WorksheetPart>(); |
| 47 | + var sheetData = new SheetData(); |
| 48 | + worksheetPart.Worksheet = new(sheetData); |
| 49 | + |
| 50 | + var sheets = workbookPart.Workbook.AppendChild(new Sheets()); |
| 51 | + var sheet = new Sheet { |
| 52 | + Id = workbookPart.GetIdOfPart(worksheetPart), |
| 53 | + SheetId = 1, |
| 54 | + Name = "ProcessingOrder" |
| 55 | + }; |
| 56 | + sheets.Append(sheet); |
| 57 | + |
| 58 | + var headerRow = new Row(); |
| 59 | + _ = sheetData.AppendChild(headerRow); |
| 60 | + headerRow.Append(headers.Select(x => new Cell { |
| 61 | + DataType = CellValues.String, |
| 62 | + CellValue = new(x) |
| 63 | + })); |
| 64 | + |
| 65 | + var userIds = await this.Db.Orders |
| 66 | + .Where(x => x.Status == OrderStatus.Processing) |
| 67 | + .Select(x => x.UserId) |
| 68 | + .Distinct() |
| 69 | + .ToArrayAsync(); |
| 70 | + |
| 71 | + foreach (var userId in userIds) { |
| 72 | + var records = this.Db.OrderCombos |
| 73 | + .Where(x => x.Order.UserId == userId) |
| 74 | + .Where(x => x.Order.Status == OrderStatus.Processing) |
| 75 | + .Include(x => x.Order) |
| 76 | + .ThenInclude(o => o.User) |
| 77 | + .Include(x => x.Combo) |
| 78 | + .ThenInclude(c => c.Product) |
| 79 | + .Include(x => x.Combo) |
| 80 | + .ThenInclude(c => c.Types) |
| 81 | + .ThenInclude(t => t.Variant) |
| 82 | + .AsAsyncEnumerable(); |
| 83 | + |
| 84 | + var first = true; |
| 85 | + await foreach (var record in records) { |
| 86 | + var order = record.Order; |
| 87 | + var user = order.User; |
| 88 | + var combo = record.Combo; |
| 89 | + |
| 90 | + var data = new List<string>(9) { |
| 91 | + record.OrderId.ToString(), |
| 92 | + order.CreateAt.ToString("yyyy-MM-dd HH:mm:ss"), |
| 93 | + user.Name |
| 94 | + }; |
| 95 | + |
| 96 | + if (first) { |
| 97 | + data.AddRange([ |
| 98 | + user.EMail, |
| 99 | + user.Phone, |
| 100 | + user.Address |
| 101 | + ]); |
| 102 | + first = false; |
| 103 | + } else |
| 104 | + data.AddRange([ |
| 105 | + "-", "-", "-" |
| 106 | + ]); |
| 107 | + |
| 108 | + data.Add(combo.Product.Name); |
| 109 | + |
| 110 | + var types = combo.Types.Aggregate( |
| 111 | + new StringBuilder(), |
| 112 | + (prev, curr) => { |
| 113 | + _ = prev.Append(curr.Variant.Name); |
| 114 | + _ = prev.Append(" : "); |
| 115 | + _ = prev.Append(curr.Name); |
| 116 | + _ = prev.Append(" ; "); |
| 117 | + return prev; |
| 118 | + }) |
| 119 | + .ToString(); |
| 120 | + |
| 121 | + data.AddRange([ |
| 122 | + types, |
| 123 | + record.Quantity.ToString() |
| 124 | + ]); |
| 125 | + |
| 126 | + var row = new Row(); |
| 127 | + _ = sheetData.AppendChild(row); |
| 128 | + row.Append(data.Select(x => new Cell { |
| 129 | + DataType = CellValues.String, |
| 130 | + CellValue = new(x) |
| 131 | + })); |
| 132 | + } |
| 133 | + |
| 134 | + var emptyRow = new Row(); |
| 135 | + _ = sheetData.AppendChild(emptyRow); |
| 136 | + } |
| 137 | + |
| 138 | + workbookPart.Workbook.Save(); |
| 139 | + document.Save(); |
| 140 | + stream.Position = 0; |
| 141 | + |
| 142 | + var buffer = new byte[30 * 1024]; |
| 143 | + int bytesRead; |
| 144 | + |
| 145 | + while ((bytesRead = await stream.ReadAsync(buffer)) > 0) |
| 146 | + yield return buffer[..bytesRead]; |
| 147 | + } |
| 148 | +} |
0 commit comments