using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using TeamAAS_VP.Core;
using TeamAAS_VP.Data; // for ISystemDatabaseService (if used)
using TeamAAS_VP.Enums;
using TeamAAS_VP.Interfaces;
using TeamAAS_VP.Models;
using TeamAAS_VP.Models.Calibration;
using TeamAAS_VP.Models.Feeder;
using TeamAAS_VP.Models.Lights;
using TeamAAS_VP.Models.PLC;
using TeamAAS_VP.Models.ScrewDriver;
using TeamAAS_VP.Resources.Languages;
using WPFLocalizeExtension.Engine;
namespace TeamAAS_VP.Services
{
///
/// 配置参数服务实现类。
/// 线程安全:内部使用私有锁字段 来保护对内存集合的并发访问。
/// 持久化:对集合的修改会写回到对应的配置文件(路径由内部静态类 定义)。
///
public class ConfigService : IConfigService
{
private static class ConfigPaths
{
// 将路径集中管理于本类,当前使用现有 FilePath 值以保持兼容
public static readonly string CamerasConfigurationPath = "..//Config//CameraConfiguration.cfg";
public static readonly string RobotsConfigurationPath = "..//Config//RobotsConfiguration.cfg";
public static readonly string FeedersConfigurationPath = "..//Config//FeedersConfiguration.cfg";
public static readonly string PlcConfigurationPath = "..//Config//PlcConfiguration.cfg";
public static readonly string BgTcpIpConfigurationPath = "..//Config//BgTcpIpConfiguration.cfg";
public static readonly string BgModbusTcpConfigurationPath = "..//Config//BgModbusTcpConfiguration.cfg";
public static readonly string SystemConfigurationPath = "..//Config//SystemConfiguration.cfg";
public static readonly string DeviceInfoConfigurationPath = "..//Config//DeviceInfo.cfg";
// Feeder清料任务配置路径
public static readonly string FeederClearanceTasksConfigurationPath = "..//Config//FeederClearanceTasksConfiguration.cfg";
// 光源控制器配置路径
public static readonly string LightControllersConfigurationPath = "..//Config//LightControllersConfiguration.cfg";
// 电批配置路径(单设备)
public static readonly string ScrewDriverConfigurationPath = "..//Config//ScrewDriverConfiguration.cfg";
// 螺丝供料器(物料)配置路径
public static readonly string ScrewFeedersConfigurationPath = "..//Config//ScrewFeedersConfiguration.cfg";
// 刷卡器配置路径
public static readonly string CardReaderConfigurationPath = "..//Config//CardReaderConfiguration.cfg";
// 生产数据配置路径
public static readonly string DataConfigurationPath = "..//Config//DataConfiguration.cfg";
}
private readonly object _sync = new object();
private ObservableCollection Cameras { get; set; }
private ObservableCollection Robots { get; set; }
private ObservableCollection Feeders { get; set; }
// 螺丝供料器(物料)集合
private ObservableCollection ScrewFeeders { get; set; }
private ObservableCollection Plcs { get; set; }
private BgTcpIP BgCommunicate { get; set; }
private BgModbusTcp BgModbusCommunicate { get; set; }
private ObservableCollection FeederClearanceTasks { get; set; }
// 光源控制器配置
private ObservableCollection LightControllers { get; set; }
// Device info - 支持多设备
private List _deviceInfoList;
private PlcAddressConfig PlcAddressConfig { get; set; }
// 单个电批配置
private TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig _screwDriverConfig;
public TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig ScrewDriverConfig { get { lock(_sync) { return _screwDriverConfig; } } }
private ISystemDatabaseService _systemDatabaseService;
// 刷卡器配置
private SerialPortConfig _cardReaderConfig;
///
/// 注入系统数据库服务(可选),用于记录螺丝批次变更等记录。
///
///
public void SetSystemDatabaseService(ISystemDatabaseService svc)
{
lock (_sync)
{
_systemDatabaseService = svc;
}
}
///
/// 将螺丝供料器批次变更记录写入数据库(若已注入 ISystemDatabaseService)。
///
public async System.Threading.Tasks.Task RecordScrewFeederBatchAsync(ScrewFeederBatchRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
try
{
if (_systemDatabaseService != null)
{
await _systemDatabaseService.RecordScrewFeederBatchAsync(record);
}
}
catch
{
// 忽略数据库写入错误,记录可添加日志
}
}
///
/// 初始化一个新的 实例。
/// 构造函数不会自动加载配置文件(避免在构造期间进行 I/O 操作);可调用 或 显式加载。
///
public ConfigService()
{
//LoadAll();
}
///
/// 同步加载所有配置文件至内存(若对应文件不存在,将创建默认空集合/对象并写入文件)。
/// 线程安全:方法内部对共享资源使用 加锁。
///
public void LoadAll()
{
lock (_sync)
{
// 读取各配置,如果文件不存在,则保持 DeviceConfig 默认值
if (File.Exists(ConfigPaths.CamerasConfigurationPath))
Cameras = FileHelper.ReadJsonFile>(ConfigPaths.CamerasConfigurationPath);
else
{
Cameras = new ObservableCollection();
FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
}
if (File.Exists(ConfigPaths.RobotsConfigurationPath))
Robots = FileHelper.ReadJsonFile>(ConfigPaths.RobotsConfigurationPath);
else
{
Robots = new ObservableCollection();
FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
}
if (File.Exists(ConfigPaths.FeedersConfigurationPath))
Feeders = FileHelper.ReadJsonFile>(ConfigPaths.FeedersConfigurationPath);
else
{
Feeders = new ObservableCollection();
FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
}
// load screw feeders (material) configuration
if (File.Exists(ConfigPaths.ScrewFeedersConfigurationPath))
ScrewFeeders = FileHelper.ReadJsonFile>(ConfigPaths.ScrewFeedersConfigurationPath);
else
{
ScrewFeeders = new ObservableCollection();
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
}
if (File.Exists(ConfigPaths.PlcConfigurationPath))
Plcs = FileHelper.ReadJsonFile>(ConfigPaths.PlcConfigurationPath);
else
{
Plcs = new ObservableCollection();
FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
}
if (File.Exists(ConfigPaths.BgTcpIpConfigurationPath))
BgCommunicate = FileHelper.ReadJsonFile(ConfigPaths.BgTcpIpConfigurationPath);
else
{
BgCommunicate = new BgTcpIP();
FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath);
}
if (File.Exists(ConfigPaths.BgModbusTcpConfigurationPath))
BgModbusCommunicate = FileHelper.ReadJsonFile(ConfigPaths.BgModbusTcpConfigurationPath);
else
{
BgModbusCommunicate = new BgModbusTcp();
FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath);
}
if (!File.Exists(ConfigPaths.FeederClearanceTasksConfigurationPath))
{
FeederClearanceTasks = new ObservableCollection();
FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
}
else
{
// 读取 Feeder清料任务 配置
FeederClearanceTasks = FileHelper.ReadJsonFile>(ConfigPaths.FeederClearanceTasksConfigurationPath);
}
// 读取光源控制器配置
if (!File.Exists(ConfigPaths.LightControllersConfigurationPath))
{
LightControllers = new ObservableCollection();
FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
}
else
{
LightControllers = FileHelper.ReadJsonFile>(ConfigPaths.LightControllersConfigurationPath);
}
// load plc addresses
var plcAddressPath = "..//Config//PlcAddressConfiguration.cfg";
if (File.Exists(plcAddressPath))
PlcAddressConfig = FileHelper.ReadJsonFile(plcAddressPath);
else
{
PlcAddressConfig = new PlcAddressConfig();
PlcAddressConfig.SetDefaultValue();
FileHelper.WriteJsonFile(PlcAddressConfig, plcAddressPath);
}
// load screw driver config (single device)
if (File.Exists(ConfigPaths.ScrewDriverConfigurationPath))
_screwDriverConfig = FileHelper.ReadJsonFile(ConfigPaths.ScrewDriverConfigurationPath);
else
{
_screwDriverConfig = new TeamAAS_VP.Models.ScrewDriver.ScrewDriverConfig();
FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
}
// load device info list (支持多设备)
if (File.Exists(ConfigPaths.DeviceInfoConfigurationPath))
{
try
{
// 尝试作为列表读取
_deviceInfoList = FileHelper.ReadJsonFile>(ConfigPaths.DeviceInfoConfigurationPath);
}
catch
{
// 兼容旧版单个 DeviceInfo,将其转换为列表
var singleDevice = FileHelper.ReadJsonFile(ConfigPaths.DeviceInfoConfigurationPath);
if (singleDevice != null)
{
singleDevice.DeviceNo = 0;
_deviceInfoList = new List { singleDevice };
}
else
{
_deviceInfoList = new List { new DeviceInfo { DeviceNo = 0 } };
}
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
}
else
{
_deviceInfoList = new List { new DeviceInfo { DeviceNo = 0 } };
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
// load card reader configuration
if (File.Exists(ConfigPaths.CardReaderConfigurationPath))
_cardReaderConfig = FileHelper.ReadJsonFile(ConfigPaths.CardReaderConfigurationPath);
else
{
_cardReaderConfig = new SerialPortConfig();
FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
}
}
}
///
/// 异步执行 操作。
///
/// 表示异步加载操作的任务。
public Task LoadAllAsync()
{
return Task.Run(() => LoadAll());
}
///
/// 将内存中的所有配置写回到对应配置文件。
/// 线程安全:方法内部对写入操作使用 加锁。
///
public void SaveAll()
{
lock (_sync)
{
FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath);
FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath);
FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
// save screw driver config
if (_screwDriverConfig != null)
FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
// save screw feeders
if (ScrewFeeders != null)
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
// save plc addresses
//FileHelper.WriteJsonFile(PlcAddressConfig, "..//Config//PlcAddressConfiguration.cfg");
// save device info list (支持多设备)
if (_deviceInfoList != null)
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
// save card reader config
if (_cardReaderConfig != null)
FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
}
}
///
/// 异步执行 操作。
///
/// 表示异步保存操作的任务。
public Task SaveAllAsync()
{
return Task.Run(() => SaveAll());
}
#region Cameras
///
/// 获取所有相机配置的只读集合。
/// 线程安全:在内部加锁以保证并发读取的一致性。
///
/// 相机配置的只读集合。
public IReadOnlyCollection GetAllCameras()
{
lock (_sync) { return Cameras.ToList().AsReadOnly(); }
}
///
/// 根据标识获取单个相机配置信息。
///
/// 相机的 Guid 标识。
/// 找到则返回对应的 ,否则返回 null。
public CameraInfo GetCamera(Guid id)
{
lock (_sync) { return Cameras.FirstOrDefault(c => c.Id == id); }
}
///
/// 新增或更新相机配置。
/// - 若传入 为 null 返回 null。
/// - 若 Id 已存在则替换;否则追加并设置连续的 CameraNo 编号。
/// 方法结束后会将相机集合持久化到配置文件。
///
/// 要添加或更新的相机配置。
/// 已添加或更新的 ;输入为 null 时返回 null。
public CameraInfo AddOrUpdateCamera(CameraInfo camera)
{
if (camera == null) return null;
lock (_sync)
{
var exist = Cameras.FirstOrDefault(c => c.Id == camera.Id);
if (exist != null)
{
var idx = Cameras.IndexOf(exist);
Cameras[idx] = camera;
}
else
{
camera.CameraNo = Cameras.Count + 1;
Cameras.Add(camera);
}
}
FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
return camera;
}
///
/// 根据标识移除相机配置并重新编号剩余相机的 CameraNo。
/// 方法结束后会将相机集合持久化到配置文件。
///
/// 要移除的相机 Guid。
/// 若找到并成功移除返回 true,否则返回 false。
public bool RemoveCamera(Guid id)
{
bool result = false;
lock (_sync)
{
var exist = Cameras.FirstOrDefault(c => c.Id == id);
if (exist != null) result = Cameras.Remove(exist);
//重新编号
int no = 1;
//对所有相机按CameraNo排序
var sortedCameras = Cameras.OrderBy(c => c.CameraNo).ToList();
foreach (var cam in sortedCameras)
{
cam.CameraNo = no;
no++;
}
Cameras.Clear();
foreach (var cam in sortedCameras)
{
Cameras.Add(cam);
}
}
FileHelper.WriteJsonFile(Cameras, ConfigPaths.CamerasConfigurationPath);
return result;
}
///
/// 检查是否包含指定 Id 的相机配置。
///
/// 相机的 Guid。
/// 存在返回 true,否则返回 false。
public bool ContainsCamera(Guid id) { lock (_sync) { return Cameras.Any(c => c.Id == id); } }
#endregion
#region DeviceInfo
///
/// 获取所有设备信息配置列表
///
/// 设备信息列表的只读集合
public IReadOnlyCollection GetAllDeviceInfos()
{
lock (_sync)
{
if (_deviceInfoList == null)
{
if (File.Exists(ConfigPaths.DeviceInfoConfigurationPath))
{
try
{
_deviceInfoList = FileHelper.ReadJsonFile>(ConfigPaths.DeviceInfoConfigurationPath);
}
catch
{
// 兼容旧版单个 DeviceInfo
var singleDevice = FileHelper.ReadJsonFile(ConfigPaths.DeviceInfoConfigurationPath);
if (singleDevice != null)
{
singleDevice.DeviceNo = 0;
_deviceInfoList = new List { singleDevice };
}
else
{
_deviceInfoList = new List { new DeviceInfo { DeviceNo = 0 } };
}
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
}
else
{
_deviceInfoList = new List { new DeviceInfo { DeviceNo = 0 } };
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
}
return _deviceInfoList.AsReadOnly();
}
}
///
/// 根据设备编号获取设备信息(兼容旧API,返回第一个设备)
///
/// 设备信息,若不存在则创建默认设备
public DeviceInfo GetDeviceInfo()
{
return GetDeviceInfo(0);
}
///
/// 根据设备编号获取设备信息
///
/// 设备编号
/// 设备信息,若不存在则返回 null
public DeviceInfo GetDeviceInfo(int deviceNo)
{
lock (_sync)
{
var allDevices = GetAllDeviceInfos();
return allDevices.FirstOrDefault(d => d.DeviceNo == deviceNo);
}
}
///
/// 添加或更新设备信息
///
/// 设备信息对象
public void SaveDeviceInfo(DeviceInfo deviceInfo)
{
if (deviceInfo == null) return;
lock (_sync)
{
// 确保列表已初始化
if (_deviceInfoList == null)
{
_deviceInfoList = new List();
}
// 查找是否已存在相同设备编号的设备
var existing = _deviceInfoList.FirstOrDefault(d => d.DeviceNo == deviceInfo.DeviceNo);
if (existing != null)
{
// 更新现有设备
var index = _deviceInfoList.IndexOf(existing);
_deviceInfoList[index] = deviceInfo;
}
else
{
// 添加新设备
_deviceInfoList.Add(deviceInfo);
}
// 按设备编号排序
_deviceInfoList = _deviceInfoList.OrderBy(d => d.DeviceNo).ToList();
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
}
///
/// 保存所有设备信息列表
///
/// 设备信息列表
public void SaveAllDeviceInfos(IEnumerable deviceInfoList)
{
if (deviceInfoList == null) return;
lock (_sync)
{
_deviceInfoList = deviceInfoList.OrderBy(d => d.DeviceNo).ToList();
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
}
}
///
/// 添加新设备
///
/// 新添加的设备
public DeviceInfo AddDeviceInfo()
{
lock (_sync)
{
if (_deviceInfoList == null)
{
_deviceInfoList = new List();
}
// 计算新设备编号
int newDeviceNo = _deviceInfoList.Count > 0 ? _deviceInfoList.Max(d => d.DeviceNo) + 1 : 0;
var newDevice = new DeviceInfo { DeviceNo = newDeviceNo };
_deviceInfoList.Add(newDevice);
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
return newDevice;
}
}
///
/// 删除设备
///
/// 设备编号
/// 是否删除成功
public bool RemoveDeviceInfo(int deviceNo)
{
lock (_sync)
{
if (_deviceInfoList == null) return false;
var device = _deviceInfoList.FirstOrDefault(d => d.DeviceNo == deviceNo);
if (device != null)
{
_deviceInfoList.Remove(device);
FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
return true;
}
return false;
}
}
#endregion
#region Robots
///
/// 获取所有机器人配置的只读集合。
///
/// 机器人配置的只读集合。
public IReadOnlyCollection GetAllRobots() { lock (_sync) { return Robots.ToList().AsReadOnly(); } }
///
/// 根据标识获取单个机器人配置。
///
/// 机器人的 Guid 标识。
/// 找到则返回对应的 ,否则返回 null。
public RobotInfo GetRobot(Guid id) { lock (_sync) { return Robots.FirstOrDefault(r => r.Id == id); } }
///
/// 新增或更新机器人配置,操作后持久化至配置文件。
/// 新增时为机器人分配连续的 RobotNo 编号。
///
/// 要添加或更新的机器人配置。
/// 已添加或更新的 ;输入为 null 时返回 null。
public RobotInfo AddOrUpdateRobot(RobotInfo robot)
{
if (robot == null) return null;
lock (_sync)
{
var exist = Robots.FirstOrDefault(r => r.Id == robot.Id);
if (exist != null)
{
var idx = Robots.IndexOf(exist);
Robots[idx] = robot;
}
else
{
robot.RobotNo = Robots.Count + 1;
Robots.Add(robot);
}
}
FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
return robot;
}
///
/// 根据标识移除机器人配置并重新编号剩余机器人。
/// 操作后持久化配置文件。
///
/// 要移除的机器人 Guid。
/// 移除成功返回 true,否则返回 false。
public bool RemoveRobot(Guid id)
{
bool result = false;
lock (_sync)
{
var e = Robots.FirstOrDefault(r => r.Id == id);
if (e != null)
result = Robots.Remove(e);
//重新编号
int no = 1;
//对所有机器人按RobotNo排序
var sortedRobots = Robots.OrderBy(r => r.RobotNo).ToList();
foreach (var r in sortedRobots)
{
r.RobotNo = no;
no++;
}
Robots.Clear();
foreach (var r in sortedRobots)
{
Robots.Add(r);
}
}
FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
return result;
}
///
/// 判断是否包含指定 Id 的机器人配置。
///
/// 机器人的 Guid。
/// 存在返回 true,否则返回 false。
public bool ContainsRobot(Guid id) { lock (_sync) { return Robots.Any(r => r.Id == id); } }
///
/// 修改指定机器人 Id的步进距离并持久化机器人配置。
///
/// 机器人唯一标识符。
/// 步进距离。
/// 更新成功返回 true,找不到机器人返回 false。
public bool UpdateRobotStepDistance(Guid id, double stepDistance)
{
lock (_sync)
{
var robot = Robots.FirstOrDefault(r => r.Id == id);
if (robot != null)
{
robot.StepDistance = stepDistance;
FileHelper.WriteJsonFile(Robots, ConfigPaths.RobotsConfigurationPath);
return true;
}
else
{
return false;
}
}
}
///
/// 获取指定机器人 Id 的步进距离。
///
/// 机器人 Guid。
/// 若找到则返回对应的步进距离,否则返回默认值 1.0。
public double GetRobotStepDistance(Guid id)
{
lock (_sync)
{
var robot = Robots.FirstOrDefault(r => r.Id == id);
if (robot != null)
{
return robot.StepDistance;
}
else
{
return 1.0;
}
}
}
#endregion
#region Feeders
///
/// 获取所有供料器配置的只读集合。
///
/// 供料器配置的只读集合。
public IReadOnlyCollection GetAllFeeders() { lock (_sync) { return Feeders.ToList().AsReadOnly(); } }
///
/// 根据标识获取单个供料器配置。
///
/// 供料器的 Guid 标识。
/// 找到则返回对应的 ,否则返回 null。
public FeederInfo GetFeeder(Guid id) { lock (_sync) { return Feeders.FirstOrDefault(f => f.Id == id); } }
///
/// 新增或更新供料器配置,操作后持久化至配置文件。
/// 新增时为供料器分配连续的 FeederNo 编号。
///
/// 要添加或更新的供料器配置。
/// 已添加或更新的 ;输入为 null 时返回 null。
public FeederInfo AddOrUpdateFeeder(FeederInfo feeder)
{
if (feeder == null) return null;
lock (_sync)
{
var exist = Feeders.FirstOrDefault(f => f.Id == feeder.Id);
if (exist != null)
{
var idx = Feeders.IndexOf(exist);
Feeders[idx] = feeder;
}
else
{
feeder.FeederNo = Feeders.Count + 1;
Feeders.Add(feeder);
}
}
FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
return feeder;
}
///
/// 根据标识移除供料器配置并重新编号剩余供料器。
/// 操作后持久化配置文件。
///
/// 要移除的供料器 Guid。
/// 移除成功返回 true,否则返回 false。
public bool RemoveFeeder(Guid id)
{
bool result = false;
lock (_sync)
{
var e = Feeders.FirstOrDefault(f => f.Id == id);
if (e != null) result = Feeders.Remove(e);
//重新编号
int no = 1;
//对所有供料器按FeederNo排序
var sortedFeeders = Feeders.OrderBy(f => f.FeederNo).ToList();
foreach (var f in sortedFeeders)
{
f.FeederNo = no;
no++;
}
Feeders.Clear();
foreach (var f in sortedFeeders)
{
Feeders.Add(f);
}
}
FileHelper.WriteJsonFile(Feeders, ConfigPaths.FeedersConfigurationPath);
return result;
}
///
/// 判断是否包含指定 Id 的供料器配置。
///
/// 供料器 Guid。
/// 存在返回 true,否则返回 false。
public bool ContainsFeeder(Guid id) { lock (_sync) { return Feeders.Any(f => f.Id == id); } }
#endregion
#region PLC
///
/// 获取所有 PLC 配置的只读集合。
///
/// PLC 配置的只读集合。
public IReadOnlyCollection GetAllPlcs() { lock (_sync) { return Plcs.ToList().AsReadOnly(); } }
///
/// 根据标识获取单个 PLC 配置。
///
/// PLC 的 Guid 标识。
/// 匹配的 实例,找不到返回 null。
public PlcInfo GetPlc(Guid id) { lock (_sync) { return Plcs.FirstOrDefault(p => p.Id == id); } }
///
/// 新增或更新 PLC 配置,操作后持久化至配置文件;新增时分配连续 PlcNo 编号。
///
/// 要添加或更新的 PLC 配置。
/// 已添加或更新的 ;输入为 null 时返回 null。
public PlcInfo AddOrUpdatePlc(PlcInfo plc)
{
if (plc == null) return null;
lock (_sync)
{
var exist = Plcs.FirstOrDefault(p => p.Id == plc.Id);
if (exist != null)
{
var idx = Plcs.IndexOf(exist);
Plcs[idx] = plc;
}
else
{
plc.PlcNo = Plcs.Count + 1;
Plcs.Add(plc);
}
}
FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
return plc;
}
///
/// 根据标识移除 PLC 配置并重新编号剩余 PLC。
/// 操作后持久化配置文件。
///
/// 要移除的 PLC Guid。
/// 移除成功返回 true,否则返回 false。
public bool RemovePlc(Guid id)
{
bool result = false;
lock (_sync)
{
var e = Plcs.FirstOrDefault(p => p.Id == id);
if (e != null) result = Plcs.Remove(e);
//重新编号
int no = 1;
//对所有PLC按PlcNo排序
var sortedPlcs = Plcs.OrderBy(p => p.PlcNo).ToList();
foreach (var p in sortedPlcs)
{
p.PlcNo = no;
no++;
}
Plcs.Clear();
foreach (var p in sortedPlcs)
{
Plcs.Add(p);
}
}
FileHelper.WriteJsonFile(Plcs, ConfigPaths.PlcConfigurationPath);
return result;
}
///
/// 判断是否包含指定 Id 的 PLC 配置。
///
/// PLC 的 Guid。
/// 存在返回 true,否则返回 false。
public bool ContainsPlc(Guid id) { lock (_sync) { return Plcs.Any(p => p.Id == id); } }
#endregion
#region BgTcp
///
/// 获取 BG TCP/IP 通信配置(内存对象,可能为 null)。
///
/// 当前的 配置对象。
public BgTcpIP GetBgTcp() { lock (_sync) { return BgCommunicate; } }
///
/// 设置 BG TCP/IP 通信配置(仅更新内存对象,不会自动持久化)。
/// 若需持久化请调用 。
///
/// 新的 配置对象。
public void SetBgTcp(BgTcpIP cfg) { lock (_sync) { BgCommunicate = cfg; } }
///
/// 将当前内存中的 BG TCP/IP 配置持久化到配置文件。
///
public void SaveBgTcp() { lock (_sync) { FileHelper.WriteJsonFile(BgCommunicate, ConfigPaths.BgTcpIpConfigurationPath); } }
#endregion
#region BgModbus
///
/// 获取 BG Modbus TCP 通信配置(内存对象)。
///
/// 当前的 配置对象。
public BgModbusTcp GetBgModbusTcp() { lock (_sync) { return BgModbusCommunicate; } }
///
/// 设置 BG Modbus TCP 通信配置(仅更新内存对象,不会自动持久化)。
///
/// 新的 配置对象。
public void SetBgModbusTcp(BgModbusTcp cfg) { lock (_sync) { BgModbusCommunicate = cfg; } }
///
/// 将当前内存中的 BG Modbus TCP 配置持久化到配置文件。
///
public void SaveBgModbusTcp() { lock (_sync) { FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath); } }
#endregion
#region 系统参数
///
/// 获取系统设置(从配置文件读取)。
/// 线程安全:方法内部加锁以保证读取一致性。
///
/// 读取到的 对象;若文件不存在则返回默认的新实例。
public SystemConfiguration GetSystemConfiguration()
{
lock (_sync)
{
var config = new SystemConfiguration();
if (File.Exists(ConfigPaths.SystemConfigurationPath))
{
config = FileHelper.ReadJsonFile(ConfigPaths.SystemConfigurationPath);
}
return config;
}
}
///
/// 保存系统设置到配置文件(会覆盖现有文件)。
///
/// 要保存的系统配置对象。
public void SaveSystemConfiguration(SystemConfiguration systemConfiguration)
{
lock (_sync)
{
FileHelper.WriteJsonFile(systemConfiguration, ConfigPaths.SystemConfigurationPath);
}
}
///
/// 获取当前语言
///
///
public Language GetCurrentLanguage()
{
lock (_sync)
{
var config = GetSystemConfiguration();
return config.CurrentLanguage;
}
}
///
/// 设置当前语言
///
///
public void SetCurrentLanguage(Language language)
{
lock (_sync)
{
var config = GetSystemConfiguration();
config.CurrentLanguage = language;
if (language == Enums.Language.ChineseSimplified)
{
var culture = new CultureInfo("zh-CN");
App.Current.Dispatcher.Thread.CurrentCulture = culture;
App.Current.Dispatcher.Thread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
Lang.Culture = culture;
System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
}
else if (language == Enums.Language.ChineseTraditional)
{
var culture = new CultureInfo("zh-TW");
App.Current.Dispatcher.Thread.CurrentCulture = culture;
App.Current.Dispatcher.Thread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
Lang.Culture = culture;
System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Microsoft YaHei");
}
else if (language == Enums.Language.English)
{
var culture = new CultureInfo("en");
App.Current.Dispatcher.Thread.CurrentCulture = culture;
App.Current.Dispatcher.Thread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
Lang.Culture = culture;
System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
}
else if (language == Enums.Language.Japanese)
{
var culture = new CultureInfo("ja-JP");
App.Current.Dispatcher.Thread.CurrentCulture = culture;
App.Current.Dispatcher.Thread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
Lang.Culture = culture;
System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
}
else if (language == Enums.Language.Vietnamese)
{
var culture = new CultureInfo("vi");
App.Current.Dispatcher.Thread.CurrentCulture = culture;
App.Current.Dispatcher.Thread.CurrentUICulture = culture;
LocalizeDictionary.Instance.Culture = culture;
Lang.Culture = culture;
System.Windows.Application.Current.Resources["DefaultFont"] = new System.Windows.Media.FontFamily("Segoe UI");
}
SaveSystemConfiguration(config);
}
}
#endregion
#region Feeder清料任务
///
/// 获取所有清料任务的只读集合。
///
/// 清料任务的只读集合。
public IReadOnlyCollection GetAllClearanceTasks() { lock (_sync) { return FeederClearanceTasks.ToList().AsReadOnly(); } }
///
/// 新增或更新清料任务,新增时为任务分配递增的 TaskCode,完成后持久化配置文件。
///
/// 要添加或更新的清料任务对象。
/// 已添加或更新的 ;输入为 null 时返回 null。
public FeederClearWork AddOrUpdateClearanceTask(FeederClearWork task)
{
if (task == null) return null;
lock (_sync)
{
var exist = FeederClearanceTasks.FirstOrDefault(t => t.Id == task.Id);
if (exist != null)
{
var idx = FeederClearanceTasks.IndexOf(exist);
FeederClearanceTasks[idx] = task;
}
else
{
// 设置任务编号为当前最大编号加1
task.TaskCode = FeederClearanceTasks.Count > 0 ? FeederClearanceTasks.Max(t => t.TaskCode) + 1 : 1;
FeederClearanceTasks.Add(task);
}
}
FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
return task;
}
///
/// 根据标识移除清料任务并持久化配置文件。
///
/// 要移除的清料任务 Guid。
/// 若找到并移除返回 true,否则返回 false。
public bool RemoveClearanceTask(Guid id)
{
lock (_sync)
{
var exist = FeederClearanceTasks.FirstOrDefault(t => t.Id == id);
if (exist != null)
{
FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
return FeederClearanceTasks.Remove(exist);
}
else
return false;
}
}
///
/// 清除所有清料任务并持久化空集合到配置文件。
///
public void ClearAllClearanceTasks()
{
lock (_sync)
{
FeederClearanceTasks.Clear();
}
FileHelper.WriteJsonFile(FeederClearanceTasks, ConfigPaths.FeederClearanceTasksConfigurationPath);
}
///
/// 判断是否包含指定 Id 的清料任务。
///
/// 清料任务 Guid。
/// 存在返回 true,否则返回 false。
public bool ContainsClearanceTask(Guid id)
{
lock (_sync) { return FeederClearanceTasks.Any(t => t.Id == id); }
}
///
/// 根据标识获取单个清料任务信息。
///
/// 清料任务 Guid。
/// 匹配的 ,找不到返回 null。
public FeederClearWork GetClearanceTask(Guid id)
{
lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.Id == id); }
}
///
/// 判断是否包含指定任务编号的清料任务。
///
/// 任务编号(TaskCode)。
/// 存在返回 true,否则返回 false。
public bool ContainsClearanceTaskByNumber(int taskNumber)
{
lock (_sync) { return FeederClearanceTasks.Any(t => t.TaskCode == taskNumber); }
}
///
/// 根据任务编号获取单个清料任务信息。
///
/// 任务编号(TaskCode)。
/// 匹配的 ,找不到返回 null。
public FeederClearWork GetClearanceTaskByNumber(int taskNumber)
{
lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.TaskCode == taskNumber); }
}
#endregion
#region Light controllers and channels
///
/// 获取所有光源控制器配置的只读集合。
/// 线程安全:在内部使用 进行锁定以保证并发访问安全。
///
/// 按当前内存中存储顺序返回的只读 集合。
public IReadOnlyCollection GetAllLightControllers()
{
lock (_sync) { return LightControllers.ToList().AsReadOnly(); }
}
///
/// 根据控制器标识获取单个光源控制器配置。
/// 线程安全:该方法对内存集合进行只读访问并在内部加锁。
///
/// 控制器的整数标识(Id)。
/// 匹配的 实例,找不到则返回 null。
public LightControllerConfig GetLightController(int id)
{
lock (_sync) { return LightControllers.FirstOrDefault(c => c.Id == id); }
}
///
/// 新增或更新光源控制器配置。
/// - 若 为 null 返回 null。
/// - 更新时以 Id 匹配现有项并替换。
/// - 新增时分配连续的控制器 Id,并为控制器内的每个通道分配全局通道编号(GlobalIndex)。
/// 线程安全:在内部使用 锁定集合。
///
/// 要添加或更新的 实例。
/// 已添加或更新的 实例;输入为 null 时返回 null。
/// 当要添加/更新的控制器名称与现有其他控制器重复时抛出。
public LightControllerConfig AddOrUpdateLightController(LightControllerConfig controller)
{
if (controller == null) return null;
lock (_sync)
{
// 名称不得与其他控制器重复(同名但不同 Id 不允许)
if (LightControllers.Any(c => c.Name == controller.Name && c.Id != controller.Id))
throw new ArgumentException("Controller name must be unique");
var exist = LightControllers.FirstOrDefault(c => c.Id == controller.Id);
if (exist != null)
{
// 更新现有控制器(按索引替换)
var idx = LightControllers.IndexOf(exist);
LightControllers[idx] = controller;
}
else
{
// 新增控制器
// 分配控制器编号为当前最大 Id + 1(若集合为空则为 1)
controller.Id = LightControllers.Count > 0 ? LightControllers.Max(c => c.Id) + 1 : 1;
// 计算下一个全局通道索引:在所有已存在控制器的通道 GlobalIndex 上取最大值并加1
int nextGlobal = 0;
if (LightControllers.SelectMany(c => c.ChannelConfigs).Any())
{
nextGlobal = LightControllers.SelectMany(c => c.ChannelConfigs).Max(ch => ch.GlobalIndex) + 1;
}
// 遍历新增控制器的通道,若通道的 GlobalIndex 无效(<0)或与现有通道冲突,则重新分配
for (int i = 0; i < controller.ChannelConfigs.Count; i++)
{
var ch = controller.ChannelConfigs[i];
if (ch.GlobalIndex < 0 || LightControllers.SelectMany(c => c.ChannelConfigs).Any(existingCh => existingCh.GlobalIndex == ch.GlobalIndex))
{
ch.GlobalIndex = nextGlobal;
nextGlobal++;
}
}
LightControllers.Add(controller);
}
}
// 持久化更新后的光源控制器配置
FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
return controller;
}
///
/// 根据 Id 移除光源控制器配置并对剩余控制器重新编号(从 1 开始连续编号)。
/// 操作后持久化配置文件。
///
/// 要移除的控制器 Id。
/// 如果成功移除返回 true,否则返回 false(比如未找到该 Id)。
public bool RemoveLightController(int id)
{
bool result = false;
lock (_sync)
{
var e = LightControllers.FirstOrDefault(c => c.Id == id);
if (e != null)
result = LightControllers.Remove(e);
// 重新按 Id 排序并从 1 开始重新编号,以保持连续性
int no = 1;
var sorted = LightControllers.OrderBy(c => c.Id).ToList();
foreach (var c in sorted)
{
c.Id = no;
no++;
}
LightControllers.Clear();
foreach (var c in sorted)
{
LightControllers.Add(c);
}
}
FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
return result;
}
///
/// 判断是否包含指定 Id 的光源控制器。
///
/// 控制器 Id。
/// 存在返回 true,否则返回 false。
public bool ContainsLightController(int id) { lock (_sync) { return LightControllers.Any(c => c.Id == id); } }
///
/// 获取所有光源通道的只读集合,按 GlobalIndex 升序返回。
///
/// 按 GlobalIndex 排序的 只读集合。
public IReadOnlyCollection GetAllLightChannels()
{
lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).OrderBy(ch => ch.GlobalIndex).ToList().AsReadOnly(); }
}
///
/// 根据全局通道索引获取单个通道配置。
///
/// 通道的全局索引(GlobalIndex)。
/// 匹配的 实例,找不到则返回 null。
public ChannelConfig GetLightChannelByGlobalIndex(int globalIndex)
{
lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).FirstOrDefault(ch => ch.GlobalIndex == globalIndex); }
}
///
/// 判断是否存在指定全局通道索引的通道配置。
///
/// 全局通道索引。
/// 存在返回 true,否则返回 false。
public bool ContainsLightChannelByGlobalIndex(int globalIndex)
{
lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).Any(ch => ch.GlobalIndex == globalIndex); }
}
///
/// 更新指定全局通道的默认亮度(DefaultBrightness),并持久化光源控制器配置。
///
/// 目标通道的全局索引(GlobalIndex)。
/// 要设置的亮度值。
/// 更新成功返回 true;找不到对应通道返回 false。
public bool UpdateChannelDefaultBrightness(int globalIndex, int brightness)
{
lock (_sync)
{
var ch = LightControllers.SelectMany(c => c.ChannelConfigs).FirstOrDefault(x => x.GlobalIndex == globalIndex);
if (ch == null) return false;
ch.DefaultBrightness = brightness;
FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
return true;
}
}
#endregion
#region Plc Addresses
public PlcAddressConfig GetPlcAddresses() { lock (_sync) { return PlcAddressConfig; } }
#endregion
#region ScrewDriver config (single device)
///
/// 获取电批配置(单设备)。
///
/// 当前的 ,若未加载则返回 null。
public ScrewDriverConfig GetScrewDriverConfig()
{
lock (_sync) { return _screwDriverConfig; }
}
///
/// 设置并持久化电批配置(单设备)。
///
/// 新的配置对象,不能为空。
public void SetScrewDriverConfig(ScrewDriverConfig cfg)
{
if (cfg == null) throw new ArgumentNullException(nameof(cfg));
lock (_sync)
{
_screwDriverConfig = cfg;
FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
}
}
///
/// 仅将当前内存中的电批配置保存到文件。
///
public void SaveScrewDriverConfig()
{
lock (_sync)
{
if (_screwDriverConfig != null)
FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
}
}
#endregion
#region Screw Feeders (material)
///
/// 获取所有螺丝供料器配置的只读集合。
///
public IReadOnlyCollection GetAllScrewFeeders() { lock (_sync) { return ScrewFeeders.ToList().AsReadOnly(); } }
///
/// 根据 Id 获取单个螺丝供料器配置。
///
public ScrewFeederInfo GetScrewFeeder(Guid id) { lock (_sync) { return ScrewFeeders.FirstOrDefault(s => s.Id == id); } }
///
/// 新增或更新螺丝供料器配置。
/// 新增时若未指定 FeederNumber 则分配为当前数量+1。
///
public ScrewFeederInfo AddOrUpdateScrewFeeder(ScrewFeederInfo feeder)
{
if (feeder == null) return null;
lock (_sync)
{
var exist = ScrewFeeders.FirstOrDefault(f => f.Id == feeder.Id);
if (exist != null)
{
var idx = ScrewFeeders.IndexOf(exist);
ScrewFeeders[idx] = feeder;
}
else
{
if (feeder.FeederNumber <= 0) feeder.FeederNumber = ScrewFeeders.Count + 1;
ScrewFeeders.Add(feeder);
}
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
}
return feeder;
}
///
/// 移除螺丝供料器配置。
///
public bool RemoveScrewFeeder(Guid id)
{
bool result = false;
lock (_sync)
{
var e = ScrewFeeders.FirstOrDefault(s => s.Id == id);
if (e != null) result = ScrewFeeders.Remove(e);
}
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
return result;
}
public bool ContainsScrewFeeder(Guid id) { lock (_sync) { return ScrewFeeders.Any(s => s.Id == id); } }
// event for low level alarm
public event Action ScrewFeederLowLevelAlarmTriggered;
///
/// 获取指定供料器编号的剩余螺丝数量(找不到返回 -1)
///
public int GetRemainingCountByFeederNumber(int feederNumber)
{
lock (_sync)
{
var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
if (f == null) return -1;
return f.RemainingCount;
}
}
///
/// 获取指定供料器编号的低量报警状态(找不到返回 false)
///
public bool GetLowLevelAlarmStatusByFeederNumber(int feederNumber)
{
lock (_sync)
{
var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
if (f == null) return false;
return f.IsLowLevelAlarmActive;
}
}
// helper: check and raise low level alarm when necessary
private void CheckAndTriggerLowLevelAlarm(ScrewFeederInfo f)
{
if (f == null) return;
if (f.LowLevelAlarmEnabled && f.RemainingCount <= f.LowLevelThreshold)
{
if (!f.IsLowLevelAlarmActive)
{
f.IsLowLevelAlarmActive = true;
try
{
ScrewFeederLowLevelAlarmTriggered?.Invoke(f.Clone());
}
catch { }
}
}
else
{
if (f.IsLowLevelAlarmActive)
{
f.IsLowLevelAlarmActive = false;
}
}
}
///
/// 为指定供料器编号递减指定数量,若数量不足返回 false
///
public bool DecrementScrewCountByFeederNumber(int feederNumber, int decrement = 1)
{
lock (_sync)
{
var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
if (f == null) return false;
if (decrement <= 0) decrement = 1;
if (f.RemainingCount < decrement) return false;
f.RemainingCount -= decrement;
// check alarm
CheckAndTriggerLowLevelAlarm(f);
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
return true;
}
}
///
/// 清除指定供料器编号的螺丝信息(批次号置空,剩余数量置0)
///
public void ClearScrewFeederByNumber(int feederNumber)
{
lock (_sync)
{
var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
if (f == null) return;
f.BatchNumber = string.Empty;
f.RemainingCount = 0;
// check alarm
CheckAndTriggerLowLevelAlarm(f);
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
}
}
///
/// 为指定供料器编号设置批次号,并在原有剩余数量上增加一包(PackSize)
///
public void SetBatchForFeederNumber(int feederNumber, string batchNumber)
{
if (string.IsNullOrWhiteSpace(batchNumber)) return;
// capture values under lock, then record to DB outside lock
ScrewFeederInfo target = null;
int remainingAfter = 0;
int packSize = 0;
string feederName = null;
lock (_sync)
{
var f = ScrewFeeders.FirstOrDefault(s => s.FeederNumber == feederNumber);
if (f == null) return;
f.BatchNumber = batchNumber;
f.RemainingCount += Math.Max(0, f.PackSize);
// prepare capture values
target = f;
remainingAfter = f.RemainingCount;
packSize = f.PackSize;
feederName = f.Name;
// check alarm
CheckAndTriggerLowLevelAlarm(f);
FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
}
try
{
var record = new ScrewFeederBatchRecord
{
BatchNumber = batchNumber,
PackSize = packSize,
ChangeTime = DateTime.Now,
RemainingCount = remainingAfter,
FeederNumber = feederNumber,
FeederName = feederName
};
// try get operator name from system database service if available
try
{
var user = _systemDatabaseService?.GetCurrentUser();
if (user != null)
record.OperatorName = user.UserName;
}
catch
{
// ignore getting user failure
}
// fire-and-forget recording (ConfigService will forward to DB service if set)
_ = RecordScrewFeederBatchAsync(record);
}
catch
{
// ignore any error creating/recording the batch record
}
}
#endregion
#region 用户登录刷卡器
///
/// 获取刷卡器配置
///
///
public SerialPortConfig GetCardReaderConfig()
{
lock (_sync)
{
if (_cardReaderConfig != null)
return _cardReaderConfig;
if (File.Exists(ConfigPaths.CardReaderConfigurationPath))
{
try
{
_cardReaderConfig = FileHelper.ReadJsonFile(ConfigPaths.CardReaderConfigurationPath);
}
catch
{
// 若读取失败,创建默认配置并覆盖文件(与项目中其他配置策略一致)
_cardReaderConfig = new SerialPortConfig();
try { FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath); } catch { }
}
}
else
{
_cardReaderConfig = new SerialPortConfig();
try { FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath); } catch { }
}
return _cardReaderConfig;
}
}
///
/// 保存刷卡器配置
///
///
public void SaveCardReaderConfig(SerialPortConfig config)
{
if (config == null) return;
lock (_sync)
{
_cardReaderConfig = config;
try
{
FileHelper.WriteJsonFile(_cardReaderConfig, ConfigPaths.CardReaderConfigurationPath);
}
catch
{
// 忽略持久化错误(与项目中其它保存方法一致),可在需要时添加日志记录
}
}
}
#endregion
///
/// 释放资源并保存当前内存中的所有配置到文件。
///
public void Dispose()
{
SaveAll();
GC.SuppressFinalize(this);
}
}
}