Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Commit

Permalink
The most significant changes involve the addition of new functionalit…
Browse files Browse the repository at this point in the history
…y to export order data. This is achieved through the creation of new methods and components across multiple files. The `Export.cs` file has been heavily modified to include a new `ExportOrder()` method that exports order data into a byte array. This method also includes checks to ensure that exports are not performed too frequently. A new `AdminOrderExportButton` component has been added to the `TopNavBar.tsx` file, allowing users to export order data. New methods have also been added to the `Get.ts` and `Export.ts` files to support this new functionality.

List of changes:

1. `Export.cs` file has been significantly modified to include new imports, changes to the `AdminHub` class, and a new `ExportOrder()` method. This method exports order data into a byte array and includes checks to ensure that exports are not performed more frequently than every 3 minutes (Export.cs).

2. `TopNavBar.tsx` file has been updated to include a new `AdminOrderExportButton` component, which allows users to export order data (TopNavBar.tsx).

3. `Entity.ts` file has been updated to change the return type of the `Order` and `Comment` methods in the `AdminOrderEntity` class (Entity.ts).

4. `Get.ts` file has been updated to include a new `Export` method in the `AdminOrderGet` class, which is used to export order data (Get.ts).

5. A new `Export.tsx` file has been created, which defines the `AdminOrderExportButton` component. This component uses the `AdminHub.Order.Get.Export(log)` method to export order data when clicked (Export.tsx).

6. A new `Export.ts` file has been created, which defines the `AdminOrderExport` class. This class includes a `Export(plog: Logger)` method, which is used to export order data (Export.ts).
  • Loading branch information
Aloento committed Feb 4, 2024
1 parent 9ee2203 commit 929989b
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 6 deletions.
111 changes: 107 additions & 4 deletions SoarCraft.AwaiShop/AdminHub/Order/Export.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
namespace SoarCraft.AwaiShop.AdminHub;

using System.Collections.Immutable;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Entities;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;

internal partial class AdminHub {
private static readonly DateTime lastExport = DateTime.MinValue;
private static DateTime lastExport = DateTime.MinValue;

private static readonly IImmutableList<string> headers = new[] {
"Order Id",
"Order Time",
"Recipient Name",
"E-Mail",
"Phone",
"Address",
"Product Name",
"Types",
"Quantity"
}.ToImmutableArray();

/**
* <remarks>
* @author Aloento
* @since 1.2.5
* @since 1.2.0
* @version 0.1.0
* </remarks>
*/
public async Task<dynamic> ExportProcessingOrder() {
public async IAsyncEnumerable<byte[]> ExportOrder() {
if (DateTime.Now - lastExport < TimeSpan.FromMinutes(3))
throw new HubException("The time interval between two exports shall not be less than 3 minutes.");

lastExport = DateTime.Now;

using var stream = new MemoryStream();
using var document = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook, true);

Expand All @@ -39,7 +57,92 @@ public async Task<dynamic> ExportProcessingOrder() {

var headerRow = new Row();
sheetData.AppendChild(headerRow);
headerRow.Append(headers.Select(x => new Cell {
DataType = CellValues.String,
CellValue = new(x)
}));

var userIds = await this.Db.Orders
.Where(x => x.Status == OrderStatus.Processing)
.Select(x => x.UserId)
.Distinct()
.ToArrayAsync();

foreach (var userId in userIds) {
var records = this.Db.OrderCombos
.Where(x => x.Order.UserId == userId)
.Where(x => x.Order.Status == OrderStatus.Processing)
.Include(x => x.Order)
.ThenInclude(o => o.User)
.Include(x => x.Combo)
.ThenInclude(c => c.Product)
.Include(x => x.Combo)
.ThenInclude(c => c.Types)
.ThenInclude(t => t.Variant)
.AsAsyncEnumerable();

var first = true;
await foreach (var record in records) {
var order = record.Order;
var user = order.User;
var combo = record.Combo;

var data = new List<string>(9) {
record.OrderId.ToString(),
order.CreateAt.ToString("yyyy-MM-dd HH:mm:ss"),
user.Name
};

if (first) {
data.AddRange([
user.EMail,
user.Phone,
user.Address
]);
first = false;
} else
data.AddRange([
"-", "-", "-"
]);

data.Add(combo.Product.Name);

var types = combo.Types.Aggregate(
new StringBuilder(),
(prev, curr) => {
prev.Append(curr.Variant.Name);
prev.Append(" : ");
prev.Append(curr.Name);
prev.Append(" ; ");
return prev;
})
.ToString();

data.AddRange([
types,
record.Quantity.ToString()
]);

var row = new Row();
sheetData.AppendChild(row);
row.Append(data.Select(x => new Cell {
DataType = CellValues.String,
CellValue = new(x)
}));
}

var emptyRow = new Row();
sheetData.AppendChild(emptyRow);
}

workbookPart.Workbook.Save();
document.Save();
stream.Position = 0;

var buffer = new byte[30 * 1024];
int bytesRead;

return 1;
while ((bytesRead = await stream.ReadAsync(buffer)) > 0)
yield return buffer[..bytesRead];
}
}
2 changes: 2 additions & 0 deletions src/Components/TopNavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AdminSearch } from "~/Components/Search";
import { Dic } from "~/Helpers/Dic";
import { Flex, NavH, NavW } from "~/Helpers/Styles";
import { AdminTopNav } from "~/Pages/Admin/Nav";
import { AdminOrderExportButton } from "~/Pages/Admin/Order/Export";
import { AdminProductAddButton } from "~/Pages/Admin/Product/Add";
import { AvatarMenu } from "./AvatarMenu";
import { ShopCart } from "./ShopCart";
Expand Down Expand Up @@ -64,6 +65,7 @@ export function TopNavBar() {
<div className={style.logoBox}>
<AdminProductAddButton />
<AdminSearch />
<AdminOrderExportButton />

<ShopCart />
<AvatarMenu />
Expand Down
57 changes: 57 additions & 0 deletions src/Pages/Admin/Order/Export.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Button, Toast, ToastTitle } from "@fluentui/react-components";
import { ArrowDownloadRegular } from "@fluentui/react-icons";
import { useRequest } from "ahooks";
import { useRouter } from "~/Components/Router";
import { Logger } from "~/Helpers/Logger";
import { useErrorToast } from "~/Helpers/useToast";
import { AdminHub } from "~/ShopNet/Admin";

