diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj index e5d9bc37d..2d2f4c99c 100644 --- a/src/Application/Application.csproj +++ b/src/Application/Application.csproj @@ -17,13 +17,13 @@ - - + + - + - + diff --git a/src/Domain/Domain.csproj b/src/Domain/Domain.csproj index b0cc30c1a..16871d85f 100644 --- a/src/Domain/Domain.csproj +++ b/src/Domain/Domain.csproj @@ -11,23 +11,23 @@ - - + + - + - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj index fa9eb79e6..bb9e2047c 100644 --- a/src/Infrastructure/Infrastructure.csproj +++ b/src/Infrastructure/Infrastructure.csproj @@ -8,10 +8,10 @@ default - - - - + + + + diff --git a/src/Server.UI/Components/ReconnectModal.razor b/src/Server.UI/Components/ReconnectModal.razor index b314c23ae..e76556579 100644 --- a/src/Server.UI/Components/ReconnectModal.razor +++ b/src/Server.UI/Components/ReconnectModal.razor @@ -1,287 +1,308 @@ - + + + -
-
- -@code { - -} + \ No newline at end of file diff --git a/src/Server.UI/Components/ReconnectModal.razor.js b/src/Server.UI/Components/ReconnectModal.razor.js deleted file mode 100644 index 916a39930..000000000 --- a/src/Server.UI/Components/ReconnectModal.razor.js +++ /dev/null @@ -1,63 +0,0 @@ -// Set up event handlers -const reconnectModal = document.getElementById("components-reconnect-modal"); -reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged); - -const retryButton = document.getElementById("components-reconnect-button"); -retryButton.addEventListener("click", retry); - -const resumeButton = document.getElementById("components-resume-button"); -resumeButton.addEventListener("click", resume); - -function handleReconnectStateChanged(event) { - if (event.detail.state === "show") { - reconnectModal.showModal(); - } else if (event.detail.state === "hide") { - reconnectModal.close(); - } else if (event.detail.state === "failed") { - document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible); - } else if (event.detail.state === "rejected") { - location.reload(); - } -} - -async function retry() { - document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible); - - try { - // Reconnect will asynchronously return: - // - true to mean success - // - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID) - // - exception to mean we didn't reach the server (this can be sync or async) - const successful = await Blazor.reconnect(); - if (!successful) { - // We have been able to reach the server, but the circuit is no longer available. - // We'll reload the page so the user can continue using the app as quickly as possible. - const resumeSuccessful = await Blazor.resumeCircuit(); - if (!resumeSuccessful) { - location.reload(); - } else { - reconnectModal.close(); - } - } - } catch (err) { - // We got an exception, server is currently unavailable - document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible); - } -} - -async function resume() { - try { - const successful = await Blazor.resumeCircuit(); - if (!successful) { - location.reload(); - } - } catch { - location.reload(); - } -} - -async function retryWhenDocumentBecomesVisible() { - if (document.visibilityState === "visible") { - await retry(); - } -} \ No newline at end of file diff --git a/src/Server.UI/Pages/AI/Chatbot.razor b/src/Server.UI/Pages/AI/Chatbot.razor new file mode 100644 index 000000000..2818e2c5a --- /dev/null +++ b/src/Server.UI/Pages/AI/Chatbot.razor @@ -0,0 +1,397 @@ +@page "/ai/chatbot" + +@using OpenAI +@using OpenAI.Chat +@using Microsoft.Extensions.Configuration + +@inject IConfiguration Configuration + + +Chatbot + + + +
+ @if (!messages.Any()) + { +
+ + Start Conversation + Chat with AI Assistant +
+ } + @foreach (var message in messages) + { +
+
+ @if (message.Role == "user") + { + + @if (!string.IsNullOrEmpty(UserProfile?.ProfilePictureDataUrl ?? "")) + { + + } + else + { + + } + + } + else + { + + + + } +
+
+ @{ + var bubbleClass = $"message-bubble {(message.Role == "user" ? "message-bubble-user" : "message-bubble-assistant")}"; + } + + @message.Content + + @if (message.Role == "assistant") + { +
+ +
+ } +
+
+ } + @if (isLoading) + { +
+
+ + + +
+
+ + + +
+
+ } +
+
+
+ +
+ + + + Send + + +
+
+ + + +@code { + // 定义本地数据模型 + private class ChatMessage + { + public string Role { get; set; } = "user"; + public string Content { get; set; } = string.Empty; + } + + private List messages = new(); + private string userInput = string.Empty; + private bool isLoading = false; + private ElementReference messagesEndRef; + private ChatClient? _chatClient; + private List _conversationHistory = new(); + + [CascadingParameter] + private UserProfile? UserProfile { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + await ScrollToBottomAsync(); + } + + private async Task HandleKeyDown(KeyboardEventArgs e) + { + if (e.Key == "Enter" && e.CtrlKey) + { + await SendAsync(); + } + } + + private void InitializeChatClient() + { + if (_chatClient is not null) return; + + var apiKey = Configuration["AISettings:OpenAIApiKey"]; + if (string.IsNullOrEmpty(apiKey) || apiKey == "your-openai-api-key") + { + throw new InvalidOperationException("OpenAI API Key is missing or invalid in AISettings."); + } + + var modelId = Configuration["AISettings:OpenAIModel"] ?? "gpt-5-nano"; + var client = new OpenAIClient(apiKey); + _chatClient = client.GetChatClient(modelId); + + // 添加系统提示 + _conversationHistory.Add(new SystemChatMessage("You are a helpful AI assistant. Be concise and accurate in your responses.")); + } + + private async Task SendAsync() + { + if (string.IsNullOrWhiteSpace(userInput) || isLoading) + { + return; + } + + var userMessageContent = userInput.Trim(); + userInput = string.Empty; + + messages.Add(new ChatMessage + { + Role = "user", + Content = userMessageContent + }); + + StateHasChanged(); + await ScrollToBottomAsync(); + + isLoading = true; + StateHasChanged(); + + try + { + InitializeChatClient(); + + // 添加用户消息到对话历史 + _conversationHistory.Add(new UserChatMessage(userMessageContent)); + + // 调用 OpenAI API + var response = await _chatClient!.CompleteChatAsync(_conversationHistory); + var assistantResponseText = response.Value.Content[0].Text; + + if (!string.IsNullOrEmpty(assistantResponseText)) + { + // 添加助手回复到对话历史 + _conversationHistory.Add(new AssistantChatMessage(assistantResponseText)); + + messages.Add(new ChatMessage + { + Role = "assistant", + Content = assistantResponseText + }); + } + else + { + throw new Exception("No response received from the API."); + } + } + catch (Exception ex) + { + var errorMessage = $"Error: {ex.Message}"; + messages.Add(new ChatMessage + { + Role = "assistant", + Content = errorMessage + }); + Snackbar.Add(errorMessage, Severity.Error); + } + finally + { + isLoading = false; + StateHasChanged(); + await ScrollToBottomAsync(); + } + } + + private async Task CopyToClipboardAsync(string text) + { + try + { + await JS.InvokeVoidAsync("navigator.clipboard.writeText", text); + Snackbar.Add("Copied to clipboard", Severity.Success); + } + catch (Exception ex) + { + Snackbar.Add($"Copy failed: {ex.Message}", Severity.Error); + } + } + + private async Task ScrollToBottomAsync() + { + try + { + await JS.InvokeVoidAsync("eval", @" + var element = document.querySelector('.chat-messages-container'); + if (element) { + element.scrollTop = element.scrollHeight; + } + "); + } + catch + { + // Ignore JS interop errors during pre-rendering + } + } +} \ No newline at end of file diff --git a/src/Server.UI/Pages/Products/Components/ProductFormDialog.razor b/src/Server.UI/Pages/Products/Components/ProductFormDialog.razor index 5a9f697df..dd5ae57f0 100644 --- a/src/Server.UI/Pages/Products/Components/ProductFormDialog.razor +++ b/src/Server.UI/Pages/Products/Components/ProductFormDialog.razor @@ -15,7 +15,6 @@ - @@ -137,18 +136,14 @@ { if (Model.Pictures != null) { - var parameters = new DialogParameters - { - { x => x.ContentText, $"{L["Are you sure you want to erase this image?"]}" } - }; - var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall, FullWidth = true }; - var dialog = await DialogService.ShowAsync($"{L["Erase imatge"]}", parameters, options); - var state = await dialog.Result; - - if (state is not null && !state.Canceled) - { - Model.Pictures.Remove(picture); - } + await DialogServiceHelper.ShowConfirmationDialogAsync( + $"{L["Erase imatge"]}", + $"{L["Are you sure you want to erase this image?"]}", + async () => + { + Model.Pictures.Remove(picture); + }); + } } diff --git a/src/Server.UI/Server.UI.csproj b/src/Server.UI/Server.UI.csproj index ea5218596..39d8abe42 100644 --- a/src/Server.UI/Server.UI.csproj +++ b/src/Server.UI/Server.UI.csproj @@ -15,15 +15,16 @@ default + - + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Server.UI/Services/Navigation/MenuService.cs b/src/Server.UI/Services/Navigation/MenuService.cs index 2c7273919..4fed68734 100644 --- a/src/Server.UI/Services/Navigation/MenuService.cs +++ b/src/Server.UI/Services/Navigation/MenuService.cs @@ -42,6 +42,13 @@ public class MenuService : IMenuService } }, new() + { + Title = "Chatbot", + Icon = Icons.Material.Filled.ChatBubble, + Href ="/ai/chatbot", + PageStatus = PageStatus.Completed + }, + new() { Title = "Analytics", Roles = new[] { RoleName.Admin, RoleName.Users }, diff --git a/src/Server.UI/Themes/Theme.cs b/src/Server.UI/Themes/Theme.cs index cf0887472..6bd8666cb 100644 --- a/src/Server.UI/Themes/Theme.cs +++ b/src/Server.UI/Themes/Theme.cs @@ -8,209 +8,212 @@ public static MudTheme ApplicationTheme() { PaletteLight = new PaletteLight { - Primary = "#5052ba", - Secondary = "#7D7D7D", - Success = "#0CAD39", - Info = "#4099f3", - Warning = "#f0c42b", - Error = "rgba(244,67,54,1)", + Primary = "#0f172a", // Modern blue, professional and trustworthy + PrimaryContrastText = "#ffffff", + PrimaryDarken = "#020617", + PrimaryLighten = "#1e293b", + Secondary = "#64748b", // Neutral gray, clean and professional + SecondaryContrastText = "#ffffff", + SecondaryLighten = "#475569", + SecondaryDarken = "#94a3b8", + Success = "#10b981", // Fresh green, success + Info = "#0ea5e9", // Info blue, clear + Tertiary = "#8b5cf6", // Purple 500 + TertiaryContrastText = "#ffffff", + TertiaryDarken = "#7c3aed", // Purple 600 + TertiaryLighten = "#a78bfa", // Purple 400 + + Warning = "#f59e0b", // Amber 500 + WarningContrastText = "#92400e", // Amber 800 + WarningDarken = "#d97706", // Amber 600 + WarningLighten = "#fbbf24", // Amber 400 + + Error = "#dc2626", // Clear red, error ErrorContrastText = "#ffffff", - ErrorDarken = "rgb(242,28,13)", - ErrorLighten = "rgb(246,96,85)", - Tertiary = "#20c997", - Black = "#111", - White = "#ffffff", - AppbarBackground = "rgba(245, 245, 245, 0.8)", - AppbarText = "#424242", - Background = "#f5f5f5", - Surface = "#ffffff", + ErrorDarken = "#b91c1c", + ErrorLighten = "#ef4444", + + Black = "#020617", // Deep blue-black, more texture + White = "#ffffff", + AppbarBackground = "#f8fafc", // Very light blue-gray, modern + AppbarText = "#0a0a0a", + Background = "#f8fafc", // Very light blue-gray, modern + Surface = "#ffffff", DrawerBackground = "#ffffff", - TextPrimary = "#2E2E2E", - TextSecondary = "#6c757d", - SecondaryContrastText = "#F5F5F5", - TextDisabled = "#B0B0B0", - ActionDefault = "#80838b", - ActionDisabled = "rgba(128, 131, 139, 0.3)", - ActionDisabledBackground = "rgba(128, 131, 139, 0.12)", - Divider = "#e2e5e8", - DividerLight = "rgba(128, 131, 139, 0.15)", - TableLines = "#eff0f2", - LinesDefault = "#e2e5e8", - LinesInputs = "#e2e5e8", - + TextPrimary = "#0f172a", // Deep blue-gray, modern professional + TextSecondary = "#64748b", // Neutral gray, hierarchy + TextDisabled = "#94a3b8", // Soft gray + ActionDefault = "#262626", + ActionDisabled = "rgba(100, 116, 139, 0.4)", + ActionDisabledBackground = "rgba(100, 116, 139, 0.1)", + Divider = "#e2e8f0", // Elegant divider + DividerLight = "#f1f5f9", + TableLines = "#e2e8f0", // Table lines, elegant + LinesDefault = "#e2e8f0", + LinesInputs = "#cbd5e1", }, PaletteDark = new PaletteDark { - Primary = "#5052ba", - Secondary = "#A5A5A5", - Success = "#0CAD39", - Info = "#4099f3", - Warning = "#f0c42b", - Error = "#e02d48", - ErrorContrastText = "#ffffff", - ErrorDarken = "#e02d48", - ErrorLighten = "#ff3333", - Tertiary = "#20c997", - Black = "#000000", - White = "#ffffff", - Background = "#202124", - Surface = "#303134", - AppbarBackground = "rgba(32, 33, 36, 0.8)", - AppbarText = "rgba(255, 255, 255, 0.7)", - DrawerBackground = "#303134", - TextPrimary = "#DADADA", - TextSecondary = "#A8A8A8", - TextDisabled = "rgba(255, 255, 255, 0.3)", - SecondaryContrastText = "#D5D5D5", - ActionDefault = "#e8eaed", - ActionDisabled = "rgba(255, 255, 255, 0.26)", - ActionDisabledBackground = "rgba(255, 255, 255, 0.12)", - Divider = "#3F4452", - DividerLight = "rgba(255, 255, 255, 0.06)", - TableLines = "rgba(63, 68, 82, 0.6)", - LinesDefault = "#3F4452", - LinesInputs = "rgba(255, 255, 255, 0.3)", + Primary = "#fafafa", // shadcn/ui white primary + PrimaryContrastText = "#020817", + PrimaryDarken = "#e4e4e7", + PrimaryLighten = "#ffffff", + Secondary = "#78716c", // Neutral gray + Success = "#22c55e", // Green for success + Info = "#0ea5e9", // Sky blue for info (shadcn sky-500) + InfoDarken = "#0284c7", // Darker sky blue (shadcn sky-600) + InfoLighten = "#38bdf8", // Lighter sky blue (shadcn sky-400) + + Tertiary = "#6366f1", + TertiaryContrastText = "#fafafa", + TertiaryDarken = "#4f46e5", + TertiaryLighten = "#818cf8", + + Warning = "#f59e0b", // Orange for warning + WarningContrastText = "#fafafa", + WarningDarken = "#d97706", + WarningLighten = "#fbbf24", + + Error = "#dc2626", // Red for error + ErrorContrastText = "#fafafa", + ErrorDarken = "#b91c1c", + ErrorLighten = "#ef4444", + + Black = "#020817", + White = "#fafafa", + Background = "#0c0a09", // shadcn/ui dark background + Surface = "#171717", // Deeper surface color + AppbarBackground = "#0c0a09", + AppbarText = "#fafafa", + DrawerText = "#fafafa", + DrawerBackground = "#0c0a09", + TextPrimary = "#fafafa", // shadcn/ui white text + TextSecondary = "#a1a1aa", // Neutral gray secondary text + TextDisabled = "rgba(161, 161, 170, 0.5)", + ActionDefault = "#e5e5e5", + ActionDisabled = "rgba(161, 161, 170, 0.3)", + ActionDisabledBackground = "rgba(161, 161, 170, 0.1)", + Divider = "rgba(255, 255, 255, 0.1)", // shadcn/ui divider color + DividerLight = "rgba(161, 161, 170, 0.1)", + TableLines = "rgba(255, 255, 255, 0.1)", + LinesDefault = "rgba(255, 255, 255, 0.1)", + LinesInputs = "rgba(161, 161, 170, 0.2)", + DarkContrastText = "#020817", + SecondaryContrastText = "#fafafa", + SecondaryDarken = "#57534e", + SecondaryLighten = "#a8a29e" + }, LayoutProperties = new LayoutProperties { - AppbarHeight = "80px", - DefaultBorderRadius = "6px" + AppbarHeight = "64px", // More modern height + DefaultBorderRadius = "8px", // More modern border radius + DrawerWidthLeft = "280px", // Wider sidebar + DrawerMiniWidthRight = "260px" }, Typography = new Typography { Default = new DefaultTypography { - FontSize = ".8125rem", + FontSize = ".875rem", FontWeight = "400", - LineHeight = "1.4", + LineHeight = "1.43", LetterSpacing = "normal", - FontFamily = ["Public Sans", "Roboto", "Arial", "sans-serif"] + FontFamily = ["Inter var", "Inter", "ui-sans-serif", "system-ui", "-apple-system", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji"] }, H1 = new H1Typography { - FontSize = "2.2rem", - FontWeight = "700", - LineHeight = "2.8", - LetterSpacing = "-.01562em" + FontSize = "2.25rem", + FontWeight = "800", + LineHeight = "2.5rem", + LetterSpacing = "-0.025em" }, H2 = new H2Typography { - FontSize = "2rem", + FontSize = "1.875rem", FontWeight = "600", - LineHeight = "2.5", - LetterSpacing = "-.00833em" + LineHeight = "2.25rem", + LetterSpacing = "-0.025em" }, H3 = new H3Typography { - FontSize = "1.75rem", + FontSize = "1.5rem", FontWeight = "600", - LineHeight = "2.23", - LetterSpacing = "0" + LineHeight = "2rem", + LetterSpacing = "-0.025em" }, H4 = new H4Typography { - FontSize = "1.5rem", - FontWeight = "500", - LineHeight = "2", - LetterSpacing = ".00735em" + FontSize = "1.25rem", + FontWeight = "600", + LineHeight = "1.75rem", + LetterSpacing = "-0.025em" }, H5 = new H5Typography { - FontSize = "1.25rem", - FontWeight = "500", - LineHeight = "1.8", - LetterSpacing = "0" + FontSize = "1.125rem", + FontWeight = "600", + LineHeight = "1.75rem", + LetterSpacing = "-0.025em" }, H6 = new H6Typography { FontSize = "1rem", - FontWeight = "400", - LineHeight = "1.6", - LetterSpacing = ".0075em" + FontWeight = "600", + LineHeight = "1.25rem", + LetterSpacing = "-0.025em" }, Button = new ButtonTypography { - FontSize = ".8125rem", + FontSize = ".875rem", FontWeight = "500", - LineHeight = "1.75", - LetterSpacing = ".02857em", - TextTransform = "uppercase" + LineHeight = "1.75rem", + LetterSpacing = "normal", + TextTransform = "none" }, Subtitle1 = new Subtitle1Typography { FontSize = ".875rem", FontWeight = "400", - LineHeight = "1.5", - LetterSpacing = "normal", - FontFamily = ["Public Sans", "Roboto", "Arial", "sans-serif"] + LineHeight = "1.5rem", + LetterSpacing = ".00938em", }, Subtitle2 = new Subtitle2Typography { - FontSize = ".8125rem", + FontSize = "1rem", FontWeight = "500", - LineHeight = "1.57", + LineHeight = "1.75rem", LetterSpacing = ".00714em" }, Body1 = new Body1Typography { - FontSize = "0.8125rem", + FontSize = ".875rem", FontWeight = "400", - LineHeight = "1.5", + LineHeight = "1.5rem", LetterSpacing = ".00938em" }, Body2 = new Body2Typography { FontSize = ".75rem", - FontWeight = "300", - LineHeight = "1.43", + FontWeight = "400", + LineHeight = "1.25rem", LetterSpacing = ".01071em" }, Caption = new CaptionTypography { - FontSize = "0.625rem", + FontSize = "0.75rem", FontWeight = "400", - LineHeight = "1.5", + LineHeight = "1.5rem", LetterSpacing = ".03333em" }, Overline = new OverlineTypography { - FontSize = "0.625rem", - FontWeight = "300", - LineHeight = "2", - LetterSpacing = ".08333em" - } - }, - Shadows = new Shadow - { - Elevation = new[] - { - "none", - "0 2px 4px -1px rgba(6, 24, 44, 0.2)", - "0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)", - "0 30px 60px rgba(0,0,0,0.12)", - "0 6px 12px -2px rgba(50,50,93,0.25),0 3px 7px -3px rgba(0,0,0,0.3)", - "0 50px 100px -20px rgba(50,50,93,0.25),0 30px 60px -30px rgba(0,0,0,0.3)", - "0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.14),0px 1px 18px 0px rgba(0,0,0,0.12)", - "0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.14),0px 2px 16px 1px rgba(0,0,0,0.12)", - "0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12)", - "0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.14),0px 3px 16px 2px rgba(0,0,0,0.12)", - "0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.14),0px 4px 18px 3px rgba(0,0,0,0.12)", - "0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.14),0px 4px 20px 3px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.14),0px 5px 22px 4px rgba(0,0,0,0.12)", - "0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.14),0px 5px 24px 4px rgba(0,0,0,0.12)", - "0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.14),0px 5px 26px 4px rgba(0,0,0,0.12)", - "0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.14),0px 6px 28px 5px rgba(0,0,0,0.12)", - "0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.14),0px 6px 30px 5px rgba(0,0,0,0.12)", - "0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.14),0px 6px 32px 5px rgba(0,0,0,0.12)", - "0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.14),0px 7px 34px 6px rgba(0,0,0,0.12)", - "0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.14),0px 7px 36px 6px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.14),0px 8px 38px 7px rgba(0,0,0,0.12)", - "0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.14),0px 8px 40px 7px rgba(0,0,0,0.12)", - "0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.14),0px 8px 42px 7px rgba(0,0,0,0.12)", - "0 50px 100px -20px rgba(50, 50, 93, 0.25), 0 30px 60px -30px rgba(0, 0, 0, 0.30)", - "2.8px 2.8px 2.2px rgba(0, 0, 0, 0.02),6.7px 6.7px 5.3px rgba(0, 0, 0, 0.028),12.5px 12.5px 10px rgba(0, 0, 0, 0.035),22.3px 22.3px 17.9px rgba(0, 0, 0, 0.042),41.8px 41.8px 33.4px rgba(0, 0, 0, 0.05),100px 100px 80px rgba(0, 0, 0, 0.07)", - "0px 0px 20px 0px rgba(0, 0, 0, 0.05)" + FontSize = "0.75rem", + FontWeight = "400", + LineHeight = "1.75rem", + LetterSpacing = ".03333em", + TextTransform = "none" } } }; diff --git a/src/Server.UI/appsettings.json b/src/Server.UI/appsettings.json index f6145a520..ffe82fe64 100644 --- a/src/Server.UI/appsettings.json +++ b/src/Server.UI/appsettings.json @@ -8,6 +8,11 @@ //"DBProvider": "postgresql", //"ConnectionString": "Server=127.0.0.1;Database=BlazorDashboardDb;User Id=root;Password=root;Port=5432" }, + "AISettings": { + "GeminiApiKey": "your-gemini-api-key", + "OpenAIApiKey": "your-openai-api-key", + "OpenAIModel": "gpt-5-nano" + }, "Authentication": { "Microsoft": { "ClientId": "***", diff --git a/src/Server.UI/wwwroot/css/app.css b/src/Server.UI/wwwroot/css/app.css index 91ee5c6da..3f85a9804 100644 --- a/src/Server.UI/wwwroot/css/app.css +++ b/src/Server.UI/wwwroot/css/app.css @@ -1,36 +1,45 @@ -.mud-main-content { +html { + font-size: 14px; /* 默认:1rem = 14px */ +} + +.mud-main-content { height: 100%; min-height: 100vh; display: flex; } - -.mud-chip { - font-size: var(--mud-typography-default-size); + +.mud-chip.mud-chip-size-medium { + font-size: var(--mud-typography-default-size) !important; } + .mud-chip.mud-chip-size-small { - font-size: var(--mud-typography-body1-size); + font-size: var(--mud-typography-body2-size) !important; } + +.mud-chip { + font-size: var(--mud-typography-default-size); +} + .mud-tabs { background-color: var(--mud-palette-surface); } -.mud-input-control > .mud-input-control-input-container > .mud-input-label-inputcontrol { - font-size: var(--mud-typography-subtitle1-size); +.mud-input-control-margin-dense .mud-input > input.mud-input-root, +.mud-input-control-margin-dense div.mud-input-slot.mud-input-root { + font-size: 0.90em; } -.mud-input > input.mud-input-root, div.mud-input-slot.mud-input-root { - font-size: var(--mud-typography-default-size) !important; -} -.mud-input > textarea.mud-input-root { + +.mud-input-control > .mud-input-control-input-container > .mud-input-label-inputcontrol { font-size: var(--mud-typography-default-size) !important; } - .mud-simple-table table * tr > td, .mud-simple-table table * tr th { + + +.mud-simple-table table * tr > td, .mud-simple-table table * tr th { font-size: var(--mud-typography-default-size) !important; - } .mud-expand-panel .mud-expand-panel-header { font-size: var(--mud-typography-default-size) !important; - } .mud-button-year { @@ -41,19 +50,10 @@ font-size: var(--mud-typography-default-size) !important; } - -.mud-typography-subtitle2 { - font-size: var(--mud-typography-subtitle2-size); - color: var(--mud-palette-text-secondary); -} -.mud-typography-body1 { - font-size: var(--mud-typography-body1-size); +.mud-table-dense .mud-table-cell { + font-size: var(--mud-typography-body2-size) !important; } -.mud-typography-body2 { - font-size: var(--mud-typography-body2-size); - color: var(--mud-palette-text-secondary); -} .mud-button-outlined-size-small { font-size: var(--mud-typography-body2-size); @@ -61,7 +61,7 @@ .mud-grid.readonly-grid > .mud-grid-item { border-bottom: 1px solid var(--mud-palette-table-lines); - padding-bottom:2px; + padding-bottom: 2px; } .mud-nav-link { @@ -101,14 +101,3 @@ - - -.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::after { - content: "An error has occurred." - } \ No newline at end of file diff --git a/tests/Application.IntegrationTests/Application.IntegrationTests.csproj b/tests/Application.IntegrationTests/Application.IntegrationTests.csproj index 4cc383975..d0eee0467 100644 --- a/tests/Application.IntegrationTests/Application.IntegrationTests.csproj +++ b/tests/Application.IntegrationTests/Application.IntegrationTests.csproj @@ -23,7 +23,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Application.UnitTests/Application.UnitTests.csproj b/tests/Application.UnitTests/Application.UnitTests.csproj index a6a6db845..5e1014c9c 100644 --- a/tests/Application.UnitTests/Application.UnitTests.csproj +++ b/tests/Application.UnitTests/Application.UnitTests.csproj @@ -13,7 +13,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Domain.UnitTests/Domain.UnitTests.csproj b/tests/Domain.UnitTests/Domain.UnitTests.csproj index ed39de0ef..8d1460c0e 100644 --- a/tests/Domain.UnitTests/Domain.UnitTests.csproj +++ b/tests/Domain.UnitTests/Domain.UnitTests.csproj @@ -14,7 +14,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive