制造执行系统(MES)实现,包含客户端和服务器端代码,使用C#开发,支持生产管理、质量管理、设备管理和物料管理等功能。
系统架构
HTTP/JSON
OPC UA
Web API
Web API
客户端
API网关
生产管理服务
质量管理服务
设备管理服务
物料管理服务
SQL Server
PLC设备
ERP系统
WMS系统
服务器端实现
1. 项目结构
MES.Server/
├── Controllers/ // API控制器
├── Services/ // 业务逻辑层
├── Models/ // 数据模型
├── Repositories/ // 数据访问层
├── Middleware/ // 中间件
├── appsettings.json // 配置文件
└── Program.cs // 入口文件
2. 数据模型 (Models)
csharp
// ProductionOrder.cs
public class ProductionOrder
{
public int Id { get; set; }
public string OrderNumber { get; set; }
public string ProductCode { get; set; }
public int PlannedQuantity { get; set; }
public int ProducedQuantity { get; set; }
public string Status { get; set; } // Created, InProgress, Completed, Canceled
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string Workstation { get; set; }
public List<ProductionStep> Steps { get; set; } = new List<ProductionStep>();
}
// ProductionStep.cs
public class ProductionStep
{
public int Id { get; set; }
public int OrderId { get; set; }
public string StepName { get; set; }
public int Sequence { get; set; }
public string Status { get; set; } // Pending, InProgress, Completed
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public string Operator { get; set; }
public string Equipment { get; set; }
}
// QualityCheck.cs
public class QualityCheck
{
public int Id { get; set; }
public int OrderId { get; set; }
public int StepId { get; set; }
public string CheckType { get; set; } // Visual, Dimensional, Functional
public string Result { get; set; } // Pass, Fail, Rework
public string Inspector { get; set; }
public DateTime CheckTime { get; set; }
public string Comments { get; set; }
public List<Defect> Defects { get; set; } = new List<Defect>();
}
// Defect.cs
public class Defect
{
public int Id { get; set; }
public int CheckId { get; set; }
public string DefectCode { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
}
// Equipment.cs
public class Equipment
{
public int Id { get; set; }
public string EquipmentId { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Status { get; set; } // Running, Idle, Maintenance, Down
public DateTime LastMaintenance { get; set; }
public string Location { get; set; }
public List<EquipmentParameter> Parameters { get; set; } = new List<EquipmentParameter>();
}
// EquipmentParameter.cs
public class EquipmentParameter
{
public int Id { get; set; }
public int EquipmentId { get; set; }
public string ParameterName { get; set; }
public string Value { get; set; }
public DateTime Timestamp { get; set; }
}
// Material.cs
public class Material
{
public int Id { get; set; }
public string MaterialCode { get; set; }
public string Name { get; set; }
public string Specification { get; set; }
public string Unit { get; set; }
public decimal CurrentStock { get; set; }
public decimal MinStock { get; set; }
public decimal MaxStock { get; set; }
public string Supplier { get; set; }
public string Location { get; set; }
}
// MaterialTransaction.cs
public class MaterialTransaction
{
public int Id { get; set; }
public int MaterialId { get; set; }
public string TransactionType { get; set; } // Receipt, Issue, Transfer, Adjustment
public decimal Quantity { get; set; }
public string OrderId { get; set; }
public string Operator { get; set; }
public DateTime Timestamp { get; set; }
public string Comments { get; set; }
}
3. 数据库上下文 (AppDbContext.cs)
csharp
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<ProductionOrder> ProductionOrders { get; set; }
public DbSet<ProductionStep> ProductionSteps { get; set; }
public DbSet<QualityCheck> QualityChecks { get; set; }
public DbSet<Defect> Defects { get; set; }
public DbSet<Equipment> Equipments { get; set; }
public DbSet<EquipmentParameter> EquipmentParameters { get; set; }
public DbSet<Material> Materials { get; set; }
public DbSet<MaterialTransaction> MaterialTransactions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置实体关系
modelBuilder.Entity<ProductionStep>()
.HasOne(s => s.Order)
.WithMany(o => o.Steps)
.HasForeignKey(s => s.OrderId);
modelBuilder.Entity<QualityCheck>()
.HasOne(q => q.Order)
.WithMany()
.HasForeignKey(q => q.OrderId);
modelBuilder.Entity<QualityCheck>()
.HasOne(q => q.Step)
.WithMany()
.HasForeignKey(q => q.StepId);
modelBuilder.Entity<Defect>()
.HasOne(d => d.Check)
.WithMany(c => c.Defects)
.HasForeignKey(d => d.CheckId);
modelBuilder.Entity<EquipmentParameter>()
.HasOne(p => p.Equipment)
.WithMany(e => e.Parameters)
.HasForeignKey(p => p.EquipmentId);
modelBuilder.Entity<MaterialTransaction>()
.HasOne(t => t.Material)
.WithMany(m => m.Transactions)
.HasForeignKey(t => t.MaterialId);
}
}
4. 仓储层 (Repository Pattern)
csharp
// IRepository.cs
public interface IRepository<T> where T : class
{
Task<IEnumerable<T>> GetAllAsync();
Task<T> GetByIdAsync(int id);
Task AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(int id);
Task SaveChangesAsync();
}
// Repository.cs
public class Repository<T> : IRepository<T> where T : class
{
protected readonly AppDbContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(AppDbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public async Task<IEnumerable<T>> GetAllAsync()
{
return await _dbSet.ToListAsync();
}
public async Task<T> GetByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public async Task AddAsync(T entity)
{
await _dbSet.AddAsync(entity);
}
public Task UpdateAsync(T entity)
{
_context.Entry(entity).State = EntityState.Modified;
return Task.CompletedTask;
}
public async Task DeleteAsync(int id)
{
var entity = await _dbSet.FindAsync(id);
if (entity != null)
{
_dbSet.Remove(entity);
}
}
public async Task SaveChangesAsync()
{
await _context.SaveChangesAsync();
}
}
5. 服务层 (Business Logic)
csharp
// IProductionService.cs
public interface IProductionService
{
Task<IEnumerable<ProductionOrder>> GetAllOrdersAsync();
Task<ProductionOrder> GetOrderByIdAsync(int id);
Task<ProductionOrder> CreateOrderAsync(ProductionOrder order);
Task UpdateOrderAsync(ProductionOrder order);
Task StartOrderAsync(int id);
Task CompleteOrderAsync(int id);
Task CancelOrderAsync(int id);
Task AddStepAsync(int orderId, ProductionStep step);
Task UpdateStepAsync(int stepId, ProductionStep step);
Task StartStepAsync(int stepId);
Task CompleteStepAsync(int stepId);
}
// ProductionService.cs
public class ProductionService : IProductionService
{
private readonly IRepository<ProductionOrder> _orderRepository;
private readonly IRepository<ProductionStep> _stepRepository;
public ProductionService(IRepository<ProductionOrder> orderRepository,
IRepository<ProductionStep> stepRepository)
{
_orderRepository = orderRepository;
_stepRepository = stepRepository;
}
public async Task<ProductionOrder> CreateOrderAsync(ProductionOrder order)
{
order.Status = "Created";
order.StartDate = DateTime.Now;
await _orderRepository.AddAsync(order);
await _orderRepository.SaveChangesAsync();
return order;
}
public async Task StartOrderAsync(int id)
{
var order = await _orderRepository.GetByIdAsync(id);
if (order == null) throw new KeyNotFoundException("Order not found");
order.Status = "InProgress";
await _orderRepository.UpdateAsync(order);
await _orderRepository.SaveChangesAsync();
}
public async Task CompleteOrderAsync(int id)
{
var order = await _orderRepository.GetByIdAsync(id);
if (order == null) throw new KeyNotFoundException("Order not found");
order.Status = "Completed";
order.EndDate = DateTime.Now;
order.ProducedQuantity = order.PlannedQuantity; // 简化处理
await _orderRepository.UpdateAsync(order);
await _orderRepository.SaveChangesAsync();
}
public async Task AddStepAsync(int orderId, ProductionStep step)
{
var order = await _orderRepository.GetByIdAsync(orderId);
if (order == null) throw new KeyNotFoundException("Order not found");
step.OrderId = orderId;
step.Status = "Pending";
await _stepRepository.AddAsync(step);
await _stepRepository.SaveChangesAsync();
}
// 其他方法实现...
}
6. API控制器
csharp
// ProductionController.cs
[ApiController]
[Route("api/production")]
public class ProductionController : ControllerBase
{
private readonly IProductionService _productionService;
public ProductionController(IProductionService productionService)
{
_productionService = productionService;
}
[HttpGet("orders")]
public async Task<ActionResult<IEnumerable<ProductionOrder>>> GetOrders()
{
var orders = await _productionService.GetAllOrdersAsync();
return Ok(orders);
}
[HttpGet("orders/{id}")]
public async Task<ActionResult<ProductionOrder>> GetOrder(int id)
{
var order = await _productionService.GetOrderByIdAsync(id);
if (order == null) return NotFound();
return Ok(order);
}
[HttpPost("orders")]
public async Task<ActionResult<ProductionOrder>> CreateOrder(ProductionOrder order)
{
var createdOrder = await _productionService.CreateOrderAsync(order);
return CreatedAtAction(nameof(GetOrder), new { id = createdOrder.Id }, createdOrder);
}
[HttpPut("orders/{id}/start")]
public async Task<IActionResult> StartOrder(int id)
{
await _productionService.StartOrderAsync(id);
return NoContent();
}
[HttpPut("orders/{id}/complete")]
public async Task<IActionResult> CompleteOrder(int id)
{
await _productionService.CompleteOrderAsync(id);
return NoContent();
}
[HttpPost("orders/{orderId}/steps")]
public async Task<ActionResult<ProductionStep>> AddStep(int orderId, ProductionStep step)
{
step.OrderId = orderId;
await _productionService.AddStepAsync(orderId, step);
return CreatedAtAction(nameof(GetStep), new { stepId = step.Id }, step);
}
[HttpGet("steps/{stepId}")]
public async Task<ActionResult<ProductionStep>> GetStep(int stepId)
{
// 实现获取步骤详情
return Ok();
}
}
7. 主程序 (Program.cs)
csharp
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 添加数据库上下文
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 添加仓储
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
// 添加服务
builder.Services.AddScoped<IProductionService, ProductionService>();
builder.Services.AddScoped<IQualityService, QualityService>();
builder.Services.AddScoped<IEquipmentService, EquipmentService>();
builder.Services.AddScoped<IMaterialService, MaterialService>();
// 添加控制器
builder.Services.AddControllers();
// 添加Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// 配置中间件
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
// 初始化数据库
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<AppDbContext>();
context.Database.Migrate();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while migrating the database.");
}
}
app.Run();
参考代码 完整MES代码(含客户端和server端) www.youwenfan.com/contentcsu/45435.html
客户端实现 (WPF)
1. 项目结构
MES.Client/
├── Views/ // 视图
├── ViewModels/ // 视图模型 (MVVM)
├── Services/ // 服务
├── Models/ // 数据模型
├── Converters/ // 值转换器
└── App.xaml // 应用入口
2. 主窗口 (MainWindow.xaml)
xml
<Window x:Class="MES.Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MES系统" Height="768" Width="1024">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 导航菜单 -->
<StackPanel Grid.Column="0" Background="#FF2D2D30">
<Image Source="/Assets/logo.png" Height="50" Margin="10"/>
<Button Content="生产管理" Command="{Binding NavigateCommand}" CommandParameter="ProductionView" Style="{StaticResource NavButton}"/>
<Button Content="质量管理" Command="{Binding NavigateCommand}" CommandParameter="QualityView" Style="{StaticResource NavButton}"/>
<Button Content="设备管理" Command="{Binding NavigateCommand}" CommandParameter="EquipmentView" Style="{StaticResource NavButton}"/>
<Button Content="物料管理" Command="{Binding NavigateCommand}" CommandParameter="MaterialView" Style="{StaticResource NavButton}"/>
<Button Content="报表中心" Command="{Binding NavigateCommand}" CommandParameter="ReportView" Style="{StaticResource NavButton}"/>
</StackPanel>
<!-- 内容区域 -->
<ContentControl Grid.Column="1" Content="{Binding CurrentView}"/>
</Grid>
</Window>
3. 主窗口视图模型 (MainWindowViewModel.cs)
csharp
public class MainWindowViewModel : INotifyPropertyChanged
{
private object _currentView;
private readonly INavigationService _navigationService;
public event PropertyChangedEventHandler PropertyChanged;
public object CurrentView
{
get => _currentView;
set
{
_currentView = value;
OnPropertyChanged();
}
}
public ICommand NavigateCommand { get; }
public MainWindowViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
NavigateCommand = new RelayCommand(Navigate);
// 默认视图
Navigate("ProductionView");
}
private void Navigate(object parameter)
{
var viewName = parameter as string;
CurrentView = _navigationService.GetView(viewName);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
4. 生产订单视图 (ProductionView.xaml)
xml
<UserControl x:Class="MES.Client.Views.ProductionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 工具栏 -->
<ToolBar Grid.Row="0">
<Button Content="新建订单" Command="{Binding NewOrderCommand}"/>
<Button Content="开始订单" Command="{Binding StartOrderCommand}"/>
<Button Content="完成订单" Command="{Binding CompleteOrderCommand}"/>
<Button Content="取消订单" Command="{Binding CancelOrderCommand}"/>
<TextBox Width="200" Text="{Binding SearchText}" PlaceholderText="搜索订单..."/>
<Button Content="搜索"/>
</ToolBar>
<!-- 订单列表 -->
<DataGrid Grid.Row="1" ItemsSource="{Binding Orders}" SelectedItem="{Binding SelectedOrder}"
AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="订单号" Binding="{Binding OrderNumber}"/>
<DataGridTextColumn Header="产品代码" Binding="{Binding ProductCode}"/>
<DataGridTextColumn Header="计划数量" Binding="{Binding PlannedQuantity}"/>
<DataGridTextColumn Header="已产数量" Binding="{Binding ProducedQuantity}"/>
<DataGridTextColumn Header="状态" Binding="{Binding Status}"/>
<DataGridTextColumn Header="开始日期" Binding="{Binding StartDate, StringFormat=yyyy-MM-dd}"/>
<DataGridTextColumn Header="结束日期" Binding="{Binding EndDate, StringFormat=yyyy-MM-dd}"/>
</DataGrid.Columns>
</DataGrid>
<!-- 状态栏 -->
<StatusBar Grid.Row="2">
<StatusBarItem>
<TextBlock Text="{Binding StatusMessage}"/>
</StatusBarItem>
</StatusBar>
</Grid>
</UserControl>
5. 生产订单视图模型 (ProductionViewModel.cs)
csharp
public class ProductionViewModel : INotifyPropertyChanged
{
private readonly IProductionService _productionService;
private ObservableCollection<ProductionOrder> _orders = new ObservableCollection<ProductionOrder>();
private ProductionOrder _selectedOrder;
private string _searchText;
private string _statusMessage;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ProductionOrder> Orders
{
get => _orders;
set
{
_orders = value;
OnPropertyChanged();
}
}
public ProductionOrder SelectedOrder
{
get => _selectedOrder;
set
{
_selectedOrder = value;
OnPropertyChanged();
}
}
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
OnPropertyChanged();
LoadOrders();
}
}
public string StatusMessage
{
get => _statusMessage;
set
{
_statusMessage = value;
OnPropertyChanged();
}
}
public ICommand NewOrderCommand { get; }
public ICommand StartOrderCommand { get; }
public ICommand CompleteOrderCommand { get; }
public ICommand CancelOrderCommand { get; }
public ProductionViewModel(IProductionService productionService)
{
_productionService = productionService;
NewOrderCommand = new RelayCommand(NewOrder);
StartOrderCommand = new RelayCommand(StartOrder, CanStartOrder);
CompleteOrderCommand = new RelayCommand(CompleteOrder, CanCompleteOrder);
CancelOrderCommand = new RelayCommand(CancelOrder, CanCancelOrder);
LoadOrders();
}
private async void LoadOrders()
{
try
{
var orders = await _productionService.GetAllOrdersAsync();
Orders = new ObservableCollection<ProductionOrder>(orders.Where(o =>
string.IsNullOrEmpty(SearchText) || o.OrderNumber.Contains(SearchText)));
StatusMessage = $"加载了 {Orders.Count} 个订单";
}
catch (Exception ex)
{
StatusMessage = $"加载订单失败: {ex.Message}";
}
}
private void NewOrder()
{
// 打开新建订单对话框
}
private async void StartOrder()
{
if (SelectedOrder == null) return;
try
{
await _productionService.StartOrderAsync(SelectedOrder.Id);
StatusMessage = $"订单 {SelectedOrder.OrderNumber} 已开始";
LoadOrders();
}
catch (Exception ex)
{
StatusMessage = $"开始订单失败: {ex.Message}";
}
}
private bool CanStartOrder()
{
return SelectedOrder != null && SelectedOrder.Status == "Created";
}
private async void CompleteOrder()
{
if (SelectedOrder == null) return;
try
{
await _productionService.CompleteOrderAsync(SelectedOrder.Id);
StatusMessage = $"订单 {SelectedOrder.OrderNumber} 已完成";
LoadOrders();
}
catch (Exception ex)
{
StatusMessage = $"完成订单失败: {ex.Message}";
}
}
private bool CanCompleteOrder()
{
return SelectedOrder != null && SelectedOrder.Status == "InProgress";
}
private async void CancelOrder()
{
if (SelectedOrder == null) return;
try
{
await _productionService.CancelOrderAsync(SelectedOrder.Id);
StatusMessage = $"订单 {SelectedOrder.OrderNumber} 已取消";
LoadOrders();
}
catch (Exception ex)
{
StatusMessage = $"取消订单失败: {ex.Message}";
}
}
private bool CanCancelOrder()
{
return SelectedOrder != null &&
(SelectedOrder.Status == "Created" || SelectedOrder.Status == "InProgress");
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
6. API服务 (ApiService.cs)
csharp
public class ApiService
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl = "https://localhost:5001/api";
public ApiService()
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<IEnumerable<ProductionOrder>> GetProductionOrdersAsync()
{
var response = await _httpClient.GetAsync($"{_baseUrl}/production/orders");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<IEnumerable<ProductionOrder>>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
public async Task<ProductionOrder> GetProductionOrderAsync(int id)
{
var response = await _httpClient.GetAsync($"{_baseUrl}/production/orders/{id}");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<ProductionOrder>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
public async Task<ProductionOrder> CreateProductionOrderAsync(ProductionOrder order)
{
var json = JsonSerializer.Serialize(order);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{_baseUrl}/production/orders", content);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<ProductionOrder>(responseContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
public async Task StartProductionOrderAsync(int id)
{
var response = await _httpClient.PutAsync($"{_baseUrl}/production/orders/{id}/start", null);
response.EnsureSuccessStatusCode();
}
// 其他API方法...
}
系统功能说明
1. 生产管理
- 生产订单创建、修改、删除
- 生产订单状态管理(创建、进行中、完成、取消)
- 生产步骤管理
- 生产进度跟踪
- 在制品(WIP)管理
2. 质量管理
- 质量检验计划管理
- 首件检验、巡检、终检管理
- 缺陷记录与分析
- SPC统计分析
- 质量报告生成
3. 设备管理
- 设备台账管理
- 设备状态监控
- 设备维护计划
- 设备参数采集
- OEE计算与分析
4. 物料管理
- 物料主数据管理
- 库存管理(入库、出库、调拨)
- 物料追溯
- 物料需求计划(MRP)
- 供应商管理
5. 报表中心
- 生产日报/周报/月报
- 质量分析报告
- 设备效率报告
- 物料消耗报告
- 自定义报表
部署方案
1. 服务器部署
bash
# 安装.NET Core运行时
wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
chmod +x dotnet-install.sh
./dotnet-install.sh --runtime aspnetcore --version 6.0.0
# 部署应用程序
scp -r MES.Server user@server:/opt/mes
ssh user@server "cd /opt/mes && dotnet MES.Server.dll"
# 使用systemd管理
sudo nano /etc/systemd/system/mes.service
ini
[Unit]
Description=MES Server
[Service]
WorkingDirectory=/opt/mes
ExecStart=/usr/bin/dotnet /opt/mes/MES.Server.dll
Restart=always
RestartSec=10
SyslogIdentifier=mes-server
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
2. 客户端部署
- 使用ClickOnce发布WPF应用程序
- 打包为MSI安装包
- 使用Azure DevOps实现CI/CD
3. 数据库部署
sql
-- 创建数据库
CREATE DATABASE MesDatabase;
GO
USE MesDatabase;
GO
-- 创建表结构 (使用Entity Framework迁移)
-- 或者执行SQL脚本
系统扩展
1. 添加OPC UA设备集成
csharp
// OpcUaClient.cs
public class OpcUaClient
{
private Opc.Ua.Client.Session _session;
private readonly string _endpointUrl;
public OpcUaClient(string endpointUrl)
{
_endpointUrl = endpointUrl;
}
public async Task ConnectAsync()
{
var config = new Opc.Ua.ApplicationConfiguration
{
ApplicationName = "MES OPC UA Client",
ApplicationType = Opc.Ua.ApplicationType.Client,
SecurityConfiguration = new Opc.Ua.SecurityConfiguration
{
ApplicationCertificate = new Opc.Ua.CertificateIdentifier
{
StoreType = "X509Store",
StorePath = "CurrentUser\\My",
SubjectName = "CN=MES Client"
},
TrustedIssuerCertificates = new Opc.Ua.CertificateTrustList
{
StoreType = "Directory",
StorePath = "Directory"
},
TrustedPeerCertificates = new Opc.Ua.CertificateTrustList
{
StoreType = "Directory",
StorePath = "Directory"
},
RejectedCertificateStore = new Opc.Ua.CertificateTrustList
{
StoreType = "Directory",
StorePath = "Rejected"
},
AutoAcceptUntrustedCertificates = true
},
TransportQuotas = new Opc.Ua.TransportQuotas
{
OperationTimeout = 15000
},
ClientConfiguration = new Opc.Ua.ClientConfiguration
{
DefaultSessionTimeout = 60000
}
};
await config.Validate(ApplicationType.Client);
var endpoint = CoreClientUtils.SelectEndpoint(_endpointUrl, useSecurity: false);
var endpointConfiguration = EndpointConfiguration.Create(config);
var endpointDescription = new EndpointDescription(_endpointUrl);
var session = Session.Create(
config,
endpointDescription,
false,
"MES Client Session",
60000,
new Opc.Ua.UserIdentity(new Opc.Ua.AnonymousIdentityToken()),
null);
_session = session.Result;
}
public async Task<object> ReadNodeValueAsync(string nodeId)
{
var node = new NodeId(nodeId);
var value = await _session.ReadValueAsync(node);
return value.Value;
}
public async Task WriteNodeValueAsync(string nodeId, object value)
{
var node = new NodeId(nodeId);
var variant = new Variant(value);
await _session.WriteValueAsync(node, variant);
}
}
2. 添加BI集成
csharp
// PowerBiService.cs
public class PowerBiService
{
private readonly string _workspaceId;
private readonly string _reportId;
private readonly string _accessToken;
public PowerBiService(string workspaceId, string reportId, string accessToken)
{
_workspaceId = workspaceId;
_reportId = reportId;
_accessToken = accessToken;
}
public async Task<byte[]> ExportReportToPdfAsync()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var url = $"https://api.powerbi.com/v1.0/myorg/groups/{_workspaceId}/reports/{_reportId}/ExportTo";
var response = await client.PostAsync(url, null);
response.EnsureSuccessStatusCode();
var exportId = await response.Content.ReadAsStringAsync();
// 轮询导出状态...
// 下载PDF
url = $"https://api.powerbi.com/v1.0/myorg/groups/{_workspaceId}/reports/{_reportId}/exports/{exportId}/file";
var pdfResponse = await client.GetAsync(url);
return await pdfResponse.Content.ReadAsByteArrayAsync();
}
}
}
3. 添加移动端支持
csharp
// Xamarin.Forms 移动端实现
public class MobileProductionPage : ContentPage
{
public MobileProductionPage()
{
Title = "生产订单";
var listView = new ListView
{
ItemTemplate = new DataTemplate(() =>
{
var viewCell = new ViewCell();
var stackLayout = new StackLayout { Padding = new Thickness(10) };
var orderNumber = new Label { FontAttributes = FontAttributes.Bold };
orderNumber.SetBinding(Label.TextProperty, "OrderNumber");
var productCode = new Label();
productCode.SetBinding(Label.TextProperty, "ProductCode");
var status = new Label();
status.SetBinding(Label.TextProperty, "Status");
stackLayout.Children.Add(orderNumber);
stackLayout.Children.Add(productCode);
stackLayout.Children.Add(status);
viewCell.View = stackLayout;
return viewCell;
})
};
Content = listView;
// 加载数据
LoadData(listView);
}
private async void LoadData(ListView listView)
{
var apiService = new ApiService();
var orders = await apiService.GetProductionOrdersAsync();
listView.ItemsSource = orders;
}
}
系统安全
1. 认证与授权
csharp
// JWT认证服务
public class JwtService
{
private readonly string _secretKey;
private readonly string _issuer;
private readonly string _audience;
public JwtService(IConfiguration configuration)
{
_secretKey = configuration["Jwt:SecretKey"];
_issuer = configuration["Jwt:Issuer"];
_audience = configuration["Jwt:Audience"];
}
public string GenerateToken(User user)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secretKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Role)
};
var token = new JwtSecurityToken(
issuer: _issuer,
audience: _audience,
claims: claims,
expires: DateTime.Now.AddHours(3),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public ClaimsPrincipal ValidateToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_secretKey);
try
{
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = true,
ValidIssuer = _issuer,
ValidateAudience = true,
ValidAudience = _audience,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out _);
return principal;
}
catch
{
return null;
}
}
}
2. 数据加密
csharp
// 数据加密服务
public class EncryptionService
{
public static string Encrypt(string plainText, string key)
{
using (var aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32));
aes.IV = new byte[16];
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (var sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
return Convert.ToBase64String(ms.ToArray());
}
}
}
public static string Decrypt(string cipherText, string key)
{
using (var aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32));
aes.IV = new byte[16];
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var ms = new MemoryStream(Convert.FromBase64String(cipherText)))
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (var sr = new StreamReader(cs))
{
return sr.ReadToEnd();
}
}
}
}
系统监控
1. 健康检查
csharp
// 健康检查端点
[ApiController]
[Route("health")]
public class HealthController : ControllerBase
{
private readonly AppDbContext _context;
private readonly ILogger<HealthController> _logger;
public HealthController(AppDbContext context, ILogger<HealthController> logger)
{
_context = context;
_logger = logger;
}
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
// 检查数据库连接
await _context.Database.CanConnectAsync();
// 检查关键服务
// ...
return Ok(new
{
Status = "Healthy",
Timestamp = DateTime.UtcNow,
Version = Assembly.GetEntryAssembly().GetName().Version.ToString()
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Health check failed");
return StatusCode(503, new
{
Status = "Unhealthy",
Error = ex.Message,
Timestamp = DateTime.UtcNow
});
}
}
}
2. 日志管理
csharp
// 日志配置
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
// 添加文件日志
logging.AddFile("Logs/mes-{Date}.txt");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
总结
这个完整的MES系统实现提供了以下核心功能:
-
生产管理:
- 生产订单全生命周期管理
- 生产步骤跟踪与控制
- 在制品管理
- 生产进度监控
-
质量管理:
- 质量检验计划与执行
- 缺陷记录与分析
- SPC统计分析
- 质量报告
-
设备管理:
- 设备台账管理
- 设备状态监控
- 设备维护管理
- OEE计算与分析
-
物料管理:
- 物料主数据管理
- 库存管理
- 物料追溯
- 物料需求计划
-
系统集成:
- OPC UA设备集成
- ERP/WMS系统集成
- BI系统对接
- 移动端支持
系统采用现代化的技术栈:
- 后端:ASP.NET Core Web API
- 前端:WPF客户端
- 数据库:SQL Server
- 架构:微服务架构(可扩展)
- 安全:JWT认证、数据加密
- 部署:Docker容器化部署