const log = new Logger("Admin", "Order", "ExportButton");

/**
* @author Aloento
* @since 1.3.5
* @version 0.1.0
*/
export function AdminOrderExportButton() {
const { Paths } = useRouter();
const path1 = Paths.at(0);
const path2 = Paths.at(1);

const { dispatch, dispatchToast } = useErrorToast(log);

const { run, loading } = useRequest(() => AdminHub.Order.Get.Export(log), {
manual: true,
onError(e, params) {
dispatch({
Message: "Failed Export Order",
Request: params,
Error: e
});
},
onSuccess(url) {
dispatchToast(
<Toast>
<ToastTitle>Order Exported</ToastTitle>
</Toast>,
{ intent: "success" }
);

const a = document.createElement("a");
a.href = url;
a.download = `Order_${new Date().toISOString()}.xlsx`;
a.click();
}
});

return (
path1 === "Admin" && path2 === "Order" &&
<Button
appearance="subtle"
icon={<ArrowDownloadRegular />}
onClick={run}
disabled={loading}>
Export Order
</Button>
)
}
4 changes: 2 additions & 2 deletions src/ShopNet/Admin/Order/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export abstract class AdminOrderEntity extends AdminNet {
Status: string;
CreateAt: Date;
TrackingNumber?: string;
} & IConcurrency) | void> {
} & IConcurrency)> {
this.EnsureLogin();
return this.GetVersionCache(key, "OrderEntity");
}
Expand All @@ -31,7 +31,7 @@ export abstract class AdminOrderEntity extends AdminNet {
Content: string;
UserId?: string;
CreateAt: Date;
} & IConcurrency) | void> {
} & IConcurrency)> {
this.EnsureLogin();
return this.GetVersionCache(key, "CommentEntity");
}
Expand Down
38 changes: 38 additions & 0 deletions src/ShopNet/Admin/Order/Export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Logger } from "~/Helpers/Logger";
import { AdminNet } from "../AdminNet";

/**
* @author Aloento
* @since 1.3.5
* @version 0.1.0
*/
export abstract class AdminOrderExport extends AdminNet {
/**
* @author Aloento
* @since 1.3.5
* @version 0.1.0
*/
public static async Export(plog: Logger): Promise<string> {
this.EnsureLogin();
await this.EnsureConnected();

const slice: Uint8Array[] = [];

return new Promise((resolve, reject) => {
this.Hub.stream<Uint8Array>("ExportOrder").subscribe({
error(err) {
plog.error(err);
reject(err);
},
next(value) {
slice.push(value);
plog.debug("Received Slice", slice.length);
},
complete() {
plog.debug("Received All Slices", slice.length);
resolve(URL.createObjectURL(new Blob(slice)));
},
});
});
}
}
2 changes: 2 additions & 0 deletions src/ShopNet/Admin/Order/Get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ProductGet } from "~/ShopNet/Product/Get";
import { AdminNet } from "../AdminNet";
import { AdminUserEntity } from "../User/Entity";
import { AdminOrderEntity } from "./Entity";
import { AdminOrderExport } from "./Export";

/**
* @author Aloento
Expand Down Expand Up @@ -181,4 +182,5 @@ export abstract class AdminOrderGet extends AdminNet {
}

public static Order = AdminOrderEntity.Order;
public static Export = AdminOrderExport.Export;
}

0 comments on commit 929989b

Please sign in to comment.