diff --git a/Sln.Wcs.UI/App.xaml b/Sln.Wcs.UI/App.xaml new file mode 100644 index 0000000..c040570 --- /dev/null +++ b/Sln.Wcs.UI/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Sln.Wcs.UI/App.xaml.cs b/Sln.Wcs.UI/App.xaml.cs new file mode 100644 index 0000000..12a8d0b --- /dev/null +++ b/Sln.Wcs.UI/App.xaml.cs @@ -0,0 +1,105 @@ +using System.Reflection; +using Com.Ctrip.Framework.Apollo; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using NeoSmart.Caching.Sqlite; +using Sln.Wcs.Repository; +using Sln.Wcs.Serilog; +using ZiggyCreatures.Caching.Fusion; +using ZiggyCreatures.Caching.Fusion.Serialization.NewtonsoftJson; +using System.Windows; +using System.IO; + +namespace Sln.Wcs.UI +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + + public static IServiceProvider ServiceProvider { get; private set; } + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); + + var services = new ServiceCollection(); + + ConfigureServices(services); + + ServiceProvider = services.BuildServiceProvider(); + + ServiceProvider.UseSerilogExtensions(); + var config = ServiceProvider.GetService(); + var log = ServiceProvider.GetService(); + + log.Info($"系统启动成功,日志存放位置:{config["logPath"]}"); + } + + private static void ConfigureServices(IServiceCollection services) + { + var basePath = AppContext.BaseDirectory; + + ApolloConfigureServices(services, ref basePath, out IConfiguration apolloConfiguration); + + Assembly[] assemblies = { + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Common.dll")), + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Cache.dll")), + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Repository.dll")), + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HikRoBotApi.dll")), + //Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HikRoBotSdk.dll")), + }; + + services.Scan(scan => scan.FromAssemblies(assemblies) + .AddClasses() + .AsImplementedInterfaces() + .AsSelf() + .WithTransientLifetime()); + + services.AddSingleton(typeof(SerilogHelper)); + + services.AddSqlSugarSetup(); + + services.AddFusionCache() + .WithSerializer( + new FusionCacheNewtonsoftJsonSerializer() + ) + .WithDistributedCache(new SqliteCache(new SqliteCacheOptions + { + CachePath = apolloConfiguration["cachePath"] + })); + } + + /// + /// Apollo 配置中心 + /// + /// + /// + /// + private static void ApolloConfigureServices(IServiceCollection services, ref string basePath, out IConfiguration apolloConfiguration) + { + + + var localConfiguration = new ConfigurationBuilder() + .SetBasePath(basePath) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .Build(); + + var apolloConfigSection = localConfiguration.GetSection("apollo"); + + services.AddSingleton(localConfiguration); + + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(basePath) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddApollo(apolloConfigSection) + .AddDefault(); + + apolloConfiguration = configurationBuilder.Build(); + + services.Remove(new ServiceDescriptor(typeof(IConfiguration), localConfiguration)); + services.AddSingleton(apolloConfiguration); + } + } + +} diff --git a/Sln.Wcs.UI/AssemblyInfo.cs b/Sln.Wcs.UI/AssemblyInfo.cs new file mode 100644 index 0000000..b0ec827 --- /dev/null +++ b/Sln.Wcs.UI/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Sln.Wcs.UI/Attribute/RegisterAsSingletonAttribute.cs b/Sln.Wcs.UI/Attribute/RegisterAsSingletonAttribute.cs new file mode 100644 index 0000000..67ab3c6 --- /dev/null +++ b/Sln.Wcs.UI/Attribute/RegisterAsSingletonAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sln.Wcs.UI.Attribute +{ + public class RegisterAsSingletonAttribute:System.Attribute + { + } +} diff --git a/Sln.Wcs.UI/Attribute/RegisterAsTransientAttribute.cs b/Sln.Wcs.UI/Attribute/RegisterAsTransientAttribute.cs new file mode 100644 index 0000000..385d689 --- /dev/null +++ b/Sln.Wcs.UI/Attribute/RegisterAsTransientAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sln.Wcs.UI.Attribute +{ + public class RegisterAsTransientAttribute:System.Attribute + { + } +} diff --git a/Sln.Wcs.UI/Attribute/RequirePermissionAttribute.cs b/Sln.Wcs.UI/Attribute/RequirePermissionAttribute.cs new file mode 100644 index 0000000..d443fc2 --- /dev/null +++ b/Sln.Wcs.UI/Attribute/RequirePermissionAttribute.cs @@ -0,0 +1,103 @@ +using Microsoft.Extensions.DependencyInjection; +using Rougamo; +using Rougamo.Context; +using Sln.Wcs.UI.Page.Loading; +using System.Windows; +using System.Windows.Threading; + +#region << 版 本 注 释 >> +/*-------------------------------------------------------------------- +* 版权所有 (c) 2024 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:T14-GEN3-7895 +* 命名空间:SlnMesnac.WPF.Attribute +* 唯一标识:fff40cb6-18aa-47e0-917c-1fa653e6f978 +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2024-12-30 10:19:41 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ +#endregion << 版 本 注 释 >> +namespace Sln.Wcs.UI.Attribute +{ + /// + /// 权限过滤 + /// + public class RequirePermissionAttribute : MoAttribute + { + private LoadingWindow loadingWindow; + private string _permissionName; + + public RequirePermissionAttribute(string permissionName) + { + _permissionName = permissionName; + + + } + public override void OnEntry(MethodContext context) + { + Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); + newWindowThread.SetApartmentState(ApartmentState.STA); // 设置为 STA 模式 + newWindowThread.IsBackground = true; // 设置为后台线程 + newWindowThread.Start(); + + bool hasPermission = CheckPermission(_permissionName); + + if (!hasPermission) + { + // 如果用户没有权限,抛出异常或采取其他措施 + throw new UnauthorizedAccessException("User does not have the required permission."); + } + + base.OnEntry(context); + } + + + public override void OnExit(MethodContext context) + { + Thread.Sleep(200); + if(loadingWindow != null) + { + loadingWindow.Dispatcher.Invoke(new Action(() => + { + loadingWindow.Close(); // 关闭窗口 + })); + } + + + base.OnExit(context); + } + + /// + /// 判断权限 + /// + /// + /// + private bool CheckPermission(string permissionName) + { + return true; + } + + private void ThreadStartingPoint() + { + Dispatcher.CurrentDispatcher.Invoke(new Action(() => + { + loadingWindow = App.ServiceProvider.GetService(); + loadingWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; + loadingWindow.Topmost = true; + loadingWindow.Show(); + })); + + Dispatcher.Run(); + } + } +} diff --git a/Sln.Wcs.UI/FodyWeavers.xml b/Sln.Wcs.UI/FodyWeavers.xml new file mode 100644 index 0000000..a6a2edf --- /dev/null +++ b/Sln.Wcs.UI/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Sln.Wcs.UI/MainWindow.xaml b/Sln.Wcs.UI/MainWindow.xaml new file mode 100644 index 0000000..9e7ab56 --- /dev/null +++ b/Sln.Wcs.UI/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Sln.Wcs.UI/MainWindow.xaml.cs b/Sln.Wcs.UI/MainWindow.xaml.cs new file mode 100644 index 0000000..1fa96a2 --- /dev/null +++ b/Sln.Wcs.UI/MainWindow.xaml.cs @@ -0,0 +1,24 @@ +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Sln.Wcs.UI +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml b/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml new file mode 100644 index 0000000..0eb20da --- /dev/null +++ b/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml.cs b/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml.cs new file mode 100644 index 0000000..b209975 --- /dev/null +++ b/Sln.Wcs.UI/Page/Loading/LoadingWindow.xaml.cs @@ -0,0 +1,26 @@ +using Sln.Wcs.UI.Attribute; +using System; +using System.Windows; +using System.Windows.Threading; + +namespace Sln.Wcs.UI.Page.Loading +{ + /// + /// LoadingWindow.xaml 的交互逻辑 + /// + [RegisterAsTransientAttribute] + public partial class LoadingWindow : Window + { + public LoadingWindow() + { + InitializeComponent(); + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + // 停止 Dispatcher 消息循环 + Dispatcher.BeginInvokeShutdown(DispatcherPriority.Background); + } + } +} diff --git a/Sln.Wcs.UI/Sln.Wcs.UI.csproj b/Sln.Wcs.UI/Sln.Wcs.UI.csproj new file mode 100644 index 0000000..02fdd99 --- /dev/null +++ b/Sln.Wcs.UI/Sln.Wcs.UI.csproj @@ -0,0 +1,42 @@ + + + + WinExe + net8.0-windows + enable + enable + true + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sln.Wcs.UI/Templates/gif/loading.gif b/Sln.Wcs.UI/Templates/gif/loading.gif new file mode 100644 index 0000000..ba81ff0 Binary files /dev/null and b/Sln.Wcs.UI/Templates/gif/loading.gif differ diff --git a/Sln.Wcs.UI/Templates/icon/Icon.png b/Sln.Wcs.UI/Templates/icon/Icon.png new file mode 100644 index 0000000..1560465 Binary files /dev/null and b/Sln.Wcs.UI/Templates/icon/Icon.png differ diff --git a/Sln.Wcs.UI/Templates/image/background.jpg b/Sln.Wcs.UI/Templates/image/background.jpg new file mode 100644 index 0000000..860c0b0 Binary files /dev/null and b/Sln.Wcs.UI/Templates/image/background.jpg differ diff --git a/Sln.Wcs.UI/Templates/image/login-background.jpg b/Sln.Wcs.UI/Templates/image/login-background.jpg new file mode 100644 index 0000000..96303ad Binary files /dev/null and b/Sln.Wcs.UI/Templates/image/login-background.jpg differ diff --git a/Sln.Wcs.UI/Templates/style/resourceStyle.xaml b/Sln.Wcs.UI/Templates/style/resourceStyle.xaml new file mode 100644 index 0000000..e7155f2 --- /dev/null +++ b/Sln.Wcs.UI/Templates/style/resourceStyle.xaml @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sln.Wcs.UI/ViewModel/Login/LoginViewModel.cs b/Sln.Wcs.UI/ViewModel/Login/LoginViewModel.cs new file mode 100644 index 0000000..c2e9d9b --- /dev/null +++ b/Sln.Wcs.UI/ViewModel/Login/LoginViewModel.cs @@ -0,0 +1,50 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.Extensions.DependencyInjection; +using Sln.Wcs.UI; +using Sln.Wcs.UI.Attribute; +using System; +using System.Windows; + +namespace Sln.Wcs.UI.ViewModel.Login +{ + [RegisterAsSingleton] + public partial class LoginViewModel: ObservableObject + { + [ObservableProperty] + public string systemTitle = string.Empty; + + [ObservableProperty] + public string userName = string.Empty; + + public LoginViewModel() + { + SystemTitle = "系统测试"; + } + + + [RequirePermission("Login")] + public bool Login(string userName,string password) + { + bool res = true; + try + { + //res = _usersBusiness.Verify(userName, password); + if (res) + { + App.Current.Dispatcher.Invoke(() => + { + MainWindow mainWindow = App.ServiceProvider.GetService(); + App.Current.MainWindow = mainWindow; + mainWindow.Show(); + + }); + } + } + catch (Exception ex) + { + MessageBox.Show($"登录失败:{ex.Message}"); + } + return res; + } + } +} diff --git a/Sln.Wcs.UI/appsettings.json b/Sln.Wcs.UI/appsettings.json new file mode 100644 index 0000000..d486625 --- /dev/null +++ b/Sln.Wcs.UI/appsettings.json @@ -0,0 +1,18 @@ +{ + "exclude": [ + "**/bin", + "**/bower_components", + "**/jspm_packages", + "**/node_modules", + "**/obj", + "**/platforms" + ], + "apollo": { + "AppId": "SlnWcs", + "Env": "DEV", + "MetaServer": "http://119.45.202.115:4320", + "ConfigServer": [ + "http://119.45.202.115:4320" + ] + } +} \ No newline at end of file diff --git a/Sln.Wcs.sln b/Sln.Wcs.sln index ff73ae9..3874f83 100644 --- a/Sln.Wcs.sln +++ b/Sln.Wcs.sln @@ -10,17 +10,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.HikRoBotSdk", "Sln. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.HikRoBotApi", "Sln.Wcs.HikRoBotApi\Sln.Wcs.HikRoBotApi.csproj", "{9E3193CA-590C-4965-B2EF-02C2AE252095}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Model", "Sln.Wcs.Model\Sln.Wcs.Model.csproj", "{18437437-F83E-4A3E-9759-8AF313C47D77}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.Model", "Sln.Wcs.Model\Sln.Wcs.Model.csproj", "{18437437-F83E-4A3E-9759-8AF313C47D77}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Plc", "Sln.Wcs.Plc\Sln.Wcs.Plc.csproj", "{ECB2A29C-7A82-83D1-F9FD-5B8C41E55261}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.Plc", "Sln.Wcs.Plc\Sln.Wcs.Plc.csproj", "{ECB2A29C-7A82-83D1-F9FD-5B8C41E55261}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.ElevatorSdk", "SLn.Wcs.ElevatorSdk\Sln.Wcs.ElevatorSdk.csproj", "{504764BF-FD5F-4BE5-80C5-061C2EE9C79B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.ElevatorSdk", "SLn.Wcs.ElevatorSdk\Sln.Wcs.ElevatorSdk.csproj", "{504764BF-FD5F-4BE5-80C5-061C2EE9C79B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.Serilog", "Sln.Wcs.Serilog\Sln.Wcs.Serilog.csproj", "{5EF250AE-58B8-4C39-8F36-A579EA252A5C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Repository", "Sln.Wcs.Repository\Sln.Wcs.Repository.csproj", "{549AF273-88BE-4316-88F8-CAD82BC5F1E7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.Repository", "Sln.Wcs.Repository\Sln.Wcs.Repository.csproj", "{549AF273-88BE-4316-88F8-CAD82BC5F1E7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.Cache", "Sln.Wcs.Cache\Sln.Wcs.Cache.csproj", "{97940311-1DE9-4282-8EE0-0174513BF245}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sln.Wcs.Cache", "Sln.Wcs.Cache\Sln.Wcs.Cache.csproj", "{97940311-1DE9-4282-8EE0-0174513BF245}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sln.Wcs.UI", "Sln.Wcs.UI\Sln.Wcs.UI.csproj", "{03325079-1FCE-4F30-828C-2E5260554961}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -68,6 +70,10 @@ Global {97940311-1DE9-4282-8EE0-0174513BF245}.Debug|Any CPU.Build.0 = Debug|Any CPU {97940311-1DE9-4282-8EE0-0174513BF245}.Release|Any CPU.ActiveCfg = Release|Any CPU {97940311-1DE9-4282-8EE0-0174513BF245}.Release|Any CPU.Build.0 = Release|Any CPU + {03325079-1FCE-4F30-828C-2E5260554961}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03325079-1FCE-4F30-828C-2E5260554961}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03325079-1FCE-4F30-828C-2E5260554961}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03325079-1FCE-4F30-828C-2E5260554961}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE