GKTGD 工业监控系统设计文档
项目名称 : GKTGD 工业监控系统
架构模式 : MVVM + 模块化架构
技术栈 : WPF + .NET 8.0
创建日期 : 2026-05-06
版本: 1.0
1. 项目概述
1.1 项目目标
开发一个基于WPF MVVM架构的工业自动化监控系统,支持设备控制、机器视觉、数据监测、实时曲线、工艺配方、数据报表、用户管理、系统设置等核心功能模块。
1.2 技术架构
- UI框架: WPF (Windows Presentation Foundation)
- 架构模式: MVVM (Model-View-ViewModel)
- 开发环境: .NET 8.0-windows
- 图表库: LiveCharts.Wpf 0.9.7 + ScottPlot(双图表库策略)
- 数据库: SQLite / MySQL
- 通讯协议: Modbus, 西门子S7, 倍福ADS, Ethernet
- 视觉库: Halcon, VM, OpenCV
1.3 设计原则
- 模块化: 每个功能模块独立封装,便于维护和扩展
- 可配置: 通过配置文件动态启用/禁用功能模块
- 可复用: 通讯、视觉、数据库功能封装为独立类库
- 用户权限: 基于角色的权限管理系统,三层权限控制策略
- UI一致性: 参考现有WPF项目的UI设计风格和控件
- 双图表库策略: LiveCharts.Wpf + ScottPlot,根据应用场景选择最优图表方案
1.4 双图表库策略说明
本项目采用LiveCharts.Wpf和ScottPlot双图表库策略,充分发挥各自优势:
1.4.1 LiveCharts.Wpf 应用场景
优势 : 实时数据绑定友好,动画流畅,仪表盘风格
适用模块:
- 实时曲线模块: 实时数据监控、趋势显示、状态变化
- 数据监测模块: 实时仪表盘、设备状态显示、KPI指标监控
- 设备控制模块: 设备状态可视化、运行参数实时显示
技术特点:
csharp
// LiveCharts.Wpf 实时数据更新示例
public class RealtimeChartViewModel : ViewModelBase
{
public ChartValues<double> Values { get; set; }
public RealtimeChartViewModel()
{
Values = new ChartValues<double>();
// 定时器实时更新数据
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += (s, e) =>
{
Values.Add(GetLatestValue());
if (Values.Count > 100) Values.RemoveAt(0); // 保持数据量
};
timer.Start();
}
}
1.4.2 ScottPlot 应用场景
优势 : 科学绘图能力强,性能优秀,适合大数据量和精确分析
适用模块:
- 机器视觉模块: 图像处理结果显示、像素值分析、边缘检测可视化
- 数据报表模块: 统计分析图表、生产趋势分析、质量分布图
- 工艺配方模块: 配方曲线对比、工艺参数优化分析
技术特点:
csharp
// ScottPlot 精确数据绘图示例
public class AnalysisChartViewModel : ViewModelBase
{
public WpfPlot PlotControl { get; set; }
public void LoadAnalysisData(double[] xData, double[] yData)
{
PlotControl.Plot.Clear();
PlotControl.Plot.AddScatter(xData, yData, label="测量数据");
PlotControl.Plot.AddSignal(yData, label="趋势线");
PlotControl.Plot.Title("数据分析图表");
PlotControl.Plot.XLabel("时间");
PlotControl.Plot.YLabel("数值");
PlotControl.Plot.Legend();
PlotControl.Render();
}
}
1.4.3 双图表库协同工作
模块间数据共享:
csharp
public class DataSharingService
{
// 实时监控使用 LiveCharts.Wpf
public void UpdateRealtimeChart(double value)
{
var liveChartModel = _serviceProvider.GetRequiredService<RealtimeChartViewModel>();
liveChartModel.Values.Add(value);
}
// 分析报告使用 ScottPlot
public void GenerateAnalysisChart(double[] historicalData)
{
var scottPlotModel = _serviceProvider.GetRequiredService<AnalysisChartViewModel>();
scottPlotModel.LoadAnalysisData(historicalData);
}
}
1.4.4 图表库选择决策树
需求分析
↓
是否需要实时数据绑定和动画?
├─ 是 → LiveCharts.Wpf
└─ 否 ↓
是否处理大量数据点(>1000点)?
├─ 是 → ScottPlot
└─ 否 ↓
是否需要科学绘图(信号处理、统计分析)?
├─ 是 → ScottPlot
└─ 否 → LiveCharts.Wpf
2. 解决方案架构
2.1 项目结构
GKTGD.sln
├── NET8_Comm/ # 通讯类库
├── NET8_Vision/ # 视觉类库
├── NET8_SQLData/ # 数据访问类库
└── GKTGD/ # 主应用程序
2.2 项目依赖关系
NET8_Comm (独立通讯类库)
↑
NET8_Vision (独立视觉类库)
↑
NET8_SQLData (独立数据访问类库)
↑
GKTGD (主应用程序) → 引用 NET8_Comm, NET8_Vision, NET8_SQLData
引用机制: 每个项目根据需求选择性引用功能类库
示例引用:
- GKTGD项目: 引用所有三个类库 (Modbus + ADS + SQLite + Halcon)
- 其他项目: 可只引用需要的类库 (如只使用Ethernet + MySQL)
3. 功能模块设计
3.1 八大功能模块
3.1.1 设备控制模块 (DeviceControl)
- 主页面: DeviceControlMainView
- 子页面 :
- 设备总控页面 (DeviceControlOverviewView)
- 设备1控制页面 (Device1ControlView)
- 设备2控制页面 (Device2ControlView)
- 功能: 设备状态监控、控制指令发送、设备参数配置
3.1.2 机器视觉模块 (MachineVision)
- 主页面: MachineVisionMainView
- 子页面 :
- 视觉任务1页面 (VisionTask1View)
- 视觉任务2页面 (VisionTask2View)
- 功能: 图像采集、缺陷检测、尺寸测量、模式匹配
- 图表库 : ScottPlot (适合图像处理结果显示和精确数据分析)
3.1.3 数据监测模块 (DataMonitoring)
- 主页面: DataMonitoringMainView
- 子页面 :
- 实时数据页面 (RealtimeDataView)
- 历史数据页面 (HistoryDataView)
- 功能: 实时数据采集、数据缓存、历史数据查询、数据导出
- 图表库 : LiveCharts.Wpf (仪表盘风格,实时数据监控,状态显示)
3.1.4 实时曲线模块 (RealtimeChart)
- 主页面: RealtimeChartMainView
- 子页面 :
- 趋势图页面 (TrendChartView)
- 对比图页面 (ComparisonChartView)
- 功能: 实时曲线绘制、历史趋势分析、多曲线对比
- 图表库 : LiveCharts.Wpf (适合实时数据监控,动画流畅,数据绑定友好)
3.1.5 工艺配方模块 (ProcessRecipe)
- 主页面: ProcessRecipeMainView
- 子页面 :
- 配方管理页面 (RecipeManagementView)
- 配方执行页面 (RecipeExecutionView)
- 功能: 配方创建、配方存储、配方执行、配方版本管理
3.1.6 数据报表模块 (DataReport)
- 主页面: DataReportMainView
- 子页面 :
- 生产报表页面 (ProductionReportView)
- 质量报表页面 (QualityReportView)
- 功能: 报表生成、数据统计、报表导出、定时报表
- 图表库 : ScottPlot (适合统计分析图表,科学绘图,性能优秀)
3.1.7 用户管理模块 (UserManagement)
- 主页面: UserManagementMainView
- 子页面 :
- 用户列表页面 (UserListView)
- 角色管理页面 (RoleManagementView)
- 权限设置页面 (PermissionSettingView)
- 功能: 用户增删改查、角色管理、权限分配、密码策略
3.1.8 系统设置模块 (SystemSettings)
- 主页面: SystemSettingsMainView
- 子页面 :
- 通讯设置页面 (CommunicationSettingView)
- 数据库设置页面 (DatabaseSettingView)
- 系统配置页面 (SystemConfigView)
- 功能: 通讯参数配置、数据库连接配置、系统参数配置
3.2 模块导航结构
MainWindow左侧菜单:
GKTGD工业监控系统
├── 设备控制
│ ├── 设备总控
│ ├── 设备1控制
│ └── 设备2控制
├── 机器视觉
│ ├── 视觉任务1
│ └── 视觉任务2
├── 数据监测
│ ├── 实时数据
│ └── 历史数据
├── 实时曲线
│ ├── 趋势图
│ └── 对比图
├── 工艺配方
│ ├── 配方管理
│ └── 配方执行
├── 数据报表
│ ├── 生产报表
│ └── 质量报表
├── 用户管理
│ ├── 用户列表
│ ├── 角色管理
│ └── 权限设置
└── 系统设置
├── 通讯设置
├── 数据库设置
└── 系统配置
4. 独立类库设计
4.1 NET8_Comm 通讯类库
职责: 实现所有工业通讯协议,提供统一的通讯接口
目录结构:
NET8_Comm/
├── Interfaces/ # 通讯接口
│ ├── IModbusService.cs
│ ├── ISiemensS7Service.cs
│ ├── IBeckhoffADSService.cs
│ └── IEthernetService.cs
├── Modbus/ # Modbus实现
│ ├── ModbusSerialService.cs
│ └── ModbusTcpService.cs
├── SiemensS7/ # 西门子S7实现
│ ├── S7TcpService.cs
│ └── S7MpIService.cs
├── BeckhoffADS/ # 倍福ADS实现
│ └── AdsClientService.cs
├── Ethernet/ # Ethernet实现
│ └── TcpClientService.cs
├── Models/ # 通讯相关模型
│ ├── CommunicationResult.cs
│ └── DeviceConnection.cs
└── Configuration/ # 通讯配置
├── CommunicationSettings.cs
└── ModbusSettings.cs
核心接口:
csharp
public interface ICommunicationService
{
bool Connect();
void Disconnect();
bool IsConnected { get; }
Task<T> ReadAsync<T>(string address);
Task<bool> WriteAsync<T>(string address, T value);
event EventHandler<CommunicationEventArgs> DataReceived;
}
特点:
- 完全独立,可单独使用
- 支持多种通讯协议
- 统一的接口设计
- 连接池和错误重试机制
4.2 NET8_Vision 视觉类库
职责: 实现所有机器视觉功能,提供统一的视觉接口
目录结构:
NET8_Vision/
├── Interfaces/ # 视觉接口
│ ├── IHalconService.cs
│ ├── IVMService.cs
│ └── IOpenCVService.cs
├── Halcon/ # Halcon实现
│ ├── HalconDetector.cs
│ ├── HalconMatcher.cs
│ └── HalconCamera.cs
├── VM/ # VM实现
│ ├── VMDetector.cs
│ ├── VMMatcher.cs
│ └── VMCamera.cs
├── OpenCV/ # OpenCV实现
│ ├── OpenCVDetector.cs
│ ├── OpenCVMatcher.cs
│ └── OpenCVCamera.cs
├── Models/ # 视觉相关模型
│ ├── VisionResult.cs
│ └── CameraInfo.cs
└── Configuration/ # 视觉配置
├── VisionSettings.cs
└── CameraSettings.cs
核心接口:
csharp
public interface IVisionService
{
bool InitializeCamera(int cameraIndex);
void ReleaseCamera();
Task<ImageData> CaptureImageAsync();
Task<DetectionResult> DetectDefectsAsync(ImageData image);
Task<MatchResult> MatchPatternAsync(ImageData image, string patternPath);
}
特点:
- 完全独立,可单独使用
- 支持多种视觉库
- 统一的图像处理接口
- 相机管理和图像采集
4.3 NET8_SQLData 数据访问类库
职责: 实现数据库操作,提供统一的数据访问接口
目录结构:
NET8_SQLData/
├── Interfaces/ # 数据接口
│ ├── ISQLiteService.cs
│ ├── IMySQLService.cs
│ ├── IRepository.cs
│ └── IDbContext.cs
├── SQLite/ # SQLite实现
│ ├── SQLiteService.cs
│ ├── SQLiteRepository.cs
│ └── SQLiteContext.cs
├── MySQL/ # MySQL实现
│ ├── MySQLService.cs
│ ├── MySQLRepository.cs
│ └── MySQLContext.cs
├── Models/ # 数据模型
│ ├── BaseEntity.cs
│ └── DbResult.cs
├── Migrations/ # 数据库迁移
│ └── MigrationHistory.cs
└── Configuration/ # 数据库配置
├── DatabaseSettings.cs
└── ConnectionSettings.cs
核心接口:
csharp
public interface IDataService
{
Task<bool> ConnectAsync();
Task DisconnectAsync();
Task<IEnumerable<T>> QueryAsync<T>(string sql, object parameters = null);
Task<bool> ExecuteAsync(string sql, object parameters = null);
Task<int> InsertAsync<T>(T entity);
Task<bool> UpdateAsync<T>(T entity);
Task<bool> DeleteAsync<T>(int id);
}
特点:
- 完全独立,可单独使用
- 支持SQLite和MySQL
- Repository模式实现
- 数据库迁移和版本管理
5. 配置系统设计
5.1 配置文件结构 (appsettings.json)
json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Communication": {
"EnabledProviders": [
"Modbus",
"BeckhoffADS"
],
"Modbus": {
"ConnectionType": "Tcp",
"IpAddress": "192.168.1.100",
"Port": 502,
"SlaveId": 1,
"Enabled": true
},
"BeckhoffADS": {
"AmsNetId": "192.168.1.100.1.1",
"Port": 851,
"LocalAmsNetId": "192.168.1.1.1.1",
"Enabled": true
},
"SiemensS7": {
"IpAddress": "192.168.1.101",
"CpuType": "S7-1200",
"Rack": 0,
"Slot": 1,
"Enabled": false
},
"Ethernet": {
"IpAddress": "192.168.1.102",
"Port": 2000,
"Enabled": false
}
},
"Vision": {
"EnabledProviders": [
"Halcon"
],
"Halcon": {
"LicensePath": "C:/Halcon/license.dat",
"Enabled": true
},
"VM": {
"LicensePath": "C:/VM/License",
"Enabled": false
},
"OpenCV": {
"Enabled": false
}
},
"Database": {
"Provider": "SQLite",
"SQLite": {
"ConnectionString": "Data Source=GKTGD.db",
"Enabled": true
},
"MySQL": {
"ConnectionString": "Server=localhost;Database=gktgd;Uid=root;Pwd=password;",
"Enabled": false
}
},
"Authentication": {
"DefaultAdmin": {
"Username": "admin",
"Password": "123456",
"ForceChangePassword": true
},
"PasswordPolicy": {
"MinLength": 6,
"RequireUppercase": false,
"RequireLowercase": false,
"RequireNumbers": false,
"RequireSpecialChars": false
},
"SessionTimeout": 30
},
"UI": {
"Theme": "Light",
"Language": "zh-CN",
"AutoLogout": true,
"AutoLogoutInterval": 15
}
}
5.2 动态服务注册
在App.xaml.cs中的服务注册:
csharp
public partial class App : Application
{
private ServiceProvider _serviceProvider;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var configuration = LoadConfiguration();
var services = new ServiceCollection();
ConfigureServices(services, configuration);
_serviceProvider = services.BuildServiceProvider();
var loginWindow = _serviceProvider.GetRequiredService<LoginWindow>();
loginWindow.Show();
}
private void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
// 注册核心服务
services.AddSingleton<IConfiguration>(configuration);
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IAuthenticationService, AuthenticationService>();
services.AddSingleton<ILoggingService, LoggingService>();
// 动态注册通讯服务
if (configuration.Communication.Modbus.Enabled)
{
services.AddSingleton<IModbusService, ModbusTcpService>();
}
if (configuration.Communication.BeckhoffADS.Enabled)
{
services.AddSingleton<IBeckhoffADSService, BeckhoffADSService>();
}
// 动态注册视觉服务
if (configuration.Vision.Halcon.Enabled)
{
services.AddSingleton<IHalconService, HalconService>();
}
// 动态注册数据库服务
if (configuration.Database.SQLite.Enabled)
{
services.AddSingleton<IDataService, SQLiteService>();
}
// 注册主窗口和视图模型
services.AddTransient<LoginWindow>();
services.AddTransient<MainWindow>();
services.AddTransient<LoginViewModel>();
services.AddTransient<MainViewModel>();
}
}
6. MVVM架构实现
6.1 MVVM层次结构
Model层: 数据模型和业务逻辑
- 实体类 (Entities)
- 数据访问对象 (DAO)
- 业务逻辑服务
View层: UI界面和用户交互
- XAML文件 (UI定义)
- Code-behind (最小化代码逻辑)
- 数据绑定和命令绑定
ViewModel层: 视图逻辑和数据绑定
- 属性通知 (INotifyPropertyChanged)
- 命令实现 (ICommand)
- 数据转换和验证
6.2 ViewModel基类设计
csharp
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
6.3 数据绑定示例
ViewModel:
csharp
public class DeviceControlViewModel : ViewModelBase
{
private bool _isConnected;
private string _deviceStatus;
private ObservableCollection<DeviceData> _deviceData;
public bool IsConnected
{
get => _isConnected;
set => SetProperty(ref _isConnected, value);
}
public string DeviceStatus
{
get => _deviceStatus;
set => SetProperty(ref _deviceStatus, value);
}
public ObservableCollection<DeviceData> DeviceData
{
get => _deviceData;
set => SetProperty(ref _deviceData, value);
}
public ICommand ConnectCommand { get; }
public ICommand DisconnectCommand { get; }
public DeviceControlViewModel()
{
ConnectCommand = new RelayCommand(ExecuteConnect, CanExecuteConnect);
DisconnectCommand = new RelayCommand(ExecuteDisconnect, CanExecuteDisconnect);
}
private bool CanExecuteConnect(object obj) => !IsConnected;
private bool CanExecuteDisconnect(object obj) => IsConnected;
private void ExecuteConnect(object obj)
{
// 连接逻辑
}
private void ExecuteDisconnect(object obj)
{
// 断开连接逻辑
}
}
View (XAML):
xml
<UserControl x:Class="GKTGD.Modules.DeviceControl.Views.DeviceControlMainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.DataContext>
<local:DeviceControlViewModel />
</UserControl.DataContext>
<Grid>
<StackPanel>
<TextBlock Text="{Binding DeviceStatus}" />
<Button Content="连接" Command="{Binding ConnectCommand}" />
<Button Content="断开" Command="{Binding DisconnectCommand}" />
<DataGrid ItemsSource="{Binding DeviceData}" />
</StackPanel>
</Grid>
</UserControl>
7. 导航系统设计
7.1 导航服务接口
csharp
public interface INavigationService
{
void NavigateTo(string viewName, object parameter = null);
void NavigateTo<T>(object parameter = null) where T : class;
bool CanGoBack { get; }
void GoBack();
event EventHandler<NavigatedEventArgs> Navigated;
}
7.2 导航服务实现
csharp
public class NavigationService : INavigationService
{
private readonly Frame _frame;
private readonly Stack<string> _navigationStack;
public NavigationService(Frame frame)
{
_frame = frame;
_navigationStack = new Stack<string>();
}
public void NavigateTo(string viewName, object parameter = null)
{
var viewType = Type.GetType($"GKTGD.Modules.{viewName}");
if (viewType == null)
throw new ArgumentException($"View {viewName} not found");
var view = Activator.CreateInstance(viewType) as Page;
if (view == null)
throw new ArgumentException($"View {viewName} is not a Page");
_navigationStack.Push(viewName);
_frame.Navigate(view, parameter);
Navigated?.Invoke(this, new NavigatedEventArgs(viewName, parameter));
}
public void NavigateTo<T>(object parameter = null) where T : class
{
NavigateTo(typeof(T).Name, parameter);
}
public bool CanGoBack => _navigationStack.Count > 1;
public void GoBack()
{
if (!CanGoBack) return;
_navigationStack.Pop(); // 移除当前页面
var previousView = _navigationStack.Peek();
// 重新导航到上一页
_frame.GoBack();
}
public event EventHandler<NavigatedEventArgs> Navigated;
}
7.3 MainWindow中的导航实现
参考项目的导航方式(需改为MVVM模式):
xml
<!-- MainWindow.xaml -->
<Frame x:Name="frameContent"
Margin="10,0,10,10"
NavigationUIVisibility="Hidden" />
改为MVVM模式的导航:
xml
<!-- MainWindow.xaml -->
<ContentControl Content="{Binding CurrentView}" />
csharp
// MainViewModel.cs
public class MainViewModel : ViewModelBase
{
private object _currentView;
private readonly INavigationService _navigationService;
public object CurrentView
{
get => _currentView;
set => SetProperty(ref _currentView, value);
}
public MainViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
_navigationService.Navigated += OnNavigated;
}
private void OnNavigated(object sender, NavigatedEventArgs e)
{
// 根据导航的视图名称加载对应的View和ViewModel
var viewType = GetViewType(e.ViewName);
var viewModelType = GetViewModelType(e.ViewName);
var view = Activator.CreateInstance(viewType);
var viewModel = _serviceProvider.GetService(viewModelType);
((FrameworkElement)view).DataContext = viewModel;
CurrentView = view;
}
}
8. 用户认证和权限系统
8.1 用户认证流程
LoginWindow (登录界面)
↓ 用户输入用户名密码
AuthenticationService (认证服务)
↓ 验证成功
MainWindow (主窗口)
↓ 根据用户权限加载模块菜单
↓ 控制功能访问权限
8.2 用户权限模型
csharp
public class UserModel
{
public int UserId { get; set; }
public string Username { get; set; }
public string PasswordHash { get; set; }
public string RealName { get; set; }
public int RoleId { get; set; }
public DateTime? LastLoginTime { get; set; }
public bool IsActive { get; set; }
}
public class RoleModel
{
public int RoleId { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public List<int> PermissionIds { get; set; }
}
public class PermissionModel
{
public int PermissionId { get; set; }
public string PermissionName { get; set; }
public string ModuleName { get; set; } // 模块名称
public string PermissionType { get; set; } // View, Edit, Delete, Export
}
8.3 三层权限控制策略
工业系统的权限控制采用三层防护策略,确保安全性和用户体验的最佳平衡:
8.3.1 第一层:页面级权限(导航级别)
职责: 控制用户能否访问特定的模块和页面
实现示例:
csharp
// MainWindowViewModel.cs - 根据权限过滤菜单
public class MainWindowViewModel : ViewModelBase
{
private readonly IAuthenticationService _authService;
public ObservableCollection<ModuleMenuItem> VisibleModules { get; }
public MainWindowViewModel(IAuthenticationService authService)
{
_authService = authService;
VisibleModules = FilterModulesByPermission();
}
private ObservableCollection<ModuleMenuItem> FilterModulesByPermission()
{
var allModules = GetAllModules();
var authorizedModules = allModules
.Where(m => _authService.HasPermission(m.Id, "View"))
.ToList();
return new ObservableCollection<ModuleMenuItem>(authorizedModules);
}
// 导航时再次验证(双重保护)
public void NavigateToModule(string moduleId)
{
if (!_authService.HasPermission(moduleId, "View"))
{
_messageService.ShowError("您没有访问此模块的权限");
_loggingService.LogWarning($"未授权访问模块: {moduleId}");
return;
}
_navigationService.NavigateTo(moduleId);
}
}
8.3.2 第二层:操作级权限(功能级别)
职责: 控制用户能否执行特定的操作,是核心安全层
实现示例:
csharp
// DeviceControlViewModel.cs - 操作级权限控制
public class DeviceControlViewModel : ViewModelBase
{
private readonly IAuthenticationService _authService;
private readonly IMessageService _messageService;
private readonly ILoggingService _loggingService;
// 命令级别权限控制 - 按钮启用/禁用状态
public ICommand ConnectCommand => new RelayCommand(
ExecuteConnect,
() => _authService.HasPermission("DeviceControl", "Connect")
);
public ICommand DeleteDeviceCommand => new RelayCommand(
ExecuteDeleteDevice,
() => _authService.HasPermission("DeviceControl", "Delete")
);
public ICommand EmergencyStopCommand => new RelayCommand(
ExecuteEmergencyStop,
() => _authService.HasPermission("DeviceControl", "EmergencyStop")
);
// 执行时再次验证(双重保护)
private void ExecuteConnect()
{
if (!_authService.HasPermission("DeviceControl", "Connect"))
{
throw new UnauthorizedAccessException("无连接权限");
}
try
{
_deviceService.Connect();
_loggingService.LogInfo($"用户 {_authService.CurrentUser.Username} 连接设备");
}
catch (Exception ex)
{
_loggingService.LogError("设备连接失败", ex);
_messageService.ShowError("设备连接失败");
}
}
// 关键操作需要三重验证
private void ExecuteEmergencyStop()
{
// 1. 权限验证
if (!_authService.HasPermission("DeviceControl", "EmergencyStop"))
{
_messageService.ShowError("您没有执行紧急停机的权限");
_loggingService.LogCritical($"用户 {_authService.CurrentUser.Username} 尝试未授权紧急停机");
return;
}
// 2. 二次确认
var result = _messageService.Confirm("确认执行紧急停机?此操作不可撤销!", "紧急操作");
if (!result) return;
// 3. 操作日志记录
_loggingService.LogCritical($"用户 {_authService.CurrentUser.Username} 执行紧急停机");
// 4. 执行操作
try
{
_deviceService.EmergencyStop();
_messageService.ShowInfo("紧急停机已执行");
}
catch (Exception ex)
{
_loggingService.LogCritical("紧急停机执行失败", ex);
_messageService.ShowError("紧急停机执行失败");
}
}
}
8.3.3 第三层:UI级权限(可见性级别)
职责: 根据权限动态显示/隐藏UI元素,优化用户体验
XAML实现示例:
xml
<!-- DeviceControlMainView.xaml -->
<UserControl x:Class="GKTGD.Modules.DeviceControl.Views.DeviceControlMainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.DataContext>
<local:DeviceControlViewModel />
</UserControl.DataContext>
<Grid>
<StackPanel>
<!-- 所有用户都能看到的基础信息 -->
<TextBlock Text="设备状态监控" FontSize="18" FontWeight="Bold" />
<TextBlock Text="{Binding DeviceStatus}" />
<!-- 基础操作权限 - 大多数用户都有 -->
<Button Content="连接设备"
Command="{Binding ConnectCommand}"
Width="120" Height="35" Margin="5" />
<Button Content="断开连接"
Command="{Binding DisconnectCommand}"
Width="120" Height="35" Margin="5" />
<!-- 配置权限 - 只有工程师级别才有 -->
<Expander Header="高级配置"
Margin="0,10,0,10"
Visibility="{Binding CanConfigure,
Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Margin="20,5,0,10">
<TextBlock Text="IP地址:" />
<TextBox Text="{Binding DeviceIp}" Width="200" />
<TextBlock Text="端口:" />
<TextBox Text="{Binding DevicePort}" Width="200" />
<Button Content="保存配置"
Command="{Binding SaveConfigCommand}"
Width="120" Height="35" Margin="5" />
</StackPanel>
</Expander>
<!-- 删除权限 - 只有管理员才有 -->
<Button Content="删除设备"
Command="{Binding DeleteCommand}"
Width="120" Height="35" Margin="5"
Background="Red" Foreground="White"
Visibility="{Binding CanDeleteDevice,
Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- 紧急停机权限 - 特殊操作权限 -->
<Button Content="紧急停机"
Command="{Binding EmergencyStopCommand}"
Width="120" Height="35" Margin="5"
Background="DarkRed" Foreground="White" FontWeight="Bold"
Visibility="{Binding CanEmergencyStop,
Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>
</Grid>
</UserControl>
ViewModel中的UI权限属性:
csharp
public class DeviceControlViewModel : ViewModelBase
{
private readonly IAuthenticationService _authService;
// UI级权限属性
public bool CanConfigure => _authService.HasPermission("DeviceControl", "Configure");
public bool CanDeleteDevice => _authService.HasPermission("DeviceControl", "Delete");
public bool CanEmergencyStop => _authService.HasPermission("DeviceControl", "EmergencyStop");
// 当权限变化时通知UI更新
public void RefreshPermissions()
{
OnPropertyChanged(nameof(CanConfigure));
OnPropertyChanged(nameof(CanDeleteDevice));
OnPropertyChanged(nameof(CanEmergencyStop));
}
}
8.4 权限控制架构图
用户登录
↓
┌─────────────────────────────────────┐
│ 第一层:页面级权限 │
│ - 过滤导航菜单 │
│ - 验证页面访问权限 │
│ - 记录页面访问日志 │
└─────────────────────────────────────┘
↓ 有页面访问权限
┌─────────────────────────────────────┐
│ 第二层:操作级权限 │
│ - 按钮启用/禁用控制 │
│ - 命令执行权限验证 │
│ - 关键操作二次确认 │
│ - 操作审计日志 │
└─────────────────────────────────────┘
↓ 有操作权限
┌─────────────────────────────────────┐
│ 第三层:UI级权限 │
│ - UI元素显示/隐藏 │
│ - 优化用户界面体验 │
│ - 避免用户困惑 │
└─────────────────────────────────────┘
8.5 权限矩阵示例
用户角色 | 页面访问 | 设备操作 | 高级配置 | 用户管理 | 系统设置
---------------|---------|---------|---------|---------|----------
超级管理员 | ✓ | ✓ | ✓ | ✓ | ✓
设备工程师 | ✓ | ✓ | ✓ | ✗ | 部分
操作员 | ✓ | 部分 | ✗ | ✗ | ✗
访客 | 部分 | ✗ | ✗ | ✗ | ✗
8.6 权限缓存策略
工业系统需要实时权限检查,但要平衡性能:
csharp
public class CachedAuthenticationService : IAuthenticationService
{
private readonly IAuthenticationService _authService;
private readonly MemoryCache _permissionCache;
private readonly ILogger _logger;
public CachedAuthenticationService(IMemoryCache cache, ILogger logger)
{
_permissionCache = cache;
_logger = logger;
}
public bool HasPermission(string module, string operation)
{
var currentUser = _authService.CurrentUser;
if (currentUser == null) return false;
string cacheKey = $"{currentUser.Id}_{module}_{operation}";
// 缓存5秒,避免频繁查询数据库,同时保证权限变更的实时性
if (!_permissionCache.TryGetValue(cacheKey, out bool hasPermission))
{
hasPermission = _authService.HasPermission(module, operation);
_permissionCache.Set(cacheKey, hasPermission, TimeSpan.FromSeconds(5));
_logger.LogDebug($"权限检查: {currentUser.Username} - {module}.{operation} = {hasPermission}");
}
return hasPermission;
}
// 权限变更时清除缓存
public void ClearPermissionCache(int userId)
{
var keysToRemove = _permissionCache.Where(
kvp => kvp.Key.StartsWith($"{userId}_")
).Select(kvp => kvp.Key).ToList();
foreach (var key in keysToRemove)
{
_permissionCache.Remove(key);
}
}
}
8.7 三层权限控制的优势
1. 安全性 : 三层防护,即使某一层失效,其他层仍能保护系统
2. 用户体验 : 用户只看到有权操作的功能,界面简洁清晰
3. 性能优化 : 通过权限缓存减少数据库查询
4. 审计追踪 : 完整的操作日志记录,满足工业审计要求
5. 灵活配置: 支持动态权限变更,实时生效
9. UI设计和主题系统
9.1 UI设计风格参考
参考项目UI特点:
- 左侧导航菜单,右侧内容区域
- 支持菜单展开/收起动画
- 自定义卡片按钮、进度条等控件
- 浅色/深色主题切换
- 图标+文字的菜单项显示
9.2 主题系统设计
主题颜色定义:
xml
<!-- LightTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="PrimaryBackgroundColor" Color="#EAEAEF"/>
<SolidColorBrush x:Key="SecundaryBackgroundColor" Color="#F2F4F8"/>
<SolidColorBrush x:Key="PrimaryTextColor" Color="#000000"/>
<SolidColorBrush x:Key="SecundaryGreenColor" Color="#12C092"/>
<SolidColorBrush x:Key="SecundaryBlueColor" Color="#3A6AA9"/>
</ResourceDictionary>
<!-- DarkTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="PrimaryBackgroundColor" Color="#121212"/>
<SolidColorBrush x:Key="SecundaryBackgroundColor" Color="#1E1E1E"/>
<SolidColorBrush x:Key="PrimaryTextColor" Color="#FFFFFF"/>
<SolidColorBrush x:Key="SecundaryGreenColor" Color="#12C092"/>
<SolidColorBrush x:Key="SecundaryBlueColor" Color="#3A6AA9"/>
</ResourceDictionary>
9.3 自定义控件复用
从参考项目复用的控件:
- CardButton - 卡片按钮(带进度条)
- CircularProgressBar - 圆形进度条
- DataCard - 数据卡片
- Paginator - 分页器
- Switch - 开关控件
10. 错误处理和日志系统
10.1 错误处理策略
多层级错误处理:
- UI层: 用户输入验证
- ViewModel层: 业务逻辑验证
- Service层: 服务异常处理
- Data层: 数据访问异常处理
10.2 日志系统设计
csharp
public interface ILoggingService
{
void LogDebug(string message);
void LogInfo(string message);
void LogWarning(string message);
void LogError(string message, Exception exception = null);
void LogCritical(string message, Exception exception = null);
}
public class LoggingService : ILoggingService
{
private readonly string _logFilePath;
public LoggingService(IConfiguration configuration)
{
_logFilePath = configuration["Logging:FilePath"] ?? "Logs/GKTGD.log";
}
public void LogInfo(string message)
{
var logMessage = $"[INFO] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}";
File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);
}
// 其他日志方法...
}
11. 开发和部署计划
11.1 开发阶段
阶段1: 基础架构搭建
- 创建解决方案和项目结构
- 实现MVVM基础框架
- 搭建配置系统
- 实现导航服务
阶段2: 独立类库开发
- 开发NET8_Comm通讯类库
- 开发NET8_Vision视觉类库
- 开发NET8_SQLData数据访问类库
阶段3: 核心功能模块
- 实现用户认证和权限管理
- 开发设备控制模块
- 开发机器视觉模块
阶段4: 扩展功能模块
- 开发数据监测模块
- 开发实时曲线模块
- 开发工艺配方模块
- 开发数据报表模块
- 开发系统设置模块
阶段5: UI优化和测试
- UI界面优化
- 功能测试
- 性能优化
- 用户验收测试
11.2 技术风险和应对措施
风险1: 第三方库兼容性
- Halcon、VM视觉库可能存在版本兼容问题
- 应对:在开发初期进行技术验证
风险2: 通讯协议稳定性
- 工业通讯环境复杂,可能存在干扰和断线
- 应对:实现重连机制和错误恢复
风险3: 数据库性能
- 实时数据量可能很大,影响数据库性能
- 应对:实现数据缓存和分页查询
12. 总结
12.1 设计优势
- 高度模块化: 通讯、视觉、数据库功能独立为类库,便于复用和维护
- 灵活配置: 通过配置文件动态启用功能,按需引用类库
- 标准MVVM: 严格遵循MVVM模式,代码结构清晰
- 权限管理: 基于角色的权限控制,保障系统安全
- UI一致性: 参考成熟项目的UI设计,保证用户体验
12.2 扩展性
- 新增通讯协议: 在NET8_Comm中添加新的实现类
- 新增视觉库: 在NET8_Vision中添加新的实现类
- 新增功能模块: 在Modules文件夹中添加新的模块
- UI主题扩展: 在Themes文件夹中添加新的主题文件
- 数据库切换: 通过配置文件切换SQLite/MySQL
12.3 下一步
设计文档完成后,将进入实施计划阶段,创建详细的开发计划和任务分解。