diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..a0ea5b3
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,4 @@
+# Copilot Instructions
+
+## 项目指南
+- 用户偏好:仅修改明确要求的内容,不要做额外改动(如未请求的 ViewModel DI 注册)。
\ No newline at end of file
diff --git a/App.axaml b/App.axaml
new file mode 100644
index 0000000..97a2bd1
--- /dev/null
+++ b/App.axaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/App.axaml.cs b/App.axaml.cs
new file mode 100644
index 0000000..8c1845b
--- /dev/null
+++ b/App.axaml.cs
@@ -0,0 +1,37 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using Avalonia_PC.ViewModels;
+using Avalonia_PC.Views;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Avalonia_PC
+{
+ ///
+ /// Avalonia 应用程序入口类,负责初始化 XAML 资源和设置主窗口。
+ ///
+ public partial class App : Application
+ {
+ ///
+ /// 加载 Avalonia XAML 资源。
+ ///
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ ///
+ /// 框架初始化完成后设置主窗口和数据上下文。
+ ///
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = Program.Services.GetRequiredService();
+ desktop.MainWindow.DataContext = new MainWindowViewModel();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
+}
diff --git a/Assets/avalonia-logo.ico b/Assets/avalonia-logo.ico
new file mode 100644
index 0000000..f7da8bb
Binary files /dev/null and b/Assets/avalonia-logo.ico differ
diff --git a/Authentication/DefaultPcThirdPartyAuthorizationClient.cs b/Authentication/DefaultPcThirdPartyAuthorizationClient.cs
new file mode 100644
index 0000000..0ff5ff4
--- /dev/null
+++ b/Authentication/DefaultPcThirdPartyAuthorizationClient.cs
@@ -0,0 +1,50 @@
+using Avalonia_Services.Services.AuthService;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Avalonia_PC.Authentication
+{
+ ///
+ /// 第三方授权客户端占位实现。接入真实第三方接口时替换此服务即可。
+ ///
+ public sealed class DefaultPcThirdPartyAuthorizationClient : IPcThirdPartyAuthorizationClient
+ {
+ ///
+ /// 验证第三方授权码是否有效。默认实现将 "invalid" 视为授权丢失,其余视为有效。
+ ///
+ /// 第三方授权码。
+ /// 取消令牌。
+ /// 授权检查结果。
+ public Task ValidateAuthorizationCodeAsync(
+ string authorizationCode,
+ CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(authorizationCode) ||
+ string.Equals(authorizationCode, "invalid", StringComparison.OrdinalIgnoreCase))
+ {
+ return Task.FromResult(ThirdPartyAuthCheckResult.AuthorizationLost);
+ }
+
+ return Task.FromResult(ThirdPartyAuthCheckResult.Valid);
+ }
+
+ ///
+ /// 刷新第三方授权。默认实现总是返回 TemporaryFailure,表示暂时无法刷新。
+ ///
+ /// 授权引用标识。
+ /// 取消令牌。
+ /// 授权检查结果。
+ public Task RefreshAuthorizationAsync(
+ string authorizationReference,
+ CancellationToken cancellationToken = default)
+ {
+ if (string.Equals(authorizationReference, "invalid", StringComparison.OrdinalIgnoreCase))
+ {
+ return Task.FromResult(ThirdPartyAuthCheckResult.AuthorizationLost);
+ }
+
+ return Task.FromResult(ThirdPartyAuthCheckResult.TemporaryFailure);
+ }
+ }
+}
diff --git a/Authentication/PcAuthEndpointService.cs b/Authentication/PcAuthEndpointService.cs
new file mode 100644
index 0000000..270b01b
--- /dev/null
+++ b/Authentication/PcAuthEndpointService.cs
@@ -0,0 +1,94 @@
+using Authentication;
+using Avalonia_Common.Core;
+using Avalonia_Services.Core;
+using Avalonia_Services.Services.AuthService;
+using System;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace Avalonia_PC.Authentication
+{
+ ///
+ /// PC 端鉴权端点服务,实现 ,
+ /// 处理授权码登录、Token 刷新和登出操作。
+ ///
+ public sealed class PcAuthEndpointService(PcGlobalTokenService tokenService) : IPcAuthEndpointService
+ {
+ private static readonly JsonSerializerOptions JsonOptions = new()
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ ///
+ public async Task