children)
+ {
+ Href = null;
+ Icon = icon;
+ Name = name;
+ Expanded = expanded;
+ Gap = gap;
+ Children = children.AsReadOnly();
+ }
+}
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.cs b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b0c41c03a270f7bb3d12cb517933471ce1c63e2
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.cs
@@ -0,0 +1,5 @@
+namespace WebAdmin.Shared.Resources.Layout;
+
+public class NavMenu
+{
+}
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.en.resx b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.en.resx
new file mode 100644
index 0000000000000000000000000000000000000000..2034ad22c355302c15b7ea1b093d0e301ae4e678
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.en.resx
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Customer
+
+
+ Customer Level
+
+
+ Customer List
+
+
+ Order
+
+
+ Purchase Orders
+
+
+ Process Orders
+
+
+ Payment
+
+
+ Receiving Orders
+
+
+ Paid Orders
+
+
+ Logistics
+
+
+ Logistics Orders
+
+
+ Logistics Services
+
+
+ Logistics Channels
+
+
+ Device
+
+
+ Device List
+
+
+ Device Types
+
+
+ Device Modules
+
+
+ Maintenance Orders
+
+
+ Remote Control
+
+
+ Version
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.zh-Hans.resx b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.zh-Hans.resx
new file mode 100644
index 0000000000000000000000000000000000000000..708114e7447ad6990032554f09da5f4b12f3e412
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/Resources/Layout/NavMenu.zh-Hans.resx
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 会员管理
+
+
+ 会员列表
+
+
+ 会员等级
+
+
+ 订单管理
+
+
+ 采购订单
+
+
+ 加工订单
+
+
+ 支付管理
+
+
+ 收款订单
+
+
+ 付款订单
+
+
+ 物流管理
+
+
+ 物流订单
+
+
+ 物流服务
+
+
+ 物流渠道
+
+
+ 终端管理
+
+
+ 终端列表
+
+
+ 型号列表
+
+
+ 基础模块
+
+
+ 维护订单
+
+
+ 远程控制
+
+
+ 版本管理
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/WebAdmin.Shared.csproj b/src/Web/WebAdmin.Shared/WebAdmin.Shared.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..984f136caf056352e2deb11f405ff375b322cc49
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/WebAdmin.Shared.csproj
@@ -0,0 +1,40 @@
+
+
+
+ false
+ false
+ false
+
+
+
+
+
+
+
+ False
+ 6
+ true
+ false
+ 612;618;1701;1702;8669;1591;1816
+
+
+
+ True
+ 1701;1702;8669;1591
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/_App.razor b/src/Web/WebAdmin.Shared/_App.razor
new file mode 100644
index 0000000000000000000000000000000000000000..6bf8f26b0516a31452ee406e9d353eeb57ba33e0
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/_App.razor
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+ 404 Not found 页面未找到
+
+ 抱歉,该地址没有任何信息.
+
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/_App.razor.cs b/src/Web/WebAdmin.Shared/_App.razor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..551f55fb0add3132fa786cf0cbd654c713b3ee3f
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/_App.razor.cs
@@ -0,0 +1,15 @@
+//namespace WebAdmin.Shared;
+
+//public partial class App
+//{
+
+// public static string PageTitle(string page)
+// {
+// return $"{page} - WebAdmin";
+// }
+
+// public const string MESSAGES_NOTIFICATION_CENTER = "NOTIFICATION_CENTER";
+// public const string MESSAGES_TOP = "TOP";
+// public const string MESSAGES_DIALOG = "DIALOG";
+// public const string MESSAGES_CARD = "CARD";
+//}
\ No newline at end of file
diff --git a/src/Web/WebAdmin.Shared/_Imports.razor b/src/Web/WebAdmin.Shared/_Imports.razor
new file mode 100644
index 0000000000000000000000000000000000000000..17a871160a7bcf34179cafd8ed38199034d74e64
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/_Imports.razor
@@ -0,0 +1,23 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+
+@using WebAdmin.Shared.Infrastructure
+@using WebAdmin.Shared.Components
+@using WebAdmin.Shared.Records
+@using WebAdmin.Shared.Layout
+@using WebAdmin.Shared
+@using WebAdmin.Shared.Configurations
+
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+
+@using Microsoft.Extensions.Logging;
+@using Microsoft.Extensions.Localization
+
+@using Microsoft.FluentUI.AspNetCore.Components
+@using Microsoft.FluentUI.AspNetCore.Components.Extensions
+@using Microsoft.FluentUI.AspNetCore.Components.DesignTokens
+
+@using Microsoft.JSInterop
diff --git a/src/Web/WebAdmin.Shared/wwwroot/css/app.css b/src/Web/WebAdmin.Shared/wwwroot/css/app.css
new file mode 100644
index 0000000000000000000000000000000000000000..1de6cdbeb559abfcaffd94102c6f8bf8551a8ae0
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/wwwroot/css/app.css
@@ -0,0 +1,479 @@
+@import '/_content/Microsoft.FluentUI.AspNetCore.Components/css/reboot.css';
+
+body {
+ height: 100%;
+ overflow: hidden;
+}
+
+.siteheader {
+ border-bottom: calc(var(--stroke-width) * 2px) solid var(--accent-fill-rest);
+ margin-bottom: 0 !important;
+}
+
+ .siteheader .logo {
+ width: 108px;
+ height: 23px;
+ grid-column: 1;
+ }
+
+ .siteheader .search {
+ display: flex;
+ align-items: center;
+ padding-right: 20px;
+ }
+
+ .siteheader .links {
+ padding-right: 10px;
+ display: flex;
+ align-items: center;
+ }
+
+ .siteheader .notifications {
+ display: flex;
+ align-items: center;
+ }
+
+ .siteheader .settings {
+ padding-right: 6px;
+ display: flex;
+ align-items: center;
+ margin-left: 0;
+ margin-right: 10px;
+ }
+
+[dir="rtl"] .siteheader .settings {
+ padding: 0 0 0 6px;
+ margin-left: 10px;
+ margin-right: 0;
+}
+
+[dir="rtl"] .siteheader .search {
+ padding-left: 20px;
+ padding-right: 0;
+}
+
+[dir="rtl"] .siteheader .links {
+ padding-left: 10px;
+}
+
+.search-result-icon {
+ vertical-align: middle;
+}
+
+.body-stack {
+ flex-direction: row;
+}
+
+.footer {
+ display: flex !important;
+ flex-direction: row !important;
+ background: var(--neutral-layer-4);
+ color: var(--neutral-foreground-rest) !important;
+ padding: 10px 10px;
+ margin-top: 0px !important;
+}
+
+ .footer .version a {
+ color: var(--neutral-foreground-rest);
+ text-decoration: none;
+ }
+
+ .footer .version a:focus {
+ outline: 1px dashed;
+ outline-offset: 3px;
+ }
+
+ .footer .version a:hover {
+ text-decoration: underline;
+ }
+
+
+nav.sitenav {
+ background-color: var(--neutral-layer-1);
+ padding: 1.5rem 1rem;
+ height: calc(100dvh - 90px);
+ width: 18rem;
+ overflow-y: auto;
+}
+
+nav h2 {
+ font-size: var(--type-ramp-plus-1-font-size);
+ line-height: var(--type-ramp-plus-1-line-height);
+ padding: 15px 0;
+ margin: 0;
+ pointer-events: none;
+}
+
+nav h3 {
+ font-size: var(--type-ramp-base-font-size);
+ line-height: var(--type-ramp-minus-1-line-height);
+ padding: 10px 0;
+ margin: 0;
+ pointer-events: none;
+}
+
+
+nav fluent-anchor {
+ width: 100%;
+ color: var(--fill-color);
+}
+
+ nav fluent-anchor::part(control) {
+ justify-content: start;
+ background: var(--accent-fill-rest);
+ }
+
+
+.fluent-nav-link.notactive .fluent-nav-text {
+ font-weight: 600 !important;
+}
+
+.content {
+ display: flex;
+ background-color: var(--neutral-layer-1);
+}
+
+article {
+ padding: 1.5rem 1rem;
+ border-right: 1px solid var(--neutral-stroke-divider-rest);
+ margin: 0 0;
+ overflow-x: hidden;
+ transition: all 300ms ease-in-out;
+ width: calc(100% - 18rem);
+}
+
+aside {
+ padding: 1.5rem 1rem;
+ top: 0px;
+ height: 100vh;
+ position: sticky;
+ width: 18rem;
+}
+
+#navmenu-toggle {
+ display: none;
+}
+
+.navmenu-icon {
+ display: none;
+}
+
+#navmenu-toggle:checked > nav {
+ width: 0px;
+}
+
+[dir="rtl"] #navmenu-toggle:checked ~ nav {
+ right: 0px;
+}
+
+#color {
+ margin-right: 10px;
+ margin-left: 0;
+}
+
+[dir="rtl"] #color {
+ margin-left: 10px;
+ margin-right: 0;
+}
+
+
+label {
+ color: var(--neutral-foreground-rest);
+ cursor: pointer;
+}
+
+.shell, .sourceCode {
+ background: var(--neutral-stroke-layer-rest);
+ padding: 7px;
+}
+
+code {
+ background: var(--neutral-stroke-layer-rest);
+}
+
+.demopanel {
+ border: 1px dashed var(--accent-fill-rest);
+ padding: 5px;
+}
+
+.highlighted-row {
+ background-color: var(--neutral-fill-secondary-hover);
+}
+
+kbd {
+ padding: 0.10rem 0.25rem;
+ font-size: 0.875em;
+ color: var(--neutral-foreground-rest);
+ background-color: var(--neutral-fill-secondary-rest);
+ border-radius: 0.25rem;
+ border: 1px solid var(--accent-fill-rest);
+}
+
+#blazor-error-ui {
+ background: lightyellow;
+ bottom: 0;
+ box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
+ display: none;
+ left: 0;
+ padding: 0.6rem 1.25rem 0.7rem 1.25rem;
+ position: fixed;
+ width: 100%;
+ z-index: 1000;
+ margin: 20px 0;
+ color: var(--neutral-foreground-rest);
+}
+
+ #blazor-error-ui .dismiss {
+ cursor: pointer;
+ position: absolute;
+ right: 0.75rem;
+ top: 0.5rem;
+ }
+
+.blazor-error-boundary {
+ border: 1px dashed var(--error);
+ background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0nNDgnIGhlaWdodD0nNDgnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIG92ZXJmbG93PSdoaWRkZW4nIGZpbGw9JyNCQzJGMzInPjxwYXRoIGQ9J00yNCA0YTIwIDIwIDAgMSAwIDAgNDAgMjAgMjAgMCAwIDAgMC00MFptMCA5Yy42OSAwIDEuMjUuNTYgMS4yNSAxLjI1djEyLjVhMS4yNSAxLjI1IDAgMSAxLTIuNSAwdi0xMi41YzAtLjY5LjU2LTEuMjUgMS4yNS0xLjI1Wm0wIDIxYTIgMiAwIDEgMSAwLTQgMiAyIDAgMCAxIDAgNFonPjwvcGF0aD48L3N2Zz4=") no-repeat 1rem/1.8rem;
+ padding: 1rem 1rem 1rem 3.7rem;
+}
+
+ .blazor-error-boundary::before {
+ content: "An error has occurred: "
+ }
+
+.loading-progress {
+ position: relative;
+ display: block;
+ width: 8rem;
+ height: 8rem;
+ margin: 20vh auto 1rem auto;
+}
+
+ .loading-progress circle {
+ fill: none;
+ stroke: var( --neutral-fill-layer-rest);
+ stroke-width: 0.6rem;
+ transform-origin: 50% 50%;
+ transform: rotate(-90deg);
+ }
+
+ .loading-progress circle:last-child {
+ stroke: #1b6ec2;
+ stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
+ transition: stroke-dasharray 0.05s ease-in-out;
+ }
+
+.loading-progress-text {
+ position: absolute;
+ text-align: center;
+ font-weight: bold;
+ inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
+}
+
+ .loading-progress-text:after {
+ content: var(--blazor-load-percentage-text, "Loading");
+ }
+
+@media (max-width: 767px) {
+
+ .siteheader {
+ grid-area: header;
+ grid-template-columns: 150px 1fr;
+ align-items: center;
+ justify-content: flex-start;
+ }
+
+ .siteheader .search {
+ display: none;
+ }
+
+ .siteheader .logo {
+ width: 160px;
+ height: 23px;
+ /*padding: 0 25px;*/
+ }
+
+
+ .body-stack {
+ flex-direction: column !important;
+ }
+
+ nav.sitenav {
+ width: 100%;
+ height: calc(100dvh - 50px);
+ }
+
+ .navmenu {
+ width: 100%;
+ }
+
+ #navmenu-toggle {
+ appearance: none;
+ }
+
+ .navmenu-icon {
+ cursor: pointer;
+ z-index: 10;
+ display: block;
+ position: absolute;
+ top: 15px;
+ left: unset;
+ right: 20px;
+ width: 20px;
+ height: 20px;
+ border: none;
+ }
+
+ [dir="rtl"] .navmenu-icon {
+ left: 20px;
+ right: unset
+ }
+
+ #navmenu-toggle ~ nav {
+ display: none;
+ }
+
+ #navmenu-toggle:checked ~ nav {
+ display: block;
+ }
+
+ #navmenu-toggle ~ article {
+ display: block;
+ }
+
+ #navmenu-toggle:checked ~ article {
+ display: none;
+ }
+
+ .content {
+ flex-direction: column;
+ }
+
+ article {
+ padding-top: 0px;
+ width: 100%;
+ }
+
+ aside {
+ padding: 1em 0.75em;
+ width: 100%;
+ }
+
+ .footer {
+ display: grid;
+ grid-template-columns: 10px auto 10px;
+ }
+
+ .footer .version {
+ grid-column: 2;
+ justify-self: start;
+ }
+
+ .footer .copy {
+ grid-column: 2;
+ grid-row: 2;
+ justify-self: end;
+ }
+
+
+ @media screen and (max-width: 767px) and (orientation: landscape) {
+
+ nav {
+ padding: 25px 40px;
+ }
+
+ nav ul {
+ margin: 0 0;
+ }
+ }
+}
+
+@media (min-width: 768px) and (max-width: 1024px) {
+ fluent-select::part(control) {
+ width: 150px;
+ }
+
+ aside {
+ padding: 1.5em 0.75em 1em 0.75em;
+ width: 12rem;
+ }
+
+ article {
+ padding-top: 0px;
+ width: 100%;
+ }
+}
+
+
+/* Surface Duo specific styling */
+@media (horizontal-viewport-segments: 2) {
+
+ .siteheader {
+ grid-area: header;
+ display: grid;
+ grid-template-columns: 150px calc(env(viewport-segment-width 0 0) - 160px) 1fr;
+ grid-template-rows: 1fr;
+ align-items: center;
+ justify-content: flex-start;
+ padding: 12px 0;
+ background-color: var(--neutral-layer-4);
+ }
+
+ .siteheader a {
+ padding: 0px 15px;
+ color: var(--neutral-foreground-rest);
+ }
+
+ .siteheader .logo {
+ grid-column: 1;
+ width: 108px;
+ height: 23px;
+ /*padding: 0 30px;*/
+ }
+
+ main {
+ display: grid;
+ grid-template-columns: env(viewport-segment-width 0 0) 1fr;
+ grid-template-rows: repeat(0, 1fr);
+ }
+
+ nav {
+ grid-column: 1;
+ width: env(viewport-segment-width 0 0) !important;
+ }
+
+ .content {
+ display: grid;
+ grid-template-columns: auto;
+ }
+
+ aside {
+ grid-area: 2 / 2 / 3 / 3;
+ padding: 1.5em 0.75em 1em 0.75em;
+ margin-inline-start: calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0)); /* hinge width */
+ margin-inline-end: calc(100% - env(viewport-segment-left 1 0));
+ width: auto;
+ }
+
+ article {
+ grid-area: 1 / 2 / 2 / 3;
+ padding-top: 0px;
+ margin-inline-start: calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0)); /* hinge width */
+ margin-inline-end: calc(100% - env(viewport-segment-left 1 0));
+ width: auto;
+ }
+}
+
+
+
+@media (min-width: 800px) {
+ .fluent-dialog-main {
+ --dialog-width: 340px;
+ }
+}
+
+
+@media (max-width: 480px) {
+ .fluent-dialog-main {
+ --dialog-width: 100vw;
+ }
+}
diff --git a/src/Web/WebAdmin.Shared/wwwroot/js/CacheStorageAccessor.js b/src/Web/WebAdmin.Shared/wwwroot/js/CacheStorageAccessor.js
new file mode 100644
index 0000000000000000000000000000000000000000..507beee1a138bad9d4e16be60f705f2903135a43
--- /dev/null
+++ b/src/Web/WebAdmin.Shared/wwwroot/js/CacheStorageAccessor.js
@@ -0,0 +1,91 @@
+async function openCacheStorage() {
+ try {
+ return await window.caches.open("WebAdmin");
+ } catch (err) {
+ return undefined;
+ }
+}
+
+function createRequest(url, method, body = "") {
+ const requestInit = {
+ method: method
+ };
+
+ if (body != "") {
+ requestInit.body = body;
+ }
+
+ const request = new Request(url, requestInit);
+
+ return request;
+}
+
+export async function put(url, method, body = "", responseString) {
+ const CACHING_DURATION = 7 * 24 * 3600;
+
+ const expires = new Date();
+ expires.setSeconds(expires.getSeconds() + CACHING_DURATION);
+
+ const cachedResponseFields = {
+ headers: { 'fluent-cache-expires': expires.toUTCString() },
+ };
+
+ const cache = await openCacheStorage();
+ if (cache != null) {
+
+ const request = createRequest(url, method, body);
+ const response = new Response(responseString, cachedResponseFields);
+
+ await cache.put(request, response);
+ }
+}
+
+export async function get(url, method, body = "") {
+ const cache = await openCacheStorage();
+ if (cache == null) {
+ return "";
+ }
+
+ const request = createRequest(url, method, body);
+ const response = await cache.match(request);
+
+ if (response == null) {
+ return "";
+ } else {
+ const expirationDate = Date.parse(response.headers.get("cache-expires"));
+ const now = new Date();
+ // Check it is not already expired and return from the cache
+ if (expirationDate > now) {
+ const result = await response.text();
+
+ return result;
+ }
+ }
+
+ return "";
+}
+
+export async function remove(url, method, body = "") {
+ const cache = await openCacheStorage();
+
+ if (cache != null) {
+ const request = createRequest(url, method, body);
+ await cache.delete(request);
+ }
+}
+
+export async function removeAll() {
+ const cache = await openCacheStorage();
+
+ if (cache != null) {
+ cache.keys().then(function(names) {
+ for (let name of names)
+ cache.delete(name);
+ });
+ //let requests = await cache.keys();
+
+ //for (let request in requests) {
+ // await cache.delete(request);
+ //}
+ }
+}
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Components/App.razor b/src/Web/WebAdmin/Components/App.razor
new file mode 100644
index 0000000000000000000000000000000000000000..c825426786b8a4bb396e5fd7c99c65093cb74d8e
--- /dev/null
+++ b/src/Web/WebAdmin/Components/App.razor
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Web/WebAdmin/Components/Layout/MainLayout.razor b/src/Web/WebAdmin/Components/Layout/MainLayout.razor
new file mode 100644
index 0000000000000000000000000000000000000000..653dbdd0694b4ba7810180cea3dce7052f8562e7
--- /dev/null
+++ b/src/Web/WebAdmin/Components/Layout/MainLayout.razor
@@ -0,0 +1,26 @@
+@inherits LayoutComponentBase
+
+
+
+ WebAdmin
+
+
+
+
+
+ @Body
+
+
+
+
+ Documentation and demos
+
+ About Blazor
+
+
+
+
+ An unhandled error has occurred.
+
Reload
+
🗙
+
diff --git a/src/Web/WebAdmin/Components/Pages/Error.razor b/src/Web/WebAdmin/Components/Pages/Error.razor
new file mode 100644
index 0000000000000000000000000000000000000000..576cc2d2f4db1df9d16532432880ea6e0bfbc001
--- /dev/null
+++ b/src/Web/WebAdmin/Components/Pages/Error.razor
@@ -0,0 +1,36 @@
+@page "/Error"
+@using System.Diagnostics
+
+Error
+
+Error.
+An error occurred while processing your request.
+
+@if (ShowRequestId)
+{
+
+ Request ID: @RequestId
+
+}
+
+Development Mode
+
+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ The Development environment shouldn't be enabled for deployed applications.
+ It can result in displaying sensitive information from exceptions to end users.
+ For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
+ and restarting the app.
+
+
+@code{
+ [CascadingParameter]
+ private HttpContext? HttpContext { get; set; }
+
+ private string? RequestId { get; set; }
+ private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+
+ protected override void OnInitialized() =>
+ RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
+}
diff --git a/src/Web/WebAdmin/Components/Pages/Home.razor b/src/Web/WebAdmin/Components/Pages/Home.razor
new file mode 100644
index 0000000000000000000000000000000000000000..50caea5c113fb44addbaac92e370f91a67303a6a
--- /dev/null
+++ b/src/Web/WebAdmin/Components/Pages/Home.razor
@@ -0,0 +1,123 @@
+@page "/"
+@inject IStringLocalizer L
+@inject AdminConfiguration AdminConfiguration
+@inject IToastService ToastService
+@inject NavigationManager NavigationManager
+
+@L["PageTitle"] - @AdminConfiguration.PageTitle
+
+Hello, world!
+
+Welcome to new Blazor Web App Admin
+
+
+
+ MessageBar
+
+
+ 当你听到一些人对于精致的概念模型侃侃而谈,请保持清醒。
+
+
+
+ 物换星移 泥牛入海
黑暗好像 一颗巨石 按在胸口
独脚大盗
+ 百万富翁 摸爬滚打
黑暗好像 一颗巨石 按在胸口
+
+
+
+ 可以照亮最黑暗的夜,也可以燃尽一切过往。
+ 在时间的长河里,我们都是匆匆的过客,留下的只有脚印和故事。
+ 一颗心被封存太久,就会生锈,忘记了如何跳动。
+ 命运之轮不停转动,我们不过是其中的一粒尘埃,飘忽不定。
+
+
+
+ 不会苦一辈子,但总有苦的一段时间。
+ 当我们站得太高时,忘记了脚下的路有多远。
+ 每个人的心里都有一座孤岛,时常有潮水上涨,也有退潮时刻。
+
+
+
+ 都有下坡的一天。
+ 当我们把昨天抛在身后,明天的路也会变得更加宽广。
+ 有些事,可以预见未来,但无法阻止发生。
+
+
+
+ 不是一个终点,它在于持续的努力而非偶然的机遇。
+
+
+
+ Toast
+
+
+ ToastService.ShowSuccess("成功确认。"))">
+
+ 显示成功
+
+ ToastService.ShowWarning("警告确认。"))">
+
+ 显示警告
+
+ ToastService.ShowError("错误确认。"))">
+
+ 显示错误
+
+ ToastService.ShowInfo("信息确认。"))">
+
+ 显示信息
+
+ ToastService.ShowProgress("进度确认。"))">
+
+ 显示进度
+
+ ToastService.ShowUpload("上传确认。"))">
+
+ 显示上传
+
+ ToastService.ShowDownload("下载确认。"))">
+
+ 显示下载
+
+ ToastService.ShowEvent("活动确认。"))">
+
+ 展示活动
+
+ ToastService.ShowMention("提及确认。"))">
+
+ 显示提及
+
+ ToastService.ShowCustom("自定义确认。", null, null, null, (new Icons.Regular.Size24.Delete(), Color.Accent)))">
+
+ 显示自定义
+
+
+
+ ToastService.ShowCustom("无图标确认。"))">
+ 无图标
+
+
+ ToastService.ShowSuccess("用 Action 确认成功。", null, "Action", EventCallback.Factory.Create(this, HandleTopAction)))">
+ 有 Action
+
+
+ ToastService.ShowInfo("信息确认自定义设置。"))">
+ 自定义超时
+
+
+ ToastService.ShowSuccess("用大量文字进行成功确认,看看 Toast 写得很大时是什么样子。"))">
+
+ 长时间 成功
+
+
+
+
+
+
+@code {
+
+ private void HandleTopAction(ToastResult result)
+ {
+ Console.WriteLine("Toast clicked");
+ }
+
+}
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Components/Pages/Weather.razor b/src/Web/WebAdmin/Components/Pages/Weather.razor
new file mode 100644
index 0000000000000000000000000000000000000000..d1e493bab53a5bc0552c9b6d6448e515d96284c9
--- /dev/null
+++ b/src/Web/WebAdmin/Components/Pages/Weather.razor
@@ -0,0 +1,65 @@
+@page "/weather"
+@inject IStringLocalizer L
+@inject AdminConfiguration AdminConfiguration
+@attribute [StreamRendering]
+
+@L["PageTitle"] - @AdminConfiguration.PageTitle
+
+Weather
+
+该组件用于显示数据。
+
+
+ DataGrid
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private IQueryable? forecasts;
+
+ protected override async Task OnInitializedAsync()
+ {
+ await OnQueryAsync();
+
+ StateHasChanged();
+ }
+ public async Task OnRefreshAsync()
+ {
+ await OnQueryAsync();
+
+ return true;
+ }
+ private async Task OnQueryAsync()
+ {
+ await Task.Delay(Random.Shared.Next(400, 800));
+
+ var startDate = DateOnly.FromDateTime(DateTime.Now);
+ var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
+ forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
+ {
+ Date = startDate.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = summaries[Random.Shared.Next(summaries.Length)]
+ }).AsQueryable();
+ }
+
+ private class WeatherForecast
+ {
+ public DateOnly Date { get; set; }
+ public int TemperatureC { get; set; }
+ public string? Summary { get; set; }
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+ }
+}
diff --git a/src/Web/WebAdmin/Components/Routes.razor b/src/Web/WebAdmin/Components/Routes.razor
new file mode 100644
index 0000000000000000000000000000000000000000..c00618981e49174924dacedfaa2fbe78b431007f
--- /dev/null
+++ b/src/Web/WebAdmin/Components/Routes.razor
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/Web/WebAdmin/Components/_Imports.razor b/src/Web/WebAdmin/Components/_Imports.razor
new file mode 100644
index 0000000000000000000000000000000000000000..4e386191fc2c77a4f35c1b0154a9a3f1ff2b1693
--- /dev/null
+++ b/src/Web/WebAdmin/Components/_Imports.razor
@@ -0,0 +1,15 @@
+@using System.Net.Http
+@using System.Net.Http.Json
+@using Microsoft.AspNetCore.Components.Forms
+@using Microsoft.AspNetCore.Components.Routing
+@using Microsoft.AspNetCore.Components.Web
+@using Microsoft.Extensions.Localization
+@using static Microsoft.AspNetCore.Components.Web.RenderMode
+@using Microsoft.AspNetCore.Components.Web.Virtualization
+@using Microsoft.FluentUI.AspNetCore.Components
+@using Microsoft.JSInterop
+@using WebAdmin
+@using WebAdmin.Client
+@using WebAdmin.Client.Layout
+@using WebAdmin.Components
+@using WebAdmin.Shared.Configurations
diff --git a/src/Web/WebAdmin/Controllers/CultureController.cs b/src/Web/WebAdmin/Controllers/CultureController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..06644bd1a613fa4bf537fbab47f8f64e7fab9d89
--- /dev/null
+++ b/src/Web/WebAdmin/Controllers/CultureController.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Localization;
+using Microsoft.AspNetCore.Mvc;
+
+[Route("[controller]/[action]")]
+public class CultureController : Controller
+{
+ public IActionResult SetCulture(string culture, string redirectUri)
+ {
+ if (culture != null)
+ {
+ HttpContext.Response.Cookies.Append(
+ CookieRequestCultureProvider.DefaultCookieName,
+ CookieRequestCultureProvider.MakeCookieValue(
+ new RequestCulture(culture, culture)));
+ }
+
+ return LocalRedirect(redirectUri);
+ }
+}
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Program.cs b/src/Web/WebAdmin/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f7b80f6da0099916f70cd6f952c18ac045e0369
--- /dev/null
+++ b/src/Web/WebAdmin/Program.cs
@@ -0,0 +1,67 @@
+using System.Globalization;
+using Microsoft.FluentUI.AspNetCore.Components;
+using WebAdmin.Components;
+using WebAdmin.Shared.Configurations;
+using WebAdmin.Shared.Infrastructure;
+
+var builder = WebApplication.CreateBuilder(args);
+
+var adminUiOptions = new AdminUiOptions();
+
+adminUiOptions.BindConfiguration(builder.Configuration);
+builder.Services.AddSingleton(adminUiOptions);
+builder.Services.AddSingleton(adminUiOptions.Admin);
+builder.Services.AddSingleton(adminUiOptions.Culture);
+builder.Services.AddSingleton(adminUiOptions.Http);
+
+// Add services to the container.
+builder.Services.AddRazorComponents()
+ .AddInteractiveServerComponents()
+ .AddInteractiveWebAssemblyComponents();
+
+builder.Services.AddLocalization(opts => opts.ResourcesPath = ConfigurationConsts.ResourcesPath);
+builder.Services.AddAdminUiServerServices();
+builder.Services.AddFluentUIComponents();
+builder.Services.AddControllers();
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment())
+{
+ app.UseWebAssemblyDebugging();
+}
+else
+{
+ app.UseExceptionHandler("/Error", createScopeForErrors: true);
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+}
+
+app.UseHttpsRedirection();
+app.MapControllers();
+app.UseRequestLocalization(options =>
+{
+ var cultureConfiguration = adminUiOptions.Culture;
+ var supportedCultureCodes =
+ (cultureConfiguration?.Cultures?.Count > 0
+ ? cultureConfiguration.Cultures.Intersect(CultureConfiguration.AvailableCultures)
+ : CultureConfiguration.AvailableCultures).ToArray();
+ if (!supportedCultureCodes.Any())
+ supportedCultureCodes = CultureConfiguration.AvailableCultures;
+ var defaultCultureCode = string.IsNullOrEmpty(cultureConfiguration?.DefaultCulture)
+ ? CultureConfiguration.DefaultRequestCulture
+ : cultureConfiguration?.DefaultCulture;
+ if (!supportedCultureCodes.Contains(defaultCultureCode))
+ defaultCultureCode = supportedCultureCodes.FirstOrDefault();
+
+ options.AddSupportedCultures(supportedCultureCodes)
+ .AddSupportedUICultures(supportedCultureCodes)
+ .SetDefaultCulture(defaultCultureCode!);
+});
+app.UseStaticFiles();
+app.UseAntiforgery();
+app.MapRazorComponents()
+ .AddInteractiveServerRenderMode()
+ .AddInteractiveWebAssemblyRenderMode()
+ .AddAdditionalAssemblies(typeof(WebAdmin.Client._Imports).Assembly);
+app.Run();
diff --git a/src/Web/WebAdmin/Properties/launchSettings.json b/src/Web/WebAdmin/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..8e35d658144e16adf860744dda883c3dc11804f3
--- /dev/null
+++ b/src/Web/WebAdmin/Properties/launchSettings.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "applicationUrl": "https://localhost:7273;http://localhost:5172",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+ }
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.en.resx b/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.en.resx
new file mode 100644
index 0000000000000000000000000000000000000000..585e2a16c913f5c343fab3dec260d6b5dc1336e9
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.en.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Customer List
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.zh-Hans.resx b/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.zh-Hans.resx
new file mode 100644
index 0000000000000000000000000000000000000000..439fcda38cbfaaa70d7642319041db32069a8baf
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/CustomerList.zh-Hans.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 会员列表
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/Home.en.resx b/src/Web/WebAdmin/Resources/Components/Pages/Home.en.resx
new file mode 100644
index 0000000000000000000000000000000000000000..d2a88d150f0a1d5ca3c3e446512de8f2d59230f9
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/Home.en.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Home
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/Home.zh-Hans.resx b/src/Web/WebAdmin/Resources/Components/Pages/Home.zh-Hans.resx
new file mode 100644
index 0000000000000000000000000000000000000000..6aff071cb35e0e98d858ffbebceb973a544655a6
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/Home.zh-Hans.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 首页
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/Weather.en.resx b/src/Web/WebAdmin/Resources/Components/Pages/Weather.en.resx
new file mode 100644
index 0000000000000000000000000000000000000000..ce9675e8de0739018758c0a2cf44731807509157
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/Weather.en.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Weather
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/Resources/Components/Pages/Weather.zh-Hans.resx b/src/Web/WebAdmin/Resources/Components/Pages/Weather.zh-Hans.resx
new file mode 100644
index 0000000000000000000000000000000000000000..f3223f758b89b69c6f4df03e34a49d305dfed023
--- /dev/null
+++ b/src/Web/WebAdmin/Resources/Components/Pages/Weather.zh-Hans.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 天气
+
+
\ No newline at end of file
diff --git a/src/Web/WebAdmin/WebAdmin.csproj b/src/Web/WebAdmin/WebAdmin.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..3c46fc8d39ecf6b3251411e7bfb170c33d2eaed3
--- /dev/null
+++ b/src/Web/WebAdmin/WebAdmin.csproj
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
diff --git a/src/Web/WebAdmin/WebAdmin.xml b/src/Web/WebAdmin/WebAdmin.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5be91c255c32a201399114afebdf1807cda8ed09
--- /dev/null
+++ b/src/Web/WebAdmin/WebAdmin.xml
@@ -0,0 +1,8 @@
+
+
+
+ WebAdmin
+
+
+
+
diff --git a/src/Web/WebAdmin/appsettings.Development.json b/src/Web/WebAdmin/appsettings.Development.json
new file mode 100644
index 0000000000000000000000000000000000000000..01daaa3b7154d27cb2a005600a43a291192a53e7
--- /dev/null
+++ b/src/Web/WebAdmin/appsettings.Development.json
@@ -0,0 +1,49 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+
+ "DetailedErrors": true,
+
+ "AllowedHosts": "*",
+
+ "ConnectionStrings": {
+ "Catalog": "Server=192.168.8.112;Port=5432;Database=dapr_catalog;User Id=dapr;Password=Local@Db;Pooling=true;MaxPoolSize=100;",
+ "Identity": "Server=192.168.8.112;Port=5432;Database=dapr_identity;User Id=dapr;Password=Local@Db;Pooling=true;MaxPoolSize=100;",
+ "Ordering": "Server=192.168.8.112;Port=5432;Database=dapr_ordering;User Id=dapr;Password=Local@Db;Pooling=true;MaxPoolSize=100;"
+ },
+
+ "AdminConfiguration": {
+ "PageTitle": "管理后台",
+ "FaviconUri": "~/favicon.ico",
+ "AdminRedirectUri": "https://localhost:44303/signin-oidc",
+ "IdentityServerBaseUrl": "https://localhost:44310",
+ "AdminCookieName": "IdentityServerAdmin",
+ "AdminCookieExpiresUtcHours": 12,
+ "RequireHttpsMetadata": false,
+ "TokenValidationClaimName": "name",
+ "TokenValidationClaimRole": "role",
+ "ClientId": "web_admin",
+ "ClientSecret": "3E220EE1-C134-4A0C-9ADF-73E303AA9FA8",
+ "OidcResponseType": "code",
+ "Scopes": [
+ "openid",
+ "profile",
+ "email",
+ "roles"
+ ],
+ "AdministrationRole": "Administrator"
+ },
+
+ "CultureConfiguration": {
+ "Cultures": [ "en", "zh-Hans" ],
+ "DefaultCulture": "zh-Hans"
+ },
+
+ "HttpConfiguration": {
+ "BasePath": ""
+ }
+}
diff --git a/src/Web/WebAdmin/appsettings.json b/src/Web/WebAdmin/appsettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..10f68b8c8b4f796baf8ddeee7551b6a52b9437cc
--- /dev/null
+++ b/src/Web/WebAdmin/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Web/WebAdmin/wwwroot/app.css b/src/Web/WebAdmin/wwwroot/app.css
new file mode 100644
index 0000000000000000000000000000000000000000..50016b29019d47bb67d5587dd4743645a5c77505
--- /dev/null
+++ b/src/Web/WebAdmin/wwwroot/app.css
@@ -0,0 +1,177 @@
+@import '/_content/Microsoft.FluentUI.AspNetCore.Components/css/reboot.css';
+
+body {
+ --body-font: "Segoe UI Variable", "Segoe UI", sans-serif;
+ font-family: var(--body-font);
+ font-size: var(--type-ramp-base-font-size);
+ line-height: var(--type-ramp-base-line-height);
+ margin: 0;
+}
+
+.navmenu-icon {
+ display: none;
+}
+
+.main {
+ min-height: calc(100dvh - 86px);
+ color: var(--neutral-foreground-rest);
+ align-items: stretch !important;
+}
+
+.body-content {
+ align-self: stretch;
+ height: unset !important;
+ display: flex;
+}
+
+.content {
+ padding: 0.5rem 1.5rem;
+ align-self: stretch !important;
+ width: 100%;
+}
+
+.manage {
+ width: 100dvw;
+}
+
+footer {
+ background: var(--neutral-layer-4);
+ color: var(--neutral-foreground-rest);
+ align-items: center;
+ padding: 10px 10px;
+}
+
+ footer a {
+ color: var(--neutral-foreground-rest);
+ text-decoration: none;
+ }
+
+ footer a:focus {
+ outline: 1px dashed;
+ outline-offset: 3px;
+ }
+
+ footer a:hover {
+ text-decoration: underline;
+ }
+
+.alert {
+ border: 1px dashed var(--accent-fill-rest);
+ padding: 5px;
+}
+
+
+#blazor-error-ui {
+ background: lightyellow;
+ bottom: 0;
+ box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
+ display: none;
+ left: 0;
+ padding: 0.6rem 1.25rem 0.7rem 1.25rem;
+ position: fixed;
+ width: 100%;
+ z-index: 1000;
+ margin: 20px 0;
+}
+
+ #blazor-error-ui .dismiss {
+ cursor: pointer;
+ position: absolute;
+ right: 0.75rem;
+ top: 0.5rem;
+ }
+
+.blazor-error-boundary {
+ background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
+ padding: 1rem 1rem 1rem 3.7rem;
+ color: white;
+}
+
+ .blazor-error-boundary::before {
+ content: "An error has occurred. "
+ }
+
+.loading-progress {
+ position: relative;
+ display: block;
+ width: 8rem;
+ height: 8rem;
+ margin: 20vh auto 1rem auto;
+}
+
+ .loading-progress circle {
+ fill: none;
+ stroke: #e0e0e0;
+ stroke-width: 0.6rem;
+ transform-origin: 50% 50%;
+ transform: rotate(-90deg);
+ }
+
+ .loading-progress circle:last-child {
+ stroke: #1b6ec2;
+ stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
+ transition: stroke-dasharray 0.05s ease-in-out;
+ }
+
+.loading-progress-text {
+ position: absolute;
+ text-align: center;
+ font-weight: bold;
+ inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
+}
+
+ .loading-progress-text:after {
+ content: var(--blazor-load-percentage-text, "Loading");
+ }
+
+code {
+ color: #c02d76;
+}
+
+@media (max-width: 600px) {
+ .main {
+ flex-direction: column !important;
+ row-gap: 0 !important;
+ }
+
+ nav.sitenav {
+ width: 100%;
+ height: 100%;
+ }
+
+ #main-menu {
+ width: 100% !important;
+ }
+
+ #main-menu > div:first-child:is(.expander) {
+ display: none;
+ }
+
+ .navmenu {
+ width: 100%;
+ }
+
+ #navmenu-toggle {
+ appearance: none;
+ }
+
+ #navmenu-toggle ~ nav {
+ display: none;
+ }
+
+ #navmenu-toggle:checked ~ nav {
+ display: block;
+ }
+
+ .navmenu-icon {
+ cursor: pointer;
+ z-index: 10;
+ display: block;
+ position: absolute;
+ top: 15px;
+ right: 20px;
+ width: 20px;
+ height: 20px;
+ border: none;
+ }
+}
diff --git a/src/Web/WebAdmin/wwwroot/favicon.ico b/src/Web/WebAdmin/wwwroot/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..e189d8e579e552ab2b3c82a949bccbc5ea00f3ed
Binary files /dev/null and b/src/Web/WebAdmin/wwwroot/favicon.ico differ
diff --git a/test/DaprTool.AbstractionsTest/Base/DbDependencySetupFixture.cs b/test/DaprTool.AbstractionsTest/Base/DbDependencySetupFixture.cs
index 6ad1e79bcc7cee0e9040a18c67fc7a2124947b0f..87b212a3905e75b2a0d0c5ce726800d48861218a 100644
--- a/test/DaprTool.AbstractionsTest/Base/DbDependencySetupFixture.cs
+++ b/test/DaprTool.AbstractionsTest/Base/DbDependencySetupFixture.cs
@@ -11,7 +11,7 @@ public class DbDependencySetupFixture : DependencySetupFixture
{
// 注册 业务数据库
ServiceCollection.AddLogging();
- ServiceCollection.AddAppDataConnection(Configuration);
+ ServiceCollection.AddOrderAppDataConnection(Configuration);
}
}
@@ -25,7 +25,7 @@ public class ObserverDependencySetupFixture : DependencySetupFixture
// 注册 MediatR
ServiceCollection.AddLogging();
ServiceCollection.AddAppMediators();
- ServiceCollection.AddAppDataConnection(Configuration);
+ ServiceCollection.AddOrderAppDataConnection(Configuration);
}
}