Compare commits
No commits in common. "41ac47205df510a76f672aae9a6aae708c3051b3" and "80593d2e183c48d2489ba8f855b9486fbcf0982c" have entirely different histories.
41ac47205d
...
80593d2e18
|
@ -1,63 +0,0 @@
|
||||||
###############################################################################
|
|
||||||
# Set default behavior to automatically normalize line endings.
|
|
||||||
###############################################################################
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set default behavior for command prompt diff.
|
|
||||||
#
|
|
||||||
# This is need for earlier builds of msysgit that does not have it on by
|
|
||||||
# default for csharp files.
|
|
||||||
# Note: This is only used by command line
|
|
||||||
###############################################################################
|
|
||||||
#*.cs diff=csharp
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Set the merge driver for project and solution files
|
|
||||||
#
|
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
|
||||||
# these files as binary and thus will always conflict and require user
|
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
|
||||||
###############################################################################
|
|
||||||
#*.sln merge=binary
|
|
||||||
#*.csproj merge=binary
|
|
||||||
#*.vbproj merge=binary
|
|
||||||
#*.vcxproj merge=binary
|
|
||||||
#*.vcproj merge=binary
|
|
||||||
#*.dbproj merge=binary
|
|
||||||
#*.fsproj merge=binary
|
|
||||||
#*.lsproj merge=binary
|
|
||||||
#*.wixproj merge=binary
|
|
||||||
#*.modelproj merge=binary
|
|
||||||
#*.sqlproj merge=binary
|
|
||||||
#*.wwaproj merge=binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# behavior for image files
|
|
||||||
#
|
|
||||||
# image files are treated as binary by default.
|
|
||||||
###############################################################################
|
|
||||||
#*.jpg binary
|
|
||||||
#*.png binary
|
|
||||||
#*.gif binary
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# diff behavior for common document formats
|
|
||||||
#
|
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
|
||||||
# entries below.
|
|
||||||
###############################################################################
|
|
||||||
#*.doc diff=astextplain
|
|
||||||
#*.DOC diff=astextplain
|
|
||||||
#*.docx diff=astextplain
|
|
||||||
#*.DOCX diff=astextplain
|
|
||||||
#*.dot diff=astextplain
|
|
||||||
#*.DOT diff=astextplain
|
|
||||||
#*.pdf diff=astextplain
|
|
||||||
#*.PDF diff=astextplain
|
|
||||||
#*.rtf diff=astextplain
|
|
||||||
#*.RTF diff=astextplain
|
|
|
@ -1,16 +1,2 @@
|
||||||
.git/
|
|
||||||
.idea/
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
##
|
|
||||||
## Visual Studio Code
|
|
||||||
##
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
=======
|
|
||||||
.git/
|
.git/
|
||||||
.idea/
|
.idea/
|
||||||
>>>>>>> 80593d2e183c48d2489ba8f855b9486fbcf0982c
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<AvaloniaVersion>11.0.2</AvaloniaVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
|
@ -1,67 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.9.34714.143
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserUI", "DispenserUI\DispenserUI.csproj", "{E08E72A8-4334-4871-AAE0-244B16ADE556}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserDesktop", "DispenserDesktop\DispenserDesktop.csproj", "{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserCommon", "DispenserCommon\DispenserCommon.csproj", "{A8587675-8F8D-4F3E-8809-DDF77743FEFD}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserCommon", "DispenserCore\DispenserCore.csproj", "{2150E333-8FDC-42A3-9474-1A3956D46DE8}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DispenserDriver", "DispenserDriver", "{42401CD7-B4C8-4F06-AD46-5D987CF4CA53}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserHal", "DispenserHal\DispenserHal.csproj", "{78E3094F-66F1-470A-BA89-37F43E7F3737}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserDriver.CameraMV", "DispenserDriver.CameraMV\DispenserDriver.CameraMV.csproj", "{FFED5A1A-44B8-4C89-B659-9B86A3FF800C}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispenserAlgorithm", "DispenserAlgorithm\DispenserAlgorithm.csproj", "{921E3C5C-1347-402E-9838-3B30170F7489}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{E08E72A8-4334-4871-AAE0-244B16ADE556}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E08E72A8-4334-4871-AAE0-244B16ADE556}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E08E72A8-4334-4871-AAE0-244B16ADE556}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E08E72A8-4334-4871-AAE0-244B16ADE556}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E08E72A8-4334-4871-AAE0-244B16ADE556}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A52ACF73-71A1-48A6-9B7F-E06761B26AC9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{A8587675-8F8D-4F3E-8809-DDF77743FEFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{A8587675-8F8D-4F3E-8809-DDF77743FEFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{A8587675-8F8D-4F3E-8809-DDF77743FEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{A8587675-8F8D-4F3E-8809-DDF77743FEFD}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A8587675-8F8D-4F3E-8809-DDF77743FEFD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{78E3094F-66F1-470A-BA89-37F43E7F3737}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{78E3094F-66F1-470A-BA89-37F43E7F3737}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{78E3094F-66F1-470A-BA89-37F43E7F3737}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{78E3094F-66F1-470A-BA89-37F43E7F3737}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{FFED5A1A-44B8-4C89-B659-9B86A3FF800C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FFED5A1A-44B8-4C89-B659-9B86A3FF800C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FFED5A1A-44B8-4C89-B659-9B86A3FF800C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FFED5A1A-44B8-4C89-B659-9B86A3FF800C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{921E3C5C-1347-402E-9838-3B30170F7489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{921E3C5C-1347-402E-9838-3B30170F7489}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{921E3C5C-1347-402E-9838-3B30170F7489}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{921E3C5C-1347-402E-9838-3B30170F7489}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{FFED5A1A-44B8-4C89-B659-9B86A3FF800C} = {42401CD7-B4C8-4F06-AD46-5D987CF4CA53}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,29 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<RootNamespace>DispenserAlgorithm</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Stateless" Version="5.15.0"/>
|
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="DispenserAlgorithms.Halcon">
|
|
||||||
<HintPath>DispenserAlgorithms.Halcon.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="DispenserVision.Halcon">
|
|
||||||
<HintPath>..\DispenserDesktop\Libs\DispenserVision.Halcon.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="halcondotnet">
|
|
||||||
<HintPath>halcondotnet.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -1,46 +0,0 @@
|
||||||
using AspectInjector.Broker;
|
|
||||||
using DispenserCommon.Utils;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Aop;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于捕获方法执行过程中的异常,并弹窗
|
|
||||||
/// </summary>
|
|
||||||
[Aspect(Scope.Global)]
|
|
||||||
[Injection(typeof(AlertWhenException))]
|
|
||||||
public class AlertWhenException(string title = "异常提示", string contentTitle = "") : Attribute
|
|
||||||
{
|
|
||||||
public AlertWhenException() : this("异常提示")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过AOP实现方法执行前后的时间消耗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <param name="hostType"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="triggers"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Advice(Kind.Around)]
|
|
||||||
public object Around([Argument(Source.Name)] string name,
|
|
||||||
[Argument(Source.Arguments)] object[] args,
|
|
||||||
[Argument(Source.Type)] Type hostType,
|
|
||||||
[Argument(Source.Target)] Func<object[], object> target,
|
|
||||||
[Argument(Source.Triggers)] Attribute[] triggers)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = target(args);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, $"方法 {name} 执行异常");
|
|
||||||
MessageBoxHelper.Error(e.Message, contentTitle, title, false);
|
|
||||||
return null!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using AspectInjector.Broker;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Aop;
|
|
||||||
|
|
||||||
[Aspect(Scope.Global)]
|
|
||||||
[Injection(typeof(AsyncOperation))]
|
|
||||||
public class AsyncOperation(string name) : Attribute
|
|
||||||
{
|
|
||||||
public string Name { get; set; } = name;
|
|
||||||
|
|
||||||
public AsyncOperation() : this("")
|
|
||||||
{
|
|
||||||
Name = "";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using System.Diagnostics;
|
|
||||||
using AspectInjector.Broker;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Aop;
|
|
||||||
|
|
||||||
[Aspect(Scope.Global)]
|
|
||||||
[Injection(typeof(ConsumeTime))]
|
|
||||||
public class ConsumeTime(string title) : Attribute
|
|
||||||
{
|
|
||||||
public ConsumeTime() : this("")
|
|
||||||
{
|
|
||||||
Title = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Title { get; set; } = title;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过AOP实现方法执行前后的时间消耗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <param name="hostType"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="triggers"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Advice(Kind.Around)]
|
|
||||||
public object Around([Argument(Source.Name)] string name,
|
|
||||||
[Argument(Source.Arguments)] object[] args,
|
|
||||||
[Argument(Source.Type)] Type hostType,
|
|
||||||
[Argument(Source.Target)] Func<object[], object> target,
|
|
||||||
[Argument(Source.Triggers)] Attribute[] triggers)
|
|
||||||
{
|
|
||||||
var sw = Stopwatch.StartNew();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = target(args);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
sw.Stop();
|
|
||||||
Log.Information(
|
|
||||||
$"方法 {(Title != "" ? Title : name)} 执行时间:{sw.Elapsed.TotalMilliseconds}ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using AspectInjector.Broker;
|
|
||||||
using DispenserCommon.Utils;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Aop;
|
|
||||||
|
|
||||||
[Aspect(Scope.Global)]
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
[Injection(typeof(GlobalTry), Inherited = true)]
|
|
||||||
public class GlobalTry : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 通过AOP实现方法执行前后的时间消耗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="method"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Advice(Kind.Around, Targets = Target.Method)]
|
|
||||||
public object? HandleMethod([Argument(Source.Name)] string name,
|
|
||||||
[Argument(Source.Arguments)] object[] args,
|
|
||||||
[Argument(Source.Target)] Func<object[], object> target,
|
|
||||||
[Argument(Source.Metadata)] MethodBase method)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = target(args);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, $"方法 {name} 执行异常: {e.Message}");
|
|
||||||
ToastUtil.Error("操作异常: " + e.Message);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
using AspectInjector.Broker;
|
|
||||||
using DispenserCommon.DTO;
|
|
||||||
using DispenserCommon.Enums;
|
|
||||||
using DispenserCommon.Events;
|
|
||||||
using DispenserCommon.Utils;
|
|
||||||
using DispenserUI.Exceptions;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Aop;
|
|
||||||
|
|
||||||
[Aspect(Scope.Global)]
|
|
||||||
[Injection(typeof(Operation))]
|
|
||||||
public class Operation(string name) : Attribute
|
|
||||||
{
|
|
||||||
public string Name { get; set; } = name;
|
|
||||||
|
|
||||||
public Operation() : this("")
|
|
||||||
{
|
|
||||||
Name = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过AOP实现方法执行过程拦截
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="triggers"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Advice(Kind.Around, Targets = Target.Method)]
|
|
||||||
public object? Around(
|
|
||||||
[Argument(Source.Arguments)] object[] args,
|
|
||||||
[Argument(Source.Target)] Func<object[], object> target,
|
|
||||||
[Argument(Source.Triggers)] Attribute[] triggers)
|
|
||||||
{
|
|
||||||
var trigger = (Operation)triggers[0];
|
|
||||||
|
|
||||||
var log = new ActionLog
|
|
||||||
{
|
|
||||||
Name = trigger.Name,
|
|
||||||
Params = args
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Log.Information($"正在执行: {trigger.Name}");
|
|
||||||
return target(args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (e is BizException { Level: ExceptionLevel.NORMAL })
|
|
||||||
{
|
|
||||||
ToastUtil.Error($"{trigger.Name}操作失败: {e.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Exception = e;
|
|
||||||
Log.Error($"{trigger.Name}操作失败: {e.Message}");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
EventBus<ActionLog>.Publish(EventType.OperationLog, log);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DispenserCommon.Atrributes;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
|
||||||
public class BlockTask(string name) : Attribute
|
|
||||||
{
|
|
||||||
public string Name { get; } = name;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DispenserCommon.Atrributes;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class Hide : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
namespace DispenserCommon.Atrributes;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class Property : Attribute
|
|
||||||
{
|
|
||||||
public bool IsReadOnly { get; set; } = false;
|
|
||||||
|
|
||||||
// 字符串格式
|
|
||||||
public string? Format { get; set; }
|
|
||||||
|
|
||||||
// 显示控件的宽
|
|
||||||
public double Width { get; set; }
|
|
||||||
|
|
||||||
// 显示控件的高
|
|
||||||
public double Height { get; set; }
|
|
||||||
|
|
||||||
public double Max { get; set; }
|
|
||||||
|
|
||||||
public double Min { get; set; }
|
|
||||||
|
|
||||||
public string Group { get; set; }
|
|
||||||
|
|
||||||
public bool IsPassword { get; set; }
|
|
||||||
|
|
||||||
public string Variable { get; set; }
|
|
||||||
|
|
||||||
public int Axis { get; set; } = -1;
|
|
||||||
|
|
||||||
public int Index { get; set; } = -1;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace DispenserCommon.Constant;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 这里管理MQTT 所有的topic
|
|
||||||
/// </summary>
|
|
||||||
public class Topics
|
|
||||||
{
|
|
||||||
// 锁机
|
|
||||||
public const string Locked = "device/{deviceId}/locked";
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using System.Globalization;
|
|
||||||
using Avalonia.Data.Converters;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Converter;
|
|
||||||
|
|
||||||
public class StringNullOrEmptyToVisibilityConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
var str = value as string;
|
|
||||||
return string.IsNullOrEmpty(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using DispenserCommon.Events;
|
|
||||||
using DispenserCommon.Utils;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCommon.DB;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 在系统启动的时候记进行数据库初始化校验
|
|
||||||
/// </summary>
|
|
||||||
public class DatabaseInitializer
|
|
||||||
{
|
|
||||||
private static readonly SqliteHelper Sqlite = ServiceLocator.GetService<SqliteHelper>();
|
|
||||||
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
EventBus<string>.Publish(EventType.SetupNotify, "正在初始化数据库");
|
|
||||||
|
|
||||||
// 扫描所有带有[Table]特性的类
|
|
||||||
var tables = GetAssemblies()
|
|
||||||
.SelectMany(a => a.GetTypes()
|
|
||||||
.Where(t => t.GetCustomAttributes(typeof(TableAttribute), true).Length > 0))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
|
|
||||||
tables.ForEach(table =>
|
|
||||||
{
|
|
||||||
// 判断当前的表是否存在
|
|
||||||
var tableName = table.GetCustomAttribute<TableAttribute>()?.Name ?? table.Name;
|
|
||||||
|
|
||||||
var tableInfo = Sqlite.GetTableInfo(tableName);
|
|
||||||
|
|
||||||
if (!tableInfo.Any())
|
|
||||||
{
|
|
||||||
Sqlite.CreateTable(table);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 读取当前类的变量是否新增了属性
|
|
||||||
var properties = table.GetProperties();
|
|
||||||
var colNames = tableInfo.Select(col => col.Name.ToUpper()).ToHashSet();
|
|
||||||
|
|
||||||
foreach (var property in properties)
|
|
||||||
{
|
|
||||||
var colName = property.GetCustomAttribute<ColumnAttribute>()?.Name ?? property.Name;
|
|
||||||
|
|
||||||
// 统一转为大写进行判断
|
|
||||||
if (colNames.Contains(colName.ToUpper())) continue;
|
|
||||||
// 重新进行DDL时,会自动的判断是否存在新增的列,如果有则自动进行新增
|
|
||||||
Sqlite.CreateTable(table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static IEnumerable<Assembly> GetAssemblies()
|
|
||||||
{
|
|
||||||
var assemblies = new List<Assembly>();
|
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
||||||
{
|
|
||||||
var name = assembly.GetName().Name;
|
|
||||||
if (name != null && name.ToLower().Contains("dispenser")) GetReferenceAssemblies(assembly, assemblies);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetReferenceAssemblies(Assembly assembly, ICollection<Assembly> assemblies)
|
|
||||||
{
|
|
||||||
foreach (var assemblyName in assembly.GetReferencedAssemblies())
|
|
||||||
{
|
|
||||||
var name = assemblyName.Name;
|
|
||||||
if (name != null && name.ToLower().Contains("dispenser"))
|
|
||||||
{
|
|
||||||
var ass = Assembly.Load(assemblyName);
|
|
||||||
if (assemblies.Contains(ass)) continue;
|
|
||||||
assemblies.Add(ass);
|
|
||||||
GetReferenceAssemblies(ass, assemblies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,228 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using DispenserCommon.DTO;
|
|
||||||
using DispenserCommon.Ioc;
|
|
||||||
using Masuit.Tools;
|
|
||||||
using Masuit.Tools.Systems;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCommon.DB;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// SQLite 数据库ORM工具类
|
|
||||||
/// </summary>
|
|
||||||
[Component]
|
|
||||||
public class SqliteHelper
|
|
||||||
{
|
|
||||||
// 默认的数据库密码
|
|
||||||
private const string Password = "88888888";
|
|
||||||
private readonly SQLiteConnection _db;
|
|
||||||
|
|
||||||
public SqliteHelper()
|
|
||||||
{
|
|
||||||
var profile = Environment.GetEnvironmentVariable("USERPROFILE");
|
|
||||||
var path = Path.Combine(profile, "dispenser", "dispenser.db");
|
|
||||||
|
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(path)!))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
|
||||||
|
|
||||||
// 将文件复模板数据库复制到目标目录下
|
|
||||||
var template = Path.Combine(Environment.CurrentDirectory, "dispenser.db");
|
|
||||||
File.Copy(template, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_db = new SQLiteConnection(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插入数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">待插入的数据</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public int Insert<T>(T item)
|
|
||||||
{
|
|
||||||
var id = item?.GetType().GetProperty("Id");
|
|
||||||
if (id != null && id.CanWrite) id.SetValue(item, SnowFlakeNew.LongId.ToString());
|
|
||||||
|
|
||||||
var createTime = item?.GetType().GetProperty("CreateTime");
|
|
||||||
if (createTime != null && createTime.CanWrite) createTime.SetValue(item, DateTime.Now);
|
|
||||||
|
|
||||||
|
|
||||||
return _db.Insert(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">待更新的数据</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public int Update<T>(T item)
|
|
||||||
{
|
|
||||||
var updateTime = item?.GetType().GetProperty("UpdateTime");
|
|
||||||
if (updateTime != null && updateTime.CanWrite) updateTime.SetValue(item, DateTime.Now);
|
|
||||||
|
|
||||||
return _db.Update(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">待删除数据的ID</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public int DeleteById<T>(object id) where T : new()
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var tableName = type.GetCustomAttribute<TableAttribute>()!.Name ?? type.Name;
|
|
||||||
|
|
||||||
return _db.Execute($"delete from {tableName} where id = {id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">待删除数据的对象</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public int Delete<T>(T item)
|
|
||||||
{
|
|
||||||
return _db.Delete<T>(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据ID获取数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">数据ID</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public T GetById<T>(object id) where T : new()
|
|
||||||
{
|
|
||||||
return _db.Get<T>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查询数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql">查询语句</param>
|
|
||||||
/// <param name="args">查询参数</param>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public List<T> Query<T>(string sql, params object[] args) where T : new()
|
|
||||||
{
|
|
||||||
return _db.Query<T>(sql, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查询所有数据
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
|
||||||
public List<T> ListAll<T>() where T : new()
|
|
||||||
{
|
|
||||||
return _db.Table<T>().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public T SaveOrUpdate<T>(T item) where T : new()
|
|
||||||
{
|
|
||||||
var id = item?.GetType().GetProperty("Id");
|
|
||||||
if (id != null && id.GetValue(item).IsNullOrEmpty())
|
|
||||||
// 插入
|
|
||||||
Insert(item);
|
|
||||||
else
|
|
||||||
// 否则是更新操作
|
|
||||||
Update(item);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 执行SQL语句
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sql">SQL语句</param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public int Execute(string sql, params object[] args)
|
|
||||||
{
|
|
||||||
return _db.Execute(sql, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前的表信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tableName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public List<SQLiteConnection.ColumnInfo> GetTableInfo(string tableName)
|
|
||||||
{
|
|
||||||
return _db.GetTableInfo(tableName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建表
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entity"></param>
|
|
||||||
public void CreateTable(Type entity)
|
|
||||||
{
|
|
||||||
_db.CreateTable(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 分页查询结果
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="page"></param>
|
|
||||||
/// <param name="pageSize"></param>
|
|
||||||
/// <param name="sql"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Page<T> Page<T>(int page, int pageSize, string sql, params object[] args) where T : new()
|
|
||||||
{
|
|
||||||
var countSql = "select count(*) from ( " + sql + " ) as c";
|
|
||||||
var total = _db.ExecuteScalar<int>(countSql, args);
|
|
||||||
var data = Query<T>(sql + " limit " + (page - 1) * pageSize + "," + pageSize, args);
|
|
||||||
return new Page<T>
|
|
||||||
{
|
|
||||||
CurrentPage = page,
|
|
||||||
PageSize = pageSize,
|
|
||||||
Total = total,
|
|
||||||
Pages = total / pageSize + (total % pageSize == 0 ? 0 : 1),
|
|
||||||
Data = data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 批量插入
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="objects"></param>
|
|
||||||
/// <param name="runInTransaction"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public void BatchInsert<T>(IEnumerable<T> objects, bool runInTransaction = false) where T : new()
|
|
||||||
{
|
|
||||||
if (runInTransaction)
|
|
||||||
{
|
|
||||||
_db.RunInTransaction((Action)(() =>
|
|
||||||
{
|
|
||||||
foreach (object obj in objects)
|
|
||||||
Insert(obj);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (object obj in objects)
|
|
||||||
Insert(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新指定字段
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id"></param>
|
|
||||||
/// <param name="field"></param>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public void UpdateFieldById<T>(object? id, string field, object? value) where T : new()
|
|
||||||
{
|
|
||||||
var type = typeof(T);
|
|
||||||
var tableName = type.GetCustomAttribute<TableAttribute>()!.Name ?? type.Name;
|
|
||||||
|
|
||||||
var sql = $"update {tableName} set {field} = ? where id = ?";
|
|
||||||
|
|
||||||
_db.Execute(sql, value, id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
namespace DispenserCommon.DTO;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过AOP方式拦截获取用户操作日志
|
|
||||||
/// </summary>
|
|
||||||
public class ActionLog
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public object[] Params { get; set; }
|
|
||||||
|
|
||||||
public Exception Exception { get; set; }
|
|
||||||
|
|
||||||
public DateTime OperateTime { get; set; } = DateTime.Now;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
namespace DispenserCommon.DTO;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
public class LogMessage(string message)
|
|
||||||
{
|
|
||||||
public LogMessage(string message, LogEventLevel level) : this(message)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
Level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime Timestamp { get; set; } = DateTime.Now;
|
|
||||||
public string Message { get; set; } = message;
|
|
||||||
|
|
||||||
public LogEventLevel Level { get; set; } = LogEventLevel.Information;
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DispenserCommon.DTO;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 分页结果
|
|
||||||
/// </summary>
|
|
||||||
public class Page<T> : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
private int _total;
|
|
||||||
|
|
||||||
private int _pages;
|
|
||||||
|
|
||||||
private int _currentPage;
|
|
||||||
|
|
||||||
private List<T> _data = [];
|
|
||||||
|
|
||||||
private int _pageSize;
|
|
||||||
|
|
||||||
public int CurrentPage
|
|
||||||
{
|
|
||||||
get => _currentPage;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_currentPage = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int PageSize
|
|
||||||
{
|
|
||||||
get => _pageSize;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_pageSize = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Total
|
|
||||||
{
|
|
||||||
get => _total;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_total = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Pages
|
|
||||||
{
|
|
||||||
get => _pages;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_pages = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<T> Data
|
|
||||||
{
|
|
||||||
get => _data;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_data = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
namespace DispenserCommon.DTO;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// plc请求结果
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public class Result<T>
|
|
||||||
{
|
|
||||||
public Result()
|
|
||||||
{
|
|
||||||
Ok = true;
|
|
||||||
Code = 0;
|
|
||||||
Message = "成功";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result(T data)
|
|
||||||
{
|
|
||||||
Ok = true;
|
|
||||||
Code = 0;
|
|
||||||
Message = "成功";
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result(int code, string message)
|
|
||||||
{
|
|
||||||
Ok = false;
|
|
||||||
Code = code;
|
|
||||||
Message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result(int code, string message, Exception? exception)
|
|
||||||
{
|
|
||||||
Ok = false;
|
|
||||||
Code = code;
|
|
||||||
Message = message;
|
|
||||||
Exception = exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Ok { get; set; }
|
|
||||||
|
|
||||||
public int Code { get; set; }
|
|
||||||
|
|
||||||
public T? Data { get; set; }
|
|
||||||
|
|
||||||
public string Message { get; set; }
|
|
||||||
|
|
||||||
public Exception? Exception { get; set; }
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<LangVersion>preview</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="AspectInjector" Version="2.8.3-pre3"/>
|
|
||||||
<PackageReference Include="Avalonia" Version="11.0.10" />
|
|
||||||
<PackageReference Include="Masuit.Tools.Core" Version="2.6.9.9"/>
|
|
||||||
<PackageReference Include="MathNet.Numerics" Version="6.0.0-beta1"/>
|
|
||||||
<PackageReference Include="MessageBox.Avalonia" Version="3.1.5.1"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0"/>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0"/>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
|
||||||
<PackageReference Include="Quartz" Version="3.8.1"/>
|
|
||||||
<PackageReference Include="ReactiveUI" Version="18.3.1" />
|
|
||||||
<PackageReference Include="Serilog" Version="3.1.1"/>
|
|
||||||
<PackageReference Include="Serilog.Exceptions" Version="8.4.0"/>
|
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1"/>
|
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.1-dev-00972"/>
|
|
||||||
<PackageReference Include="sqlite-net" Version="1.6.292"/>
|
|
||||||
<PackageReference Include="sqlite-net-sqlcipher" Version="1.9.172"/>
|
|
||||||
<PackageReference Include="Stateless" Version="5.15.0"/>
|
|
||||||
<PackageReference Include="System.Drawing.Common" Version="8.0.0"/>
|
|
||||||
<PackageReference Include="System.IO.Ports" Version="8.0.0"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,13 +0,0 @@
|
||||||
namespace DispenserCommon.Enums;
|
|
||||||
|
|
||||||
public enum BinCoordinateTransformStrategyEnum
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 基于角度
|
|
||||||
/// </summary>
|
|
||||||
ByAngel,
|
|
||||||
/// <summary>
|
|
||||||
/// 基于矩阵
|
|
||||||
/// </summary>
|
|
||||||
ByMatrix
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DispenserCommon.Enums;
|
|
||||||
|
|
||||||
public enum ExceptionLevel : int
|
|
||||||
{
|
|
||||||
NORMAL,
|
|
||||||
WARN,
|
|
||||||
ERROR,
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DispenserCommon.Enums;
|
|
||||||
|
|
||||||
public enum ScannerTypeEnum
|
|
||||||
{
|
|
||||||
Wafer,
|
|
||||||
Pcb,
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DispenserCommon.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于声明当前方法为事件处理器
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
|
||||||
public class EventAction(params EventType[] types) : Attribute
|
|
||||||
{
|
|
||||||
public EventType[] Types => types;
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 事件总线
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
public abstract class EventBus<T>
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<EventType, List<Delegate>> Subscribers = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加订阅
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
public static void AddEventHandler(EventType type, Delegate action)
|
|
||||||
{
|
|
||||||
if (Subscribers.TryGetValue(type, out var subscribers))
|
|
||||||
{
|
|
||||||
var any = subscribers.Any(item => item.Equals(action));
|
|
||||||
if (!any) subscribers.Add(action);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Subscribers.Add(type, [action]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除订阅逻辑
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">事件类型</param>
|
|
||||||
/// <param name="action">回调方法</param>
|
|
||||||
public static void RemoveEventHandler(EventType type, Delegate action)
|
|
||||||
{
|
|
||||||
if (!Subscribers.TryGetValue(type, out var handlers)) return;
|
|
||||||
|
|
||||||
handlers.Remove(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 发布事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
public static void Publish(EventType type, T data)
|
|
||||||
{
|
|
||||||
if (!Subscribers.TryGetValue(type, out var subscribers)) return;
|
|
||||||
|
|
||||||
// 创建一个副本,避免在回调中修改订阅列表导致迭代异常
|
|
||||||
var actions = subscribers.ToList();
|
|
||||||
|
|
||||||
foreach (var action in actions)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
action.DynamicInvoke(type, data);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DispenserCommon.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于声明当前类为事件监听
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class EventListener(string name = "") : Attribute
|
|
||||||
{
|
|
||||||
private string Name => name;
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using DispenserCommon.Ioc;
|
|
||||||
using DispenserCommon.Utils;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过事件管理者的方式来扫描系统内所有添加了注解的事件订阅者,并注册到事件总线上
|
|
||||||
/// </summary>
|
|
||||||
public class EventManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 扫描所有带有 EventListener 注解的类,并注册到事件总线上
|
|
||||||
/// Action回调方法 为 所有带有 EventAction 注解的方法
|
|
||||||
/// 方法必须为两个参数的委托,第一个参数为事件类型,第二个参数为事件数据
|
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public static void RegListeners()
|
|
||||||
{
|
|
||||||
var listeners = AppDomain.CurrentDomain.GetAssemblies()
|
|
||||||
.SelectMany(a => a.GetTypes()
|
|
||||||
.Where(t => t.GetCustomAttributes(typeof(EventListener), true).Length > 0
|
|
||||||
|| t.GetCustomAttributes(typeof(Component), true).Length > 0))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var listener in listeners)
|
|
||||||
{
|
|
||||||
// 扫描当前类中所有的带有 EventAction 特性的方法
|
|
||||||
var methods = listener
|
|
||||||
.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)
|
|
||||||
.Where(m => m.GetCustomAttributes(typeof(EventAction), true).Length > 0)
|
|
||||||
.ToList();
|
|
||||||
foreach (var method in methods)
|
|
||||||
{
|
|
||||||
var handler = method.GetCustomAttribute<EventAction>();
|
|
||||||
|
|
||||||
// 获取方法的参数类型
|
|
||||||
var parameters = method.GetParameters();
|
|
||||||
if (parameters.Length != 2) throw new Exception("订阅方法的参数必须为两个,第一个参数为事件类型,第二个参数为事件数据");
|
|
||||||
|
|
||||||
// 获取参数类型
|
|
||||||
var parameterType = parameters[1].ParameterType;
|
|
||||||
|
|
||||||
var types = handler?.Types;
|
|
||||||
if (types == null) continue;
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
var actionType = typeof(Action<,>).MakeGenericType(typeof(EventType), parameterType);
|
|
||||||
|
|
||||||
var instance = ServiceLocator.GetService(listener);
|
|
||||||
var @delegate = method.CreateDelegate(actionType, instance);
|
|
||||||
var eventBus = typeof(EventBus<>).MakeGenericType(parameterType);
|
|
||||||
var addEventHandler = eventBus.GetMethod("AddEventHandler");
|
|
||||||
addEventHandler?.Invoke(null, new object[] { type, @delegate });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过事件发布订阅模式实现系统各组件的解耦
|
|
||||||
/// 这里定义的是事件的驱动类型
|
|
||||||
/// </summary>
|
|
||||||
public enum EventType
|
|
||||||
{
|
|
||||||
// 系统初始化事件
|
|
||||||
[Description("系统初始化事件")] SetupNotify,
|
|
||||||
|
|
||||||
[Description("系统已经启动事件")] StartUp,
|
|
||||||
|
|
||||||
// 锁机事件
|
|
||||||
[Description("锁机事件")] LockEvent,
|
|
||||||
|
|
||||||
[Description("许可无效事件")] LicenseInvalidEvent,
|
|
||||||
|
|
||||||
[Description("异常信息")] Exception,
|
|
||||||
|
|
||||||
[Description("解决异常信息")] SolveFault,
|
|
||||||
|
|
||||||
[Description("操作日志")] OperationLog,
|
|
||||||
|
|
||||||
[Description("动打状态")] StrikeState,
|
|
||||||
|
|
||||||
[Description("生产作业过程状态信息")] ProductionState,
|
|
||||||
|
|
||||||
[Description("动打路径范围")] StrokePath,
|
|
||||||
|
|
||||||
[Description("传感器状态更新")] SensorState,
|
|
||||||
|
|
||||||
// 相机数据
|
|
||||||
[Description("测距仪数据")] CameraData,
|
|
||||||
|
|
||||||
//参数修改
|
|
||||||
[Description("参数修改")] ConfigChange,
|
|
||||||
|
|
||||||
// 晶环上料确认事件
|
|
||||||
[Description("晶环上料确认事件")] WaferLoadingConfirmed,
|
|
||||||
|
|
||||||
// 芯片缺料事件
|
|
||||||
[Description("芯片缺料事件")] ChipLacking,
|
|
||||||
|
|
||||||
// 晶环上料事件
|
|
||||||
[Description("晶环上料事件")] WaferLoading,
|
|
||||||
|
|
||||||
// 晶环旋转事件
|
|
||||||
[Description("晶环旋转事件")] WaferRotation,
|
|
||||||
|
|
||||||
// 晶环旋转失败事件
|
|
||||||
[Description("晶环旋转失败事件")] WaferRotationFailure,
|
|
||||||
|
|
||||||
// 晶环下料事件
|
|
||||||
[Description("晶环下料事件")] WaferUnloading,
|
|
||||||
|
|
||||||
// 基板上料确认事件
|
|
||||||
[Description("PCB上料确认事件")] PcbLoadingConfirmed,
|
|
||||||
|
|
||||||
// 基板上料事件
|
|
||||||
[Description("PCB上料事件")] PcbLoading,
|
|
||||||
|
|
||||||
// 基板下料事件
|
|
||||||
[Description("PCB下料事件")] PcbUnloading,
|
|
||||||
|
|
||||||
// 针刺组件移动到指定位置事件
|
|
||||||
[Description("针刺组件移动")] NeedleMoveTo,
|
|
||||||
|
|
||||||
// 晶环组件移动到自定位置事件
|
|
||||||
[Description("晶环组件移动")] WaferMoveTo,
|
|
||||||
|
|
||||||
// pcb上料完成事件
|
|
||||||
[Description("基板上料完成")] PcbLoadingCompleted,
|
|
||||||
|
|
||||||
// pcb下料完成事件
|
|
||||||
[Description("基板下料完成")] PcbUnloadingCompleted,
|
|
||||||
|
|
||||||
// 晶圆上料完成事件
|
|
||||||
[Description("基板上料完成")] WaferLoadingCompleted,
|
|
||||||
|
|
||||||
// 晶圆下料完成事件
|
|
||||||
[Description("基板下料完成")] WaferUnloadingCompleted,
|
|
||||||
|
|
||||||
// 整机回零完成事件
|
|
||||||
[Description("整机回零完成")] TotalResetCompleted,
|
|
||||||
|
|
||||||
[Description("基板扫描完成")] PcbScanCompleted,
|
|
||||||
|
|
||||||
[Description("晶圆扫描完成")] WaferScanCompleted,
|
|
||||||
|
|
||||||
[Description("整体扫描完成")] ScanCompleted,
|
|
||||||
|
|
||||||
[Description("步序信息")] StepInfo,
|
|
||||||
|
|
||||||
[Description("生产配置界面切换")] SettingChanged,
|
|
||||||
|
|
||||||
[Description("切换步骤")] StepChanged,
|
|
||||||
|
|
||||||
[Description("切换菜单")] MenuChanged,
|
|
||||||
|
|
||||||
[Description("菜单按钮切换事件")] PageChanged,
|
|
||||||
|
|
||||||
[Description("MQTT 接收到数据")] MqttMessage,
|
|
||||||
|
|
||||||
StartScan,
|
|
||||||
|
|
||||||
[Description("错误日志")] PopLog,
|
|
||||||
[Description("滚动日志")] RollingLog
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
using DispenserCommon.Enums;
|
|
||||||
using DispenserUI.Exceptions;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Exceptions;
|
|
||||||
|
|
||||||
public class AssertException(
|
|
||||||
string message,
|
|
||||||
string? code = null,
|
|
||||||
string? module = null,
|
|
||||||
Exception? exception = null,
|
|
||||||
ExceptionLevel? level = null) : BizException(message, code, module, exception, level)
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
using DispenserCommon.Enums;
|
|
||||||
|
|
||||||
namespace DispenserUI.Exceptions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 业务异常
|
|
||||||
/// </summary>
|
|
||||||
public class BizException(
|
|
||||||
string message,
|
|
||||||
string? code = null,
|
|
||||||
string? module = null,
|
|
||||||
Exception? exception = null,
|
|
||||||
ExceptionLevel? level = null) : ApplicationException(message, exception)
|
|
||||||
{
|
|
||||||
public ExceptionLevel Level { get; set; } = level ?? ExceptionLevel.NORMAL;
|
|
||||||
|
|
||||||
public string? Module { get; set; } = module;
|
|
||||||
|
|
||||||
public string? Code { get; set; } = code;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
using DispenserCommon.Enums;
|
|
||||||
using DispenserUI.Exceptions;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Exceptions;
|
|
||||||
|
|
||||||
public class CameraException(
|
|
||||||
string message,
|
|
||||||
string? code = null,
|
|
||||||
Exception? exception = null,
|
|
||||||
ExceptionLevel? level = null)
|
|
||||||
: BizException(message, code, "视觉相机异常", exception, level);
|
|
|
@ -1,15 +0,0 @@
|
||||||
using DispenserCommon.Enums;
|
|
||||||
using DispenserUI.Exceptions;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Exceptions;
|
|
||||||
|
|
||||||
public class ScannerException(
|
|
||||||
ScannerTypeEnum type,
|
|
||||||
string message,
|
|
||||||
string? code = null,
|
|
||||||
Exception? exception = null,
|
|
||||||
ExceptionLevel? level = null)
|
|
||||||
: BizException(message, code, "扫码枪异常", exception, level)
|
|
||||||
{
|
|
||||||
public ScannerTypeEnum Type { get; set; } = type;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
namespace DispenserCommon.Interface;
|
|
||||||
|
|
||||||
public interface Instant
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace DispenserCommon.Ioc;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于声明当前类需要交由IOC管理
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class Component(Type? type = null, string? name = null) : Attribute
|
|
||||||
{
|
|
||||||
public Type? Type => type;
|
|
||||||
|
|
||||||
public string? Name => name;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Lazy;
|
|
||||||
|
|
||||||
public static class IServiceCollectionExtendtions
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddLazyResolution(this IServiceCollection services)
|
|
||||||
{
|
|
||||||
return services.AddTransient(
|
|
||||||
typeof(Lazy<>),
|
|
||||||
typeof(LazilyResolved<>));
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LazilyResolved<T> : Lazy<T>
|
|
||||||
{
|
|
||||||
public LazilyResolved(IServiceProvider serviceProvider)
|
|
||||||
: base(serviceProvider.GetRequiredService<T>)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
using DispenserCommon.DTO;
|
|
||||||
using DispenserCommon.Events;
|
|
||||||
using Serilog.Core;
|
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
namespace DispenserCommon.LogUtils;
|
|
||||||
|
|
||||||
public class DispenserLogSink : ILogEventSink
|
|
||||||
{
|
|
||||||
public void Emit(LogEvent logEvent)
|
|
||||||
{
|
|
||||||
//错误日志,用于弹窗提示
|
|
||||||
if (IsPopLog(logEvent))
|
|
||||||
EventBus<LogMessage>.Publish(EventType.PopLog,
|
|
||||||
new LogMessage(logEvent.RenderMessage(), LogEventLevel.Error));
|
|
||||||
|
|
||||||
var sb = new StringBuilder(logEvent.RenderMessage());
|
|
||||||
if (logEvent.Exception != null)
|
|
||||||
{
|
|
||||||
sb.Append(logEvent.Exception.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventBus<LogMessage>.Publish(EventType.RollingLog, new LogMessage(sb.ToString(), logEvent.Level));
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsPopLog(LogEvent logEvent)
|
|
||||||
{
|
|
||||||
return logEvent.Properties.ContainsKey("IsPop") &&
|
|
||||||
logEvent.Properties["IsPop"].ToString() == true.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Queue;
|
|
||||||
|
|
||||||
public class BitmapQueue
|
|
||||||
{
|
|
||||||
private bool _isProcessing;
|
|
||||||
private readonly ConcurrentQueue<Bitmap> _queue = new();
|
|
||||||
private readonly Action<Bitmap> ImageProcessor;
|
|
||||||
|
|
||||||
public BitmapQueue(Delegate @delegate)
|
|
||||||
{
|
|
||||||
ImageProcessor = (Action<Bitmap>)@delegate;
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_queue.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将BitmapItem加入队列
|
|
||||||
public void Enqueue(Bitmap item)
|
|
||||||
{
|
|
||||||
_queue.Enqueue(item);
|
|
||||||
StartProcessing(); // 尝试开始处理(如果尚未开始)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始处理队列中的BitmapItem
|
|
||||||
private void StartProcessing()
|
|
||||||
{
|
|
||||||
if (_isProcessing) return;
|
|
||||||
_isProcessing = true;
|
|
||||||
|
|
||||||
Task.Run(ProcessQueue).ContinueWith(t =>
|
|
||||||
{
|
|
||||||
// 处理完成后的逻辑(如果有的话)
|
|
||||||
_isProcessing = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 异步处理队列
|
|
||||||
private async Task ProcessQueue()
|
|
||||||
{
|
|
||||||
while (_queue.TryDequeue(out var item))
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里处理Bitmap,例如保存、修改等
|
|
||||||
await ProcessBitmapAsync(item);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// 确保释放资源
|
|
||||||
item.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task ProcessBitmapAsync(Bitmap item)
|
|
||||||
{
|
|
||||||
return Task.Run(() => { ImageProcessor(item); });
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 延时定时任务
|
|
||||||
/// </summary>
|
|
||||||
public class DelayScheduler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 设定延时任务
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="delay"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
||||||
public static async void Delay(Action action, TimeSpan delay, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (action == null) throw new ArgumentNullException(nameof(action));
|
|
||||||
if (delay.TotalMilliseconds < 0)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(delay), "延时时间不能为负数");
|
|
||||||
|
|
||||||
await Task.Delay(delay, cancellationToken);
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, "延时任务执行失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通过定时执行某个委托方法
|
|
||||||
/// </summary>
|
|
||||||
public class ExecuteTask : ITask
|
|
||||||
{
|
|
||||||
private readonly Timer _timer;
|
|
||||||
|
|
||||||
public ExecuteTask(string name, Action action, int interval = 100)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Interval = interval;
|
|
||||||
Action = action;
|
|
||||||
_timer = new Timer(_ => { Run(); }, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(Interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Interval { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public Action Action { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除任务进行定时任务释放
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 定义一个虚方法, 子类可以重写该方法实现具体的轮询逻辑
|
|
||||||
/// </summary>
|
|
||||||
public void Run()
|
|
||||||
{
|
|
||||||
Action.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
public interface ITask : IDisposable
|
|
||||||
{
|
|
||||||
public void Run();
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
public class JobScheduler
|
|
||||||
{
|
|
||||||
private static readonly ConcurrentDictionary<string, ExecuteTask> Tasks = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加调度任务
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="interval"></param>
|
|
||||||
/// <param name="delay"></param>
|
|
||||||
public static void AddTask(string name, Action action, int interval = 100, int delay = 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
if (Tasks.ContainsKey(name)) return;
|
|
||||||
|
|
||||||
if (delay > 0)
|
|
||||||
{
|
|
||||||
await Task.Delay(delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tasks[name] = new ExecuteTask(name, action, interval);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, $"添加 {name} 任务失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除任务
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
public static void RemoveTask(string name)
|
|
||||||
{
|
|
||||||
if (Tasks.TryRemove(name, out var task)) task.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 轮询任务
|
|
||||||
/// </summary>
|
|
||||||
public abstract class PollingTask : ITask
|
|
||||||
{
|
|
||||||
private readonly Timer _timer;
|
|
||||||
|
|
||||||
protected PollingTask(string name, int interval = 100)
|
|
||||||
{
|
|
||||||
Interval = interval;
|
|
||||||
Name = name;
|
|
||||||
_timer = new Timer(_ => { Run(); }, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(Interval));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Interval { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除任务进行定时任务释放
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 定义一个虚方法, 子类可以重写该方法实现具体的轮询逻辑
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Run()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.scheduler;
|
|
||||||
|
|
||||||
public class SchedulerHelper
|
|
||||||
{
|
|
||||||
private static readonly Lazy<IScheduler> lazyScheduler = new(() => InitSchedulerAsync().GetAwaiter().GetResult());
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, IJobDetail> _jobDetails = new();
|
|
||||||
|
|
||||||
private static IScheduler Scheduler => lazyScheduler.Value;
|
|
||||||
|
|
||||||
private static async Task<IScheduler> InitSchedulerAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await new StdSchedulerFactory().GetScheduler();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error($"Failed to initialize scheduler: {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Start()
|
|
||||||
{
|
|
||||||
await Scheduler.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task SchedulerInterval<T>(Dictionary<string, object>? data, int interval,
|
|
||||||
string group = "defaultGroup") where T : IJob
|
|
||||||
{
|
|
||||||
var job = CreateJob<T>(data, group);
|
|
||||||
|
|
||||||
var trigger = TriggerBuilder.Create()
|
|
||||||
.WithIdentity(typeof(T).Name, group)
|
|
||||||
.StartNow()
|
|
||||||
.WithSimpleSchedule(x => x.WithIntervalInSeconds(interval).RepeatForever())
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
await Scheduler.ScheduleJob(job, trigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task SchedulerCorn<T>(Dictionary<string, object>? data, string? cronExpression,
|
|
||||||
string group = "defaultGroup") where T : IJob
|
|
||||||
{
|
|
||||||
var job = CreateJob<T>(data, group);
|
|
||||||
|
|
||||||
var trigger = TriggerBuilder.Create()
|
|
||||||
.WithIdentity(typeof(T).Name, group)
|
|
||||||
.StartNow()
|
|
||||||
.WithSchedule(CronScheduleBuilder.CronSchedule(cronExpression))
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
await Scheduler.ScheduleJob(job, trigger);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IJobDetail CreateJob<T>(Dictionary<string, object>? data, string group) where T : IJob
|
|
||||||
{
|
|
||||||
if (_jobDetails.ContainsKey(typeof(T).Name)) return _jobDetails[typeof(T).Name];
|
|
||||||
|
|
||||||
var job = JobBuilder.Create<T>()
|
|
||||||
.WithIdentity(typeof(T).Name, group)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
if (data != null && data.Count > 0)
|
|
||||||
foreach (var item in data)
|
|
||||||
job.JobDataMap.Add(item.Key, item.Value);
|
|
||||||
|
|
||||||
_jobDetails[typeof(T).Name] = job;
|
|
||||||
return job;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task PauseJob<T>(string group = "defaultGroup")
|
|
||||||
{
|
|
||||||
if (_jobDetails.ContainsKey(typeof(T).Name)) await Scheduler.PauseJob(JobKey.Create(typeof(T).Name, group));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ResumeJob<T>(string group = "defaultGroup")
|
|
||||||
{
|
|
||||||
if (_jobDetails.ContainsKey(typeof(T).Name)) await Scheduler.ResumeJob(JobKey.Create(typeof(T).Name, group));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Shutdown()
|
|
||||||
{
|
|
||||||
if (!Scheduler.IsShutdown) await Scheduler.Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task TriggerOnceImmediately<T>(string group = "defaultGroup") where T : IJob
|
|
||||||
{
|
|
||||||
if (!_jobDetails.ContainsKey(typeof(T).Name)) return;
|
|
||||||
|
|
||||||
await Scheduler.TriggerJob(new JobKey(typeof(T).Name, group));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
using Castle.Core.Internal;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Scheduler;
|
|
||||||
|
|
||||||
public class TaskWaiter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 在
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="timeout"></param>
|
|
||||||
/// <param name="cts"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<bool> WaitingFor(Func<bool> action, long timeout = 60000,
|
|
||||||
CancellationTokenSource? cts = null)
|
|
||||||
{
|
|
||||||
var method = action.Method;
|
|
||||||
var blockTask = method.GetAttribute<BlockTask>();
|
|
||||||
|
|
||||||
var taskName = blockTask?.Name ?? method.Name;
|
|
||||||
var span = TimeSpan.FromMilliseconds(timeout);
|
|
||||||
var endTime = DateTime.Now.Add(span);
|
|
||||||
|
|
||||||
return await Task.Run(() =>
|
|
||||||
{
|
|
||||||
while (DateTime.Now < endTime)
|
|
||||||
{
|
|
||||||
if (cts is { IsCancellationRequested: true })
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action())
|
|
||||||
{
|
|
||||||
Log.Information($"{taskName} 任务等待完成");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
using MathNet.Numerics.LinearAlgebra;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class AffineTransformCalculator
|
|
||||||
{
|
|
||||||
public static Matrix<double> Calculate3x2AffineTransform(List<Tuple<double, double>> acupunctureCoordinates,
|
|
||||||
List<Tuple<double, double>> binCoordinates)
|
|
||||||
{
|
|
||||||
if (acupunctureCoordinates.Count != binCoordinates.Count || acupunctureCoordinates.Count < 3)
|
|
||||||
throw new ArgumentException("Both sets must have the same number of points and at least three points.");
|
|
||||||
|
|
||||||
// 创建矩阵X和Y
|
|
||||||
var rowCount = acupunctureCoordinates.Count;
|
|
||||||
var matrixX = Matrix<double>.Build.Dense(rowCount, 3);
|
|
||||||
var matrixY = Matrix<double>.Build.Dense(rowCount, 2);
|
|
||||||
|
|
||||||
for (var i = 0; i < rowCount; i++)
|
|
||||||
{
|
|
||||||
matrixX[i, 0] = acupunctureCoordinates[i].Item1; // x-coordinate
|
|
||||||
matrixX[i, 1] = acupunctureCoordinates[i].Item2; // y-coordinate
|
|
||||||
matrixX[i, 2] = 1; // homogeneous coordinate
|
|
||||||
|
|
||||||
matrixY[i, 0] = binCoordinates[i].Item1; // x'-coordinate
|
|
||||||
matrixY[i, 1] = binCoordinates[i].Item2; // y'-coordinate
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算仿射变换矩阵 A = Y * X^(-1)
|
|
||||||
var pseudoInverseX = matrixX.PseudoInverse();
|
|
||||||
var transformMatrix = matrixY.Transpose() * pseudoInverseX.Transpose();
|
|
||||||
|
|
||||||
return transformMatrix;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
using System.Net.Http.Json;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class ApiClient : IDisposable
|
|
||||||
{
|
|
||||||
private static readonly HttpClient Client;
|
|
||||||
|
|
||||||
static ApiClient()
|
|
||||||
{
|
|
||||||
Client = new HttpClient();
|
|
||||||
Client.DefaultRequestHeaders.Accept.Clear();
|
|
||||||
Client.DefaultRequestHeaders.Add("Accept", "application/json");
|
|
||||||
Client.DefaultRequestHeaders.Add("Content-Type", "application/json");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步Get请求
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T?> GetAsync<T>(string url)
|
|
||||||
{
|
|
||||||
using var response = await Client.GetAsync(url);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步 Post请求
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url"></param>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T?> PostAsync<T>(string url, object? data)
|
|
||||||
{
|
|
||||||
using var response = await Client.PostAsJsonAsync(url, data);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步 Put请求
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url"></param>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T?> PutAsync<T>(string url, object? data)
|
|
||||||
{
|
|
||||||
using var response = await Client.PutAsJsonAsync(url, data);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步 Delete请求
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<T?> DeleteAsync<T>(string url)
|
|
||||||
{
|
|
||||||
using var response = await Client.DeleteAsync(url);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
return await response.Content.ReadFromJsonAsync<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Client.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
using DispenserCommon.Exceptions;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 断言工具类
|
|
||||||
/// </summary>
|
|
||||||
public class AssertUtil
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 判断条件是否为真
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="expression"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
public static void IsTrue(bool expression, string msg)
|
|
||||||
{
|
|
||||||
if (!expression)
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断条件是否为假
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="expression"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
public static void IsFalse(bool expression, string msg)
|
|
||||||
{
|
|
||||||
if (expression)
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 集合非空断言
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="list"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
public static void NotEmpty(List<object>? list, string msg)
|
|
||||||
{
|
|
||||||
if (list == null || list.Count == 0)
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 集合空断言
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="list"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
public static void IsEmpty(List<object> list, string msg)
|
|
||||||
{
|
|
||||||
if (list is { Count: > 0 })
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对象非空断言
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="model"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <exception cref="AssertException"></exception>
|
|
||||||
public static void NotNull(object? model, string msg)
|
|
||||||
{
|
|
||||||
if (model == null)
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对象空断言
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="model"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <exception cref="AssertException"></exception>
|
|
||||||
public static void IsNull(object? model, string msg)
|
|
||||||
{
|
|
||||||
if (model != null)
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 字符串非空断言
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <exception cref="AssertException"></exception>
|
|
||||||
public static void StringNotNullOrEmpty(string str, string msg)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
throw new AssertException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// bean 工具类
|
|
||||||
/// </summary>
|
|
||||||
public class BeanUtil
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 实现Bean的属性复制
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
public static void CopyProperties(object source, object target)
|
|
||||||
{
|
|
||||||
var sourceProperties = source.GetType().GetProperties();
|
|
||||||
var targetProperties = target.GetType().GetProperties();
|
|
||||||
|
|
||||||
foreach (var sourceProperty in sourceProperties)
|
|
||||||
{
|
|
||||||
var targetProperty = Array.Find(targetProperties, p => p.Name == sourceProperty.Name &&
|
|
||||||
p.PropertyType == sourceProperty.PropertyType);
|
|
||||||
|
|
||||||
if (targetProperty != null && targetProperty.CanWrite)
|
|
||||||
targetProperty.SetValue(target, sourceProperty.GetValue(source));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T CopyProperties<T>(object source)
|
|
||||||
{
|
|
||||||
var instance = Activator.CreateInstance<T>();
|
|
||||||
CopyProperties(source, instance);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<T> CopyProperties<T>(IEnumerable<object> source)
|
|
||||||
{
|
|
||||||
return source.Select(CopyProperties<T>).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 缓冲队列
|
|
||||||
/// </summary>
|
|
||||||
public class BufferQueue<T>(int capacity)
|
|
||||||
{
|
|
||||||
private readonly Queue<T?> _queue = new();
|
|
||||||
private readonly int _capacity = Math.Min(capacity, 10);
|
|
||||||
private readonly object _lock = new();
|
|
||||||
|
|
||||||
// 尝试添加元素到队列中
|
|
||||||
public bool TryEnqueue(T? item)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (_queue.Count >= _capacity) return false;
|
|
||||||
_queue.Enqueue(item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从队列中移除并返回元素
|
|
||||||
public bool TryDequeue(out T? result)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (_queue.Count > 0)
|
|
||||||
{
|
|
||||||
result = _queue.Dequeue();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = default(T);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前队列中的元素数量
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
return _queue.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 弹窗工具类
|
|
||||||
/// </summary>
|
|
||||||
public interface ConfirmDialogHelper
|
|
||||||
{
|
|
||||||
Task<bool> ShowConfirm(string title, bool showCancel = true, bool showConfirm = true,
|
|
||||||
string cancelText = "取消", string confirmText = "确认");
|
|
||||||
}
|
|
|
@ -1,577 +0,0 @@
|
||||||
using Masuit.Tools;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数组工具类
|
|
||||||
/// </summary>
|
|
||||||
public class CoordinateUtil
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 将一个二维坐标数组拆分成两个一维数组
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="coordinates">二维坐标数组</param>
|
|
||||||
/// <param name="xAxis">X轴坐标数组</param>
|
|
||||||
/// <param name="yAxis">Y轴坐标数组</param>
|
|
||||||
public static void SplitCoordinates(double[][] coordinates, out double[] xAxis, out double[] yAxis)
|
|
||||||
{
|
|
||||||
var totalPoints = coordinates.GetLength(0);
|
|
||||||
xAxis = new double[totalPoints];
|
|
||||||
yAxis = new double[totalPoints];
|
|
||||||
|
|
||||||
for (var i = 0; i < totalPoints; i++)
|
|
||||||
{
|
|
||||||
// 提取x坐标
|
|
||||||
xAxis[i] = coordinates[i][0];
|
|
||||||
// 提取y坐标
|
|
||||||
yAxis[i] = coordinates[i][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SplitCoordinates(double[][] coordinates, out double[] xAxis, out double[] yAxis,
|
|
||||||
out double[] depth)
|
|
||||||
{
|
|
||||||
var totalPoints = coordinates.GetLength(0);
|
|
||||||
xAxis = new double[totalPoints];
|
|
||||||
yAxis = new double[totalPoints];
|
|
||||||
depth = new double[totalPoints];
|
|
||||||
|
|
||||||
for (var i = 0; i < totalPoints; i++)
|
|
||||||
{
|
|
||||||
// 提取x坐标
|
|
||||||
xAxis[i] = coordinates[i][0];
|
|
||||||
// 提取y坐标
|
|
||||||
yAxis[i] = coordinates[i][1];
|
|
||||||
// 提取针刺深度
|
|
||||||
depth[i] = coordinates[i][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将两个坐标数组合并成一个二维坐标数组
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="coordinates1"></param>
|
|
||||||
/// <param name="coordinates2"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static double[][] MergeArray(IEnumerable<double> coordinates1, double[] coordinates2)
|
|
||||||
{
|
|
||||||
List<double[]> merged = [];
|
|
||||||
merged.AddRange(coordinates1.Select((t, i) => (double[]) [t, coordinates2[i]]));
|
|
||||||
|
|
||||||
return merged.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断数组是否为空
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool IsEmpty(double[]? array)
|
|
||||||
{
|
|
||||||
return array == null || !array.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断数组是否为空
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool IsEmpty(double[][]? array)
|
|
||||||
{
|
|
||||||
return array == null || !array.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断数组是否为空
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool IsEmpty(double[,]? array)
|
|
||||||
{
|
|
||||||
return array == null || array.GetLength(0) == 0 || array.GetLength(1) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 合并相似点
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points"></param>
|
|
||||||
/// <param name="window">相似划分窗口</param>
|
|
||||||
/// <param name="rowSimilarPitchThreshold">行相似值判断阈值</param>
|
|
||||||
/// <param name="colSimilarPitchThreshold">列相似值判断阈值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static List<double[]> MergeSimilarPoints(List<double[]> points, string window,
|
|
||||||
double rowSimilarPitchThreshold,
|
|
||||||
double colSimilarPitchThreshold)
|
|
||||||
{
|
|
||||||
var windowConfig = window;
|
|
||||||
var windows = windowConfig.Split(",");
|
|
||||||
points = windows
|
|
||||||
.Select(int.Parse)
|
|
||||||
.Aggregate(points,
|
|
||||||
(current, windowSize) =>
|
|
||||||
MergeSimilarPoints(current, windowSize, rowSimilarPitchThreshold, colSimilarPitchThreshold));
|
|
||||||
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对坐标进行分区计算,提高计算效率
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points">合并前的坐标点</param>
|
|
||||||
/// <param name="space">分区数</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static List<List<List<double[]>>> DivideIntoRegions(List<double[]> points, int space)
|
|
||||||
{
|
|
||||||
// 找到坐标范围
|
|
||||||
var minX = points.Min(p => p[0]);
|
|
||||||
var maxX = points.Max(p => p[0]);
|
|
||||||
var minY = points.Min(p => p[1]);
|
|
||||||
var maxY = points.Max(p => p[1]);
|
|
||||||
|
|
||||||
// 计算每个区域的尺寸
|
|
||||||
var regionWidth = (maxX - minX) / space;
|
|
||||||
var regionHeight = (maxY - minY) / space;
|
|
||||||
|
|
||||||
// 初始化区域列表
|
|
||||||
var regions = new List<List<List<double[]>>>(space);
|
|
||||||
for (var i = 0; i < space; i++)
|
|
||||||
{
|
|
||||||
regions.Add(new List<List<double[]>>(space));
|
|
||||||
for (var j = 0; j < space; j++) regions[i].Add([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将点分配到相应的区域
|
|
||||||
foreach (var point in points)
|
|
||||||
{
|
|
||||||
var x = point[0];
|
|
||||||
var y = point[1];
|
|
||||||
var row = (int)Math.Floor((y - minY) / regionHeight);
|
|
||||||
var col = (int)Math.Floor((x - minX) / regionWidth);
|
|
||||||
|
|
||||||
// 防止由于边界值导致的索引超出范围
|
|
||||||
row = Math.Min(row, space - 1);
|
|
||||||
col = Math.Min(col, space - 1);
|
|
||||||
|
|
||||||
regions[row][col].Add(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
return regions;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 合并相似点
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points">合并前的坐标点集合</param>
|
|
||||||
/// <param name="space">区域数</param>
|
|
||||||
/// <param name="rowSimilarPitchThreshold">行相似值判断阈值</param>
|
|
||||||
/// <param name="colSimilarPitchThreshold">列相似值判断阈值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static List<double[]> MergeSimilarPoints(List<double[]> points, int space, double rowSimilarPitchThreshold,
|
|
||||||
double colSimilarPitchThreshold)
|
|
||||||
{
|
|
||||||
// 将整个区域划分为 若干个区域
|
|
||||||
var regions = DivideIntoRegions(points, space);
|
|
||||||
|
|
||||||
var merged = new List<double[]>();
|
|
||||||
// 遍历每个区域,对每个区域进行相似点合并
|
|
||||||
foreach (var region in regions)
|
|
||||||
foreach (var col in region)
|
|
||||||
merged.AddRange(MergePoints(col, rowSimilarPitchThreshold, colSimilarPitchThreshold));
|
|
||||||
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对区域内的点进行合并处理
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="points">待合并区域</param>
|
|
||||||
/// <param name="rowSimilarPitchThreshold">行相似值判断阈值</param>
|
|
||||||
/// <param name="colSimilarPitchThreshold">列相似值判断阈值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static List<double[]> MergePoints(List<double[]> points, double rowSimilarPitchThreshold,
|
|
||||||
double colSimilarPitchThreshold)
|
|
||||||
{
|
|
||||||
if (points.Count == 0)
|
|
||||||
return new List<double[]>();
|
|
||||||
|
|
||||||
// 如果两个两个点的 abs(x2-x1) <= 0.2 && abs(y2-y1) <= 0.35, 那么可以认为这两个点是相似的,只保留第一个点即可
|
|
||||||
var merged = new List<double[]>();
|
|
||||||
foreach (var point in points)
|
|
||||||
// 同当前区域的其他点进行比较
|
|
||||||
if (merged.Count == 0)
|
|
||||||
{
|
|
||||||
merged.Add(point);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var similar = false;
|
|
||||||
foreach (var other in merged)
|
|
||||||
if (IsSimilar(point, other, 0.1, 0.1))
|
|
||||||
{
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{point[0]},{point[1]} 与 {other[0]},{other[1]} 相似, X差值{point[0] - other[0]}, y差值{point[1] - other[1]}");
|
|
||||||
similar = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!similar) merged.Add(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
return merged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断两个点是否相似
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="p1">第一个点</param>
|
|
||||||
/// <param name="p2">第二个点</param>
|
|
||||||
/// <param name="rowSimilarPitchThreshold">行相似值判断阈值</param>
|
|
||||||
/// <param name="colSimilarPitchThreshold">列相似值判断阈值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static bool IsSimilar(double[] p1, double[] p2, double rowSimilarPitchThreshold,
|
|
||||||
double colSimilarPitchThreshold)
|
|
||||||
{
|
|
||||||
return Math.Abs(p2[0] - p1[0]) <= rowSimilarPitchThreshold &&
|
|
||||||
Math.Abs(p2[1] - p1[1]) <= colSimilarPitchThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从原数组中根据匹配点数组查找相似点
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="referencePoints"></param>
|
|
||||||
/// <param name="comparisonPoints"></param>
|
|
||||||
/// <param name="rowSimilarPitchThreshold">行相似值判断阈值</param>
|
|
||||||
/// <param name="colSimilarPitchThreshold">列相似值判断阈值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static List<double[]> FindSimilarPoints(List<double[]> referencePoints, List<double[]> comparisonPoints,
|
|
||||||
double rowSimilarPitchThreshold,
|
|
||||||
double colSimilarPitchThreshold)
|
|
||||||
{
|
|
||||||
// 从原数组中根据匹配点数组查找相似点
|
|
||||||
return referencePoints.AsParallel().Where(sourcePoint =>
|
|
||||||
comparisonPoints.Any(matchPoint =>
|
|
||||||
IsSimilar(sourcePoint, matchPoint, rowSimilarPitchThreshold, colSimilarPitchThreshold))
|
|
||||||
).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 晶环和pcb坐标长度对齐
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pcbCoordinates">原始pcb坐标</param>
|
|
||||||
/// <param name="waferCoordinates">原始晶环坐标</param>
|
|
||||||
/// <param name="pcbAlignedCoordinates">对齐后的pcb坐标</param>
|
|
||||||
/// <param name="waferAlignedCoordinates">对齐后的晶环坐标</param>
|
|
||||||
public static void CoordinateAlign(List<double[]> pcbCoordinates, List<double[]> waferCoordinates,
|
|
||||||
out List<double[]> pcbAlignedCoordinates, out List<double[]> waferAlignedCoordinates)
|
|
||||||
{
|
|
||||||
pcbAlignedCoordinates = [];
|
|
||||||
waferAlignedCoordinates = [];
|
|
||||||
var pcbStartIndex = 0;
|
|
||||||
var waferStartIndex = 0;
|
|
||||||
var pStart = 0;
|
|
||||||
var wStart = 0;
|
|
||||||
while (pcbStartIndex <= pcbCoordinates.Count && waferStartIndex <= waferCoordinates.Count)
|
|
||||||
if ((IsReal(pcbCoordinates, pcbStartIndex) && IsReal(waferCoordinates, waferStartIndex)) ||
|
|
||||||
(!IsReal(pcbCoordinates, pcbStartIndex) && !IsReal(waferCoordinates, waferStartIndex)))
|
|
||||||
{
|
|
||||||
pcbAlignedCoordinates[pStart++] = pcbCoordinates[pcbStartIndex++];
|
|
||||||
waferAlignedCoordinates[wStart++] = waferCoordinates[waferStartIndex++];
|
|
||||||
}
|
|
||||||
else if (IsReal(pcbCoordinates, pcbStartIndex) && !IsReal(waferCoordinates, waferStartIndex))
|
|
||||||
{
|
|
||||||
var pcbCoordinate = new double[3];
|
|
||||||
Array.Copy(pcbCoordinates[pcbStartIndex], pcbCoordinate, 3);
|
|
||||||
pcbCoordinate[2] = 0;
|
|
||||||
pcbAlignedCoordinates[pStart++] = pcbCoordinate;
|
|
||||||
waferAlignedCoordinates[wStart++] = waferCoordinates[waferStartIndex++];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pcbAlignedCoordinates[pStart++] = pcbCoordinates[pcbStartIndex++];
|
|
||||||
var waferCoordinate = new double[3];
|
|
||||||
Array.Copy(waferCoordinates[waferStartIndex], waferCoordinate, 3);
|
|
||||||
waferCoordinate[2] = 0;
|
|
||||||
waferAlignedCoordinates[wStart++] = waferCoordinate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断是否是真实坐标
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pcbCoordinates"></param>
|
|
||||||
/// <param name="pcbStartIndex"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static bool IsReal(IReadOnlyList<double[]> pcbCoordinates, int pcbStartIndex)
|
|
||||||
{
|
|
||||||
return pcbCoordinates[pcbStartIndex][2] != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从插值路径中提取动打坐标信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="coordinates">插值后的坐标数组</param>
|
|
||||||
/// <param name="startPoint">开始的坐标</param>
|
|
||||||
/// <param name="endPoint">借宿的坐标</param>
|
|
||||||
public static List<double[]> SubCurrentBatchCoordinate(IEnumerable<double[]> coordinates, double[] startPoint,
|
|
||||||
double[] endPoint)
|
|
||||||
{
|
|
||||||
// 保存当前截取后的新坐标
|
|
||||||
List<double[]> newCoordinates = [];
|
|
||||||
var target = false;
|
|
||||||
|
|
||||||
foreach (var coordinate in coordinates)
|
|
||||||
{
|
|
||||||
if (Equals(coordinate, startPoint))
|
|
||||||
{
|
|
||||||
target = true;
|
|
||||||
}
|
|
||||||
else if (Equals(coordinate, endPoint))
|
|
||||||
{
|
|
||||||
newCoordinates.Add(coordinate);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target)
|
|
||||||
// 都是目标值
|
|
||||||
newCoordinates.Add(coordinate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newCoordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Equals(double[] a, double[] b)
|
|
||||||
{
|
|
||||||
if (IsEmpty(a) || IsEmpty(b)) return false;
|
|
||||||
|
|
||||||
return Math.Abs(a[0] - b[0]) < 0.00001 && Math.Abs(a[1] - b[1]) < 0.00001;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double[][] FillDefaultFlagIfNotExist(double[][] path, double defaultFlag = 1)
|
|
||||||
{
|
|
||||||
if (path.IsNullOrEmpty()) return path;
|
|
||||||
if (path[0].Length == 2) return path.Select(v => new[] { v[0], v[1], defaultFlag }).ToArray();
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsRealPoint(double flag)
|
|
||||||
{
|
|
||||||
return Math.Abs(Math.Round(flag, MidpointRounding.ToEven) - 1) < 0.0001;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double GetTowCoordinatesDistinct(double[] p1, double[] p2)
|
|
||||||
{
|
|
||||||
return Math.Sqrt(Math.Pow(p1[0] - p2[0], 2) + Math.Pow(p1[1] - p2[1], 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double[][] SubPcbPath(double[][] path, int rowAmount, int startColumn, int pathRowAmount)
|
|
||||||
{
|
|
||||||
List<double[]> result = new();
|
|
||||||
|
|
||||||
if ((startColumn + pathRowAmount - 1) > rowAmount)
|
|
||||||
{
|
|
||||||
pathRowAmount = rowAmount - startColumn + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rows = RowBy(path.ToList(), rowAmount);
|
|
||||||
|
|
||||||
for (var i = 0; i < rows.Count; i++)
|
|
||||||
{
|
|
||||||
var row = rows[i];
|
|
||||||
List<double[]> chunkRow;
|
|
||||||
if (i % 2 == 0)
|
|
||||||
{
|
|
||||||
chunkRow = row.Skip(startColumn - 1).Take(pathRowAmount).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chunkRow = row.Skip(rowAmount - (pathRowAmount + startColumn - 1)).Take(pathRowAmount).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.AddRange(chunkRow);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<List<double[]>> RowBy(List<double[]> source, int chunkSize)
|
|
||||||
{
|
|
||||||
List<List<double[]>> result = new List<List<double[]>>();
|
|
||||||
|
|
||||||
for (int i = 0; i < source.Count; i += chunkSize)
|
|
||||||
{
|
|
||||||
result.Add(source.GetRange(i, Math.Min(chunkSize, source.Count - i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double[] AffineTransform(double[,] matrix, IReadOnlyList<double> point)
|
|
||||||
{
|
|
||||||
if (matrix.GetLength(0) != 3 || matrix.GetLength(1) != 3)
|
|
||||||
throw new ArgumentException("Matrix must be a 3x3 array.");
|
|
||||||
|
|
||||||
return new double[]
|
|
||||||
{
|
|
||||||
matrix[0, 0] * point[0] + matrix[0, 1] * point[1] + matrix[0, 2] * point[2],
|
|
||||||
matrix[1, 0] * point[0] + matrix[1, 1] * point[1] + matrix[1, 2] * point[2]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double[][] Convert2DArrayToJaggedArray(double[,] twoDArray)
|
|
||||||
{
|
|
||||||
int rows = twoDArray.GetLength(0); // 获取第一维度的长度,即行数
|
|
||||||
int cols = twoDArray.GetLength(1); // 获取第二维度的长度,即列数
|
|
||||||
|
|
||||||
double[][] jaggedArray = new double[rows][]; // 创建外层数组
|
|
||||||
|
|
||||||
for (int i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
jaggedArray[i] = new double[cols]; // 每一行创建一个新的内层数组
|
|
||||||
for (int j = 0; j < cols; j++)
|
|
||||||
{
|
|
||||||
jaggedArray[i][j] = twoDArray[i, j]; // 复制元素
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return jaggedArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<List<double[]>> GroupPointsIntoRows(double[][] pointsArray, double yThreshold)
|
|
||||||
{
|
|
||||||
// 对点数组进行排序
|
|
||||||
var pointsArraySorted = pointsArray.OrderBy(p => p[0]).ToArray();
|
|
||||||
List<List<double[]>> rows = new List<List<double[]>>();
|
|
||||||
|
|
||||||
foreach (var point in pointsArraySorted)
|
|
||||||
{
|
|
||||||
bool placed = false;
|
|
||||||
foreach (var row in rows)
|
|
||||||
{
|
|
||||||
if (Math.Abs(row.Last()[1] - point[1]) <= yThreshold && point[0] > row.Last()[0])
|
|
||||||
{
|
|
||||||
row.Add(point);
|
|
||||||
placed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!placed)
|
|
||||||
{
|
|
||||||
rows.Add(new List<double[]> { point });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows.OrderBy(p => p[0][1]).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<double[]> ConvertMatrixToList(double[,] matrix)
|
|
||||||
{
|
|
||||||
int rows = matrix.GetLength(0);
|
|
||||||
int columns = matrix.GetLength(1);
|
|
||||||
var list = new List<double[]>();
|
|
||||||
|
|
||||||
for (int i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
double[] rowArray = new double[columns];
|
|
||||||
for (int j = 0; j < columns; j++)
|
|
||||||
{
|
|
||||||
rowArray[j] = matrix[i, j];
|
|
||||||
}
|
|
||||||
|
|
||||||
list.Add(rowArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将 坐标数组转为 矩阵
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">坐标数组</param>
|
|
||||||
/// <param name="cols">标准分列数</param>
|
|
||||||
public static double[,][] Array2Matrix(double[][] array, int cols)
|
|
||||||
{
|
|
||||||
// 总的行数
|
|
||||||
var rows = array.Length / cols;
|
|
||||||
|
|
||||||
var matrix = new double[rows, cols][];
|
|
||||||
|
|
||||||
for (var i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < cols; j++)
|
|
||||||
{
|
|
||||||
matrix[i, j] = array[i * cols + j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从矩阵的中心位置将其一分为二
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static (double[,][], double[,][]) SplitMatrixByHalf(double[,][] array)
|
|
||||||
{
|
|
||||||
var rows = array.GetLength(0);
|
|
||||||
var cols = array.GetLength(1);
|
|
||||||
|
|
||||||
var middle = cols / 2;
|
|
||||||
|
|
||||||
var part1 = new double[rows, middle][];
|
|
||||||
var part2 = new double[rows, cols - middle][];
|
|
||||||
|
|
||||||
for (var i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < cols; j++)
|
|
||||||
{
|
|
||||||
if (j < middle)
|
|
||||||
part1[i, j] = array[i, j];
|
|
||||||
else
|
|
||||||
part2[i, j - middle] = array[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (part1, part2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将矩阵数组转为弓字形数组
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="matrix"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static double[][] ConvertMatrix2BowShapeArray(double[,][] matrix)
|
|
||||||
{
|
|
||||||
var rows = matrix.GetLength(0);
|
|
||||||
var cols = matrix.GetLength(1);
|
|
||||||
var result = new double[rows * cols][];
|
|
||||||
var index = 0;
|
|
||||||
|
|
||||||
for (var d = 0; d < rows + cols - 1; d++)
|
|
||||||
{
|
|
||||||
if (d % 2 == 0) // 从左下角到右上角
|
|
||||||
{
|
|
||||||
for (var i = Math.Min(d, rows - 1); i >= Math.Max(0, d - cols + 1); i--)
|
|
||||||
{
|
|
||||||
result[index++] = matrix[i, d - i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // 从右上角到左下角
|
|
||||||
{
|
|
||||||
for (var i = Math.Max(0, d - cols + 1); i <= Math.Min(d, rows - 1); i++)
|
|
||||||
{
|
|
||||||
result[index++] = matrix[i, d - i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class INIFileReader
|
|
||||||
{
|
|
||||||
[DllImport("kernel32")]
|
|
||||||
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
|
|
||||||
|
|
||||||
// 声明INI文件的读操作函数 GetPrivateProfileString()
|
|
||||||
[DllImport("kernel32")]
|
|
||||||
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal,
|
|
||||||
int size, string filePath);
|
|
||||||
|
|
||||||
/// 写入INI的方法
|
|
||||||
public void INIWrite(string section, string key, string value, string path)
|
|
||||||
{
|
|
||||||
// section=配置节点名称,key=键名,value=返回键值,path=路径
|
|
||||||
WritePrivateProfileString(section, key, value, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
//读取INI的方法
|
|
||||||
public string INIRead(string section, string key, string path)
|
|
||||||
{
|
|
||||||
// 每次从ini中读取多少字节
|
|
||||||
var temp = new StringBuilder(255);
|
|
||||||
// section=配置节点名称,key=键名,temp=上面,path=路径
|
|
||||||
GetPrivateProfileString(section, key, "", temp, 255, path);
|
|
||||||
return temp.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除一个INI文件
|
|
||||||
public void INIDelete(string FilePath)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class JsonUtil
|
|
||||||
{
|
|
||||||
public static string ToJson(object obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(obj);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($" 无效的json 对象 {obj} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<string, object>? ToDictionary(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($" 无效的json 对象 {json} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T FromJson<T>(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<T>(json);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error($"json解析异常 {e.Message}");
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object? FromJson(Type type, string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject(json, type);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($" 无效的json 字符串 {json} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T FromJsonOrDefault<T>(string json)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return JsonConvert.DeserializeObject<T>(json);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class LineEquationUtil
|
|
||||||
{
|
|
||||||
public static double CalculateX(LineEquation lineEquation, double y)
|
|
||||||
{
|
|
||||||
return lineEquation.CalculateXCoordinate(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double CalculateY(LineEquation lineEquation, double x)
|
|
||||||
{
|
|
||||||
return lineEquation.CalculateYCoordinate(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LineEquation CreateLineEquation(double x1, double y1, double x2, double y2)
|
|
||||||
{
|
|
||||||
return new LineEquation(x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LineEquation
|
|
||||||
{
|
|
||||||
public LineEquation(double x1, double y1, double x2, double y2)
|
|
||||||
{
|
|
||||||
CalculateSlopeAndIntercept(x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double Slope { get; private set; }
|
|
||||||
public double Intercept { get; private set; }
|
|
||||||
|
|
||||||
private void CalculateSlopeAndIntercept(double x1, double y1, double x2, double y2)
|
|
||||||
{
|
|
||||||
Slope = (y2 - y1) / (x2 - x1);
|
|
||||||
Intercept = y1 - Slope * x1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double CalculateXCoordinate(double y)
|
|
||||||
{
|
|
||||||
return (y - Intercept) / Slope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double CalculateYCoordinate(double x)
|
|
||||||
{
|
|
||||||
return Slope * x + Intercept;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// MD5 加密工具类
|
|
||||||
/// </summary>
|
|
||||||
public class Md5Util
|
|
||||||
{
|
|
||||||
public static string Md5(string input)
|
|
||||||
{
|
|
||||||
// 创建一个MD5对象
|
|
||||||
// 将输入字符串转换为字节数组
|
|
||||||
var inputBytes = Encoding.UTF8.GetBytes(input);
|
|
||||||
// 计算输入字节数组的哈希值
|
|
||||||
var bytes = MD5.HashData(inputBytes);
|
|
||||||
// 将字节数组转换为字符串
|
|
||||||
var hashString = new StringBuilder();
|
|
||||||
foreach (var b in bytes) hashString.Append($"{b:x2}");
|
|
||||||
|
|
||||||
return hashString.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using MsBox.Avalonia;
|
|
||||||
using MsBox.Avalonia.Base;
|
|
||||||
using MsBox.Avalonia.Dto;
|
|
||||||
using MsBox.Avalonia.Models;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用于弹窗提示
|
|
||||||
/// </summary>
|
|
||||||
public static class MessageBoxHelper
|
|
||||||
{
|
|
||||||
private const string SUCCESS = "Assets/success.png";
|
|
||||||
private const string INFO = "Assets/info.png";
|
|
||||||
private const string WARNING = "Assets/warning.png";
|
|
||||||
private const string ERROR = "Assets/error.png";
|
|
||||||
private const string NOTIFY = "Assets/notify.png";
|
|
||||||
|
|
||||||
// 定义 5分钟的滑动时间窗口
|
|
||||||
private static readonly SlidingWindow SlidingWindow = new(5 * 60 * 1000);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构建弹窗对象
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="title">消息标题,用于显示在弹窗最顶方</param>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">内容标题,用于显示在内容的顶部</param>
|
|
||||||
/// <param name="icon">弹窗左上角icon</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static IMsBox<string> CreateMessageBox(
|
|
||||||
string title,
|
|
||||||
string msg,
|
|
||||||
string contentTitle = "",
|
|
||||||
string icon = "Assets/info.png")
|
|
||||||
{
|
|
||||||
return MessageBoxManager.GetMessageBoxCustom(
|
|
||||||
new MessageBoxCustomParams
|
|
||||||
{
|
|
||||||
ButtonDefinitions = new List<ButtonDefinition>
|
|
||||||
{
|
|
||||||
new() { Name = "关闭", IsCancel = true }
|
|
||||||
},
|
|
||||||
WindowIcon = new WindowIcon(icon),
|
|
||||||
ContentTitle = title,
|
|
||||||
ContentHeader = contentTitle,
|
|
||||||
ContentMessage = msg,
|
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
|
||||||
CanResize = false,
|
|
||||||
MinWidth = 300,
|
|
||||||
MinHeight = 200,
|
|
||||||
MaxWidth = 800,
|
|
||||||
MaxHeight = 1000,
|
|
||||||
SizeToContent = SizeToContent.WidthAndHeight,
|
|
||||||
ShowInCenter = true,
|
|
||||||
Topmost = true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async void Show(string title, string msg, string icon, string contentTitle = "", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 对弹窗内容进行滤波,减少相同内容的弹窗频次
|
|
||||||
if (filter && !SlidingWindow.AllowValue(msg)) return;
|
|
||||||
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
var box = CreateMessageBox(title, msg, contentTitle, icon);
|
|
||||||
await box.ShowWindowAsync();
|
|
||||||
});
|
|
||||||
if (callback != null) callback();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, "弹窗出现异常");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 消息级别弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">消息标题,默认为空字符串,不显示</param>
|
|
||||||
/// <param name="title">弹窗标题</param>
|
|
||||||
/// <param name="filter">是否过滤弹窗</param>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
public static void Info(string msg, string contentTitle = "", string title = "提示", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
Show(title, msg, INFO, contentTitle, filter, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 告警级别弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">消息标题,默认为空字符串,不显示</param>
|
|
||||||
/// <param name="title">弹窗标题</param>
|
|
||||||
/// <param name="filter">是否过滤弹窗</param>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
public static void Warning(string msg, string contentTitle = "", string title = "警告", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
Show(title, msg, WARNING, contentTitle, filter, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 错误级别弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">消息标题,默认为空字符串,不显示</param>
|
|
||||||
/// <param name="title">弹窗标题</param>
|
|
||||||
/// <param name="filter">是否过滤弹窗</param>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
public static void Error(string msg, string contentTitle = "", string title = "错误", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
Show(title, msg, ERROR, contentTitle, filter, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通知级别弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">消息标题,默认为空字符串,不显示</param>
|
|
||||||
/// <param name="title">弹窗标题</param>
|
|
||||||
/// <param name="filter">是否过滤弹窗</param>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
public static void Notify(string msg, string contentTitle = "", string title = "通知", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
Show(title, msg, NOTIFY, contentTitle, filter, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 成功通知级别弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="msg">消息内容</param>
|
|
||||||
/// <param name="contentTitle">消息标题,默认为空字符串,不显示</param>
|
|
||||||
/// <param name="title">弹窗标题</param>
|
|
||||||
/// <param name="filter">是否过滤弹窗</param>
|
|
||||||
/// <param name="callback"></param>
|
|
||||||
public static void Success(string msg, string contentTitle = "", string title = "成功", bool filter = true,
|
|
||||||
Action? callback = null)
|
|
||||||
{
|
|
||||||
Show(title, msg, SUCCESS, contentTitle, filter, callback);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册表工具类
|
|
||||||
/// </summary>
|
|
||||||
public static class RegistryHelper
|
|
||||||
{
|
|
||||||
public static void WriteValue(string keyPath, string valueName, object value, RegistryValueKind valueKind)
|
|
||||||
{
|
|
||||||
using var key = Registry.CurrentUser.CreateSubKey(keyPath);
|
|
||||||
key.SetValue(valueName, value, valueKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object? ReadValue(string keyPath, string valueName)
|
|
||||||
{
|
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(keyPath);
|
|
||||||
return key?.GetValue(valueName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DeleteValue(string keyPath, string valueName)
|
|
||||||
{
|
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(keyPath, writable: true);
|
|
||||||
key?.DeleteValue(valueName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DeleteKey(string keyPath)
|
|
||||||
{
|
|
||||||
Registry.CurrentUser.DeleteSubKeyTree(keyPath, throwOnMissingSubKey: false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重试工具类
|
|
||||||
/// </summary>
|
|
||||||
public class RetryHelper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 进行重试
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="maxRetries"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool Retry(Action action, int maxRetries)
|
|
||||||
{
|
|
||||||
for (var attempt = 0; attempt < maxRetries; attempt++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
// 成功后返回 true
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (attempt == maxRetries - 1)
|
|
||||||
{
|
|
||||||
// 超过重试次数返回 false
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
using DispenserCommon.Interface;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取服务实例工具类
|
|
||||||
/// </summary>
|
|
||||||
public class ServiceLocator
|
|
||||||
{
|
|
||||||
private static IServiceProvider? _serviceProvider;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册 IServiceProvider
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="serviceProvider"></param>
|
|
||||||
public static void Initialize(IServiceProvider? serviceProvider, IServiceCollection services)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
|
|
||||||
// 注册服务定位器
|
|
||||||
foreach (var service in services)
|
|
||||||
{
|
|
||||||
var serviceType = service.ServiceType;
|
|
||||||
if (typeof(Instant).IsAssignableFrom(serviceType)) serviceProvider.GetService(service.ServiceType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取服务实例
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="ArgumentException"></exception>
|
|
||||||
public static T GetService<T>() where T : class
|
|
||||||
{
|
|
||||||
return _serviceProvider.GetService(typeof(T)) is not T service
|
|
||||||
? throw new ArgumentException(
|
|
||||||
$"{typeof(T)} needs to be registered in ConfigureServices within App.axaml.cs.")
|
|
||||||
: service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据指定的实现类型获取服务实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="impl"></param>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="ArgumentException"></exception>
|
|
||||||
public static T GetService<T>(Type impl) where T : class
|
|
||||||
{
|
|
||||||
var services = GetServices<T>();
|
|
||||||
|
|
||||||
return services.FirstOrDefault(x => x.GetType() == impl) ?? throw new ArgumentException(
|
|
||||||
$"{typeof(T)} needs to be registered in ConfigureServices within App.axaml.cs.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static object? GetService(Type type)
|
|
||||||
{
|
|
||||||
return _serviceProvider.GetService(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据类型获取服务实例
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static IEnumerable<T> GetServices<T>() where T : class
|
|
||||||
{
|
|
||||||
var services = _serviceProvider.GetServices<T>();
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 基于滑动时间窗口算法来判断指定时间窗口内是否存在目标值
|
|
||||||
/// </summary>
|
|
||||||
public class SlidingWindow(int milliseconds, int thresold = 1)
|
|
||||||
{
|
|
||||||
private readonly Queue<(DateTime time, object value)> _window = new();
|
|
||||||
private readonly TimeSpan _windowSize = TimeSpan.FromMilliseconds(milliseconds);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">待添加值</param>
|
|
||||||
public bool AllowValue(object value)
|
|
||||||
{
|
|
||||||
var currentTime = DateTime.Now;
|
|
||||||
|
|
||||||
while (_window.Count > 0 && currentTime - _window.Peek().time > _windowSize) _window.Dequeue();
|
|
||||||
|
|
||||||
if (_window.Count < thresold)
|
|
||||||
{
|
|
||||||
_window.Enqueue((currentTime, value));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断是否已经包含了该值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetValue">待匹配值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Contains(object targetValue)
|
|
||||||
{
|
|
||||||
return _window.Any(item => item.value.Equals(targetValue));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class TimeUtil
|
|
||||||
{
|
|
||||||
public static void Sleep(int milliseconds)
|
|
||||||
{
|
|
||||||
Thread.Sleep(milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前的时间戳
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static long Now()
|
|
||||||
{
|
|
||||||
return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前的时间,格式化为目标格式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GetNowTime(string format = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
{
|
|
||||||
return DateTime.Now.ToString(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 格式化时间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="time"></param>
|
|
||||||
/// <param name="format"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string FormatTime(long time, string format = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
{
|
|
||||||
var dateTime = DateTimeOffset.FromUnixTimeMilliseconds(time).DateTime;
|
|
||||||
return dateTime.ToString(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToTimeSpan(long time)
|
|
||||||
{
|
|
||||||
// 使用TimeSpan.FromMilliseconds来创建TimeSpan对象
|
|
||||||
var timeSpan = TimeSpan.FromMilliseconds(time);
|
|
||||||
|
|
||||||
// 获取小时、分钟和秒
|
|
||||||
var hours = timeSpan.Hours;
|
|
||||||
var minutes = timeSpan.Minutes;
|
|
||||||
var seconds = timeSpan.Seconds;
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
if (hours > 0)
|
|
||||||
{
|
|
||||||
sb.Append(hours).Append("小时");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minutes > 0)
|
|
||||||
{
|
|
||||||
sb.Append(minutes).Append('分');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seconds > 0)
|
|
||||||
{
|
|
||||||
sb.Append(seconds).Append('秒');
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将时间戳转为DateTime对象
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="timestamp"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static DateTime TimeStampToDateTime(long timestamp)
|
|
||||||
{
|
|
||||||
var dateTimeOffset = (timestamp + "").Length == 10
|
|
||||||
? DateTimeOffset.FromUnixTimeSeconds(timestamp)
|
|
||||||
: DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
|
|
||||||
|
|
||||||
return dateTimeOffset.DateTime;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
using Avalonia.Controls.Notifications;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class ToastUtil
|
|
||||||
{
|
|
||||||
private static WindowNotificationManager? _manager;
|
|
||||||
|
|
||||||
public static void SetManager(WindowNotificationManager manager)
|
|
||||||
{
|
|
||||||
_manager = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Info(string msg)
|
|
||||||
{
|
|
||||||
Log.Information(msg);
|
|
||||||
Dispatcher.UIThread.Invoke(() => { _manager?.Show(new Notification("", msg)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Error(string msg)
|
|
||||||
{
|
|
||||||
Log.Error(msg);
|
|
||||||
Dispatcher.UIThread.Invoke(() => { _manager?.Show(new Notification("", msg, NotificationType.Error)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Warn(string msg)
|
|
||||||
{
|
|
||||||
Log.Warning(msg);
|
|
||||||
Dispatcher.UIThread.Invoke(() => { _manager?.Show(new Notification("", msg, NotificationType.Warning)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Success(string msg)
|
|
||||||
{
|
|
||||||
Log.Information(msg);
|
|
||||||
Dispatcher.UIThread.Invoke(() => { _manager?.Show(new Notification("", msg, NotificationType.Success)); });
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public static class ValueUtil
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 将 int 转为 8 bit 的二进制字符串,前面不足的补 0
|
|
||||||
/// </summary>
|
|
||||||
public static string Int2BitStr(int val, int bitLen)
|
|
||||||
{
|
|
||||||
return new string(Int2BitChars(val, bitLen));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
/// <param name="bitLen"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static char[] Int2BitChars(int val, int bitLen)
|
|
||||||
{
|
|
||||||
// 直接将整数val转换为二进制字符串,不考虑十六进制。
|
|
||||||
var binaryString = Convert.ToString(val, 2);
|
|
||||||
|
|
||||||
// 如果val为负数,binaryString将包含二进制补码形式的字符串,其长度可能超过bitLen。
|
|
||||||
// 根据需要裁剪或填充字符串以适应指定的位长度(bitLen)。
|
|
||||||
if (binaryString.Length > bitLen)
|
|
||||||
// 对于负数,去除多余的前导'1'。
|
|
||||||
binaryString = binaryString.Substring(binaryString.Length - bitLen);
|
|
||||||
else
|
|
||||||
// 填充以达到所需长度。
|
|
||||||
binaryString = binaryString.PadLeft(bitLen, '0');
|
|
||||||
|
|
||||||
// 反转和转换为字符数组。
|
|
||||||
var chars = binaryString.Reverse().ToArray();
|
|
||||||
|
|
||||||
return chars;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int BitChars2Int(char[] chars)
|
|
||||||
{
|
|
||||||
return Convert.ToInt32(new string(chars), 2);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
using Avalonia.Controls;
|
|
||||||
|
|
||||||
namespace DispenserCommon.Utils;
|
|
||||||
|
|
||||||
public class WindowUtil
|
|
||||||
{
|
|
||||||
private static Window? _mainWindow;
|
|
||||||
|
|
||||||
public static void SetMainWindow(Window window)
|
|
||||||
{
|
|
||||||
_mainWindow = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dialog">弹窗</param>
|
|
||||||
/// <typeparam name="TD">弹窗类型</typeparam>
|
|
||||||
public static void ShowDialog<TD>(TD dialog) where TD : Window
|
|
||||||
{
|
|
||||||
if (_mainWindow == null) return;
|
|
||||||
dialog.ShowDialog(_mainWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dialog">弹窗</param>
|
|
||||||
/// <param name="action">弹窗回调</param>
|
|
||||||
/// <typeparam name="TD">弹窗类型</typeparam>
|
|
||||||
public static void ShowDialog<TD>(TD dialog, Action<TD> action) where TD : Window
|
|
||||||
{
|
|
||||||
if (_mainWindow == null) return;
|
|
||||||
dialog.ShowDialog(_mainWindow);
|
|
||||||
action(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dialog">弹窗实体</param>
|
|
||||||
/// <typeparam name="TD">弹窗类型</typeparam>
|
|
||||||
/// <typeparam name="TR">弹窗回调信息</typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static async Task<TR> ShowDialog<TD, TR>(TD dialog) where TD : Window
|
|
||||||
{
|
|
||||||
if (_mainWindow == null) return default;
|
|
||||||
return await dialog.ShowDialog<TR>(_mainWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 无返回值的弹窗
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TD"></typeparam>
|
|
||||||
public static void ShowDialog<TD>() where TD : Window
|
|
||||||
{
|
|
||||||
if (_mainWindow == null) return;
|
|
||||||
var dialog = Activator.CreateInstance<TD>();
|
|
||||||
dialog.ShowDialog(_mainWindow);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
using DispenserCommon.LogUtils;
|
|
||||||
using DispenserCore.Service;
|
|
||||||
using Serilog;
|
|
||||||
using Serilog.Core;
|
|
||||||
using Serilog.Events;
|
|
||||||
using Serilog.Exceptions;
|
|
||||||
|
|
||||||
namespace DispenserCommon.LogConfig;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志配置类
|
|
||||||
/// </summary>
|
|
||||||
public class LogConfiguration
|
|
||||||
{
|
|
||||||
private static LogParamsService _logParamsService = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取日志配置对象
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Logger GetLogger()
|
|
||||||
{
|
|
||||||
var logParams = _logParamsService.GetLogParams();
|
|
||||||
|
|
||||||
// 日志输出目录
|
|
||||||
var basePath = logParams!.Path ?? AppDomain.CurrentDomain.BaseDirectory;
|
|
||||||
|
|
||||||
// 适配最小日志级别
|
|
||||||
Enum.TryParse(logParams.Level, true, out LogEventLevel miniLevel);
|
|
||||||
|
|
||||||
return new LoggerConfiguration()
|
|
||||||
#if DEBUG
|
|
||||||
// 测试环境的话,输出debug级别
|
|
||||||
.MinimumLevel.Debug()
|
|
||||||
#else
|
|
||||||
// 其他环境输出info 级别
|
|
||||||
.MinimumLevel.Information()
|
|
||||||
#endif
|
|
||||||
.MinimumLevel.Override("Microsoft", miniLevel)
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.Enrich.WithExceptionDetails()
|
|
||||||
.WriteTo.Logger(
|
|
||||||
l =>
|
|
||||||
l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Debug)
|
|
||||||
.WriteTo.File(
|
|
||||||
Path.Combine(basePath, "logs", "debug", "debug-.log"),
|
|
||||||
rollingInterval: RollingInterval.Hour,
|
|
||||||
retainedFileCountLimit: 24
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.WriteTo.Logger(
|
|
||||||
l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information)
|
|
||||||
.WriteTo.File(
|
|
||||||
Path.Combine(basePath, "logs", "info", "info-.log"),
|
|
||||||
rollingInterval: RollingInterval.Hour,
|
|
||||||
retainedFileCountLimit: 72
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.WriteTo.Logger(
|
|
||||||
l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning)
|
|
||||||
.WriteTo.File(
|
|
||||||
Path.Combine(basePath, "logs", "warning", "warning-.log"),
|
|
||||||
rollingInterval: RollingInterval.Day,
|
|
||||||
retainedFileCountLimit: 30
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.WriteTo.Logger(
|
|
||||||
l => l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Error)
|
|
||||||
.WriteTo.File(
|
|
||||||
Path.Combine(basePath, "logs", "error", "error-.log"),
|
|
||||||
rollingInterval: RollingInterval.Day,
|
|
||||||
retainedFileCountLimit: 90
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// 测试环境同步输出到控制台
|
|
||||||
.WriteTo.Console()
|
|
||||||
.WriteTo.Sink(new DispenserLogSink())
|
|
||||||
.CreateLogger();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using DispenserCore.Model.DTO;
|
|
||||||
|
|
||||||
namespace DispenserCore.Context;
|
|
||||||
|
|
||||||
[DispenserCommon.Ioc.Component]
|
|
||||||
public class GlobalSessionHolder : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
private Session _session;
|
|
||||||
|
|
||||||
private Session Session
|
|
||||||
{
|
|
||||||
get => _session;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_session = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置用户会话
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="session"></param>
|
|
||||||
public void SetSession(Session session)
|
|
||||||
{
|
|
||||||
Session = session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取用户会话信息
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Session GetSession()
|
|
||||||
{
|
|
||||||
return Session;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Logged()
|
|
||||||
{
|
|
||||||
return Session != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清理会话会话
|
|
||||||
/// </summary>
|
|
||||||
public void ClearSession()
|
|
||||||
{
|
|
||||||
Session = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<LangVersion>preview</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Masuit.Tools.Core" Version="2.6.9.9"/>
|
|
||||||
<PackageReference Include="Stateless" Version="5.15.0"/>
|
|
||||||
<PackageReference Include="System.Security.Permissions" Version="8.0.0"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DispenserAlgorithm\DispenserAlgorithm.csproj"/>
|
|
||||||
<ProjectReference Include="..\DispenserCommon\DispenserCommon.csproj"/>
|
|
||||||
<ProjectReference Include="..\DispenserHal\DispenserHal.csproj"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Flow\Core\Node.cs"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="DispenserVision.Halcon">
|
|
||||||
<HintPath>..\DispenserDesktop\Libs\DispenserVision.Halcon.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,52 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using DispenserCommon.Ioc;
|
|
||||||
|
|
||||||
namespace DispenserCore.IOC;
|
|
||||||
|
|
||||||
public class IocScanner
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 扫描所有的类,将所有带有Component的类注册到IOC容器中
|
|
||||||
/// </summary>
|
|
||||||
public static List<IocService> Scan()
|
|
||||||
{
|
|
||||||
var components = GetAssemblies()
|
|
||||||
.SelectMany(a => a.GetTypes()
|
|
||||||
.Where(t => t.GetCustomAttributes(typeof(Component), true).Length > 0))
|
|
||||||
.ToList();
|
|
||||||
List<IocService> services = [];
|
|
||||||
components.ForEach(component =>
|
|
||||||
{
|
|
||||||
var attribute = component.GetCustomAttribute<Component>();
|
|
||||||
services.Add(new IocService(attribute?.Type ?? component, component));
|
|
||||||
});
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<Assembly> GetAssemblies()
|
|
||||||
{
|
|
||||||
var assemblies = new List<Assembly>();
|
|
||||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
||||||
{
|
|
||||||
var name = assembly.GetName().Name;
|
|
||||||
if (name != null && name.ToLower().Contains("dispenser")) GetReferenceAssemblies(assembly, assemblies);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetReferenceAssemblies(Assembly assembly, ICollection<Assembly> assemblies)
|
|
||||||
{
|
|
||||||
foreach (var assemblyName in assembly.GetReferencedAssemblies())
|
|
||||||
{
|
|
||||||
var name = assemblyName.Name;
|
|
||||||
if (name != null && name.ToLower().Contains("dispenser"))
|
|
||||||
{
|
|
||||||
var ass = Assembly.Load(assemblyName);
|
|
||||||
if (assemblies.Contains(ass)) continue;
|
|
||||||
assemblies.Add(ass);
|
|
||||||
GetReferenceAssemblies(ass, assemblies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DispenserCore.IOC;
|
|
||||||
|
|
||||||
public class IocService(Type type, Type implement)
|
|
||||||
{
|
|
||||||
public Type Type => type;
|
|
||||||
|
|
||||||
public Type Implement => implement;
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System.IO.Compression;
|
|
||||||
using DispenserCore.Service;
|
|
||||||
using Quartz;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCore.Job;
|
|
||||||
|
|
||||||
public class LogUploadJob : IJob
|
|
||||||
{
|
|
||||||
private static LogParamsService _logParamsService = new();
|
|
||||||
|
|
||||||
public Task Execute(IJobExecutionContext context)
|
|
||||||
{
|
|
||||||
var logParams = _logParamsService.GetLogParams();
|
|
||||||
|
|
||||||
var basePath = logParams!.Path ?? AppDomain.CurrentDomain.BaseDirectory;
|
|
||||||
//前一天的日期
|
|
||||||
var date = DateTime.Now.AddDays(-1).ToString("yyyyMMdd");
|
|
||||||
var levels = logParams.UploadLevels!.Split(",").ToList();
|
|
||||||
string? sourceFolder = null;
|
|
||||||
string? zipFilePath = null;
|
|
||||||
foreach (var level in levels)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sourceFolder = Path.Combine(basePath, "logs", level);
|
|
||||||
zipFilePath = Path.Combine(sourceFolder, $"{level}-{date}.log");
|
|
||||||
var searchPattern = $"*{level}-{date}*.log";
|
|
||||||
using (var zipFile = new FileStream(zipFilePath, FileMode.Create))
|
|
||||||
{
|
|
||||||
using (var archive = new ZipArchive(zipFile, ZipArchiveMode.Create))
|
|
||||||
{
|
|
||||||
foreach (var file in Directory.GetFiles(sourceFolder, searchPattern))
|
|
||||||
{
|
|
||||||
var fileName = Path.GetFileName(file);
|
|
||||||
var entry = archive.CreateEntry(fileName);
|
|
||||||
using (var entryStream = entry.Open())
|
|
||||||
using (var fileStream = File.OpenRead(file))
|
|
||||||
{
|
|
||||||
fileStream.CopyTo(entryStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO 上传到云端
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, "日志{0}上传失败", sourceFolder);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (zipFilePath != null && File.Exists(zipFilePath)) File.Delete(zipFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
using DispenserCommon.Events;
|
|
||||||
using DispenserCommon.scheduler;
|
|
||||||
using DispenserCore.Service;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace DispenserCore.Job;
|
|
||||||
|
|
||||||
public class SchedulerManager
|
|
||||||
{
|
|
||||||
private static readonly LogParamsService LogParamsService = new();
|
|
||||||
|
|
||||||
public static async Task<bool> StartAll()
|
|
||||||
{
|
|
||||||
Log.Information("启动所有定时任务");
|
|
||||||
EventBus<string>.Publish(EventType.SetupNotify, "正在启动定时任务");
|
|
||||||
|
|
||||||
var logParams = LogParamsService.GetLogParams();
|
|
||||||
await SchedulerHelper.Start();
|
|
||||||
|
|
||||||
await SchedulerHelper.SchedulerCorn<LogUploadJob>(null, logParams?.UploadCorn);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async void Shutdown()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Log.Information("关闭任务调度器");
|
|
||||||
await SchedulerHelper.Shutdown();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error(e, "关闭任务调度器");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DispenserCore.Model.DTO;
|
|
||||||
|
|
||||||
public class QueryOperationLog : QueryPage
|
|
||||||
{
|
|
||||||
public string? UserName { get; set; }
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.DTO;
|
|
||||||
|
|
||||||
public class QueryPage : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
private int _currentPage = 1;
|
|
||||||
|
|
||||||
private int _pageSize = 10;
|
|
||||||
|
|
||||||
private DateTime? _startTime;
|
|
||||||
|
|
||||||
private DateTime? _endTime;
|
|
||||||
|
|
||||||
public int CurrentPage
|
|
||||||
{
|
|
||||||
get => _currentPage;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_currentPage = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int PageSize
|
|
||||||
{
|
|
||||||
get => _pageSize;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_pageSize = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime? StartTime
|
|
||||||
{
|
|
||||||
get => _startTime;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_startTime = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime? EndTime
|
|
||||||
{
|
|
||||||
get => _endTime;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_endTime = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.DTO;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户登录会话信息
|
|
||||||
/// </summary>
|
|
||||||
public class Session(User user)
|
|
||||||
{
|
|
||||||
// 用户信息
|
|
||||||
public User User { get; set; } = user;
|
|
||||||
|
|
||||||
// 登录时间
|
|
||||||
public DateTime LoginTime { get; set; } = DateTime.Now;
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using DispenserCore.Model.Enum;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
[Table("camera_internal_params"), Description("相机内部参数")]
|
|
||||||
public class CameraInternalParams : Entity
|
|
||||||
{
|
|
||||||
[Column("type"), Description("参数类型"), Hide]
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
[Column("balance_ratio"), Description("白平衡值")]
|
|
||||||
public int BalanceRatio { get; set; }
|
|
||||||
|
|
||||||
[Column("exposure_time"), Description("曝光时间"), Property(Min = 15, Max = 2000)]
|
|
||||||
public int ExposureTime { get; set; }
|
|
||||||
|
|
||||||
[Column("exposure_auto"), Description("自动曝光")]
|
|
||||||
public bool ExposureAuto { get; set; }
|
|
||||||
|
|
||||||
[Column("gain"), Description("增益")] public float Gain { get; set; }
|
|
||||||
|
|
||||||
[Column("gain_auto"), Description("自动增益")]
|
|
||||||
public GainAutoEnum GainAuto { get; set; }
|
|
||||||
|
|
||||||
[Column("black_level"), Description("灰度值")]
|
|
||||||
public float BlackLevel { get; set; }
|
|
||||||
|
|
||||||
[Column("black_level_enable"), Description("黑电平调节使能")]
|
|
||||||
public bool BlackLevelEnable { get; set; }
|
|
||||||
|
|
||||||
[Column("balance_white_auto"), Description("自动白平衡")]
|
|
||||||
public bool BalanceWhiteAuto { get; set; }
|
|
||||||
|
|
||||||
[Column("resulting_frame_rate"), Description("实际采集帧率fps")]
|
|
||||||
public float ResultingFrameRate { get; set; }
|
|
||||||
|
|
||||||
[Column("gamma"), Description("gamma值"), Property(Min = 0, Max = 4)]
|
|
||||||
public float Gamma { get; set; }
|
|
||||||
|
|
||||||
[Column("gamma_enable"), Description("是否gamma使能")]
|
|
||||||
public bool GammaEnable { get; set; }
|
|
||||||
|
|
||||||
[Column("line_mode"), Description("IO 模式")]
|
|
||||||
public LineModeEnum LineMode { get; set; }
|
|
||||||
|
|
||||||
[Column("line_selector"), Description("IO 选择")]
|
|
||||||
public LineSelectorEnum LineSelector { get; set; }
|
|
||||||
|
|
||||||
[Column("trigger_activation"), Description("触发激活")]
|
|
||||||
public TriggerActivationEnum TriggerActivation { get; set; }
|
|
||||||
|
|
||||||
[Column("trigger_mode"), Description("触发模式")]
|
|
||||||
public TriggerModeEnum TriggerMode { get; set; }
|
|
||||||
|
|
||||||
[Column("trigger_source"), Description("触发源")]
|
|
||||||
public TriggerSourceEnum TriggerSource { get; set; }
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 相机参数
|
|
||||||
/// </summary>
|
|
||||||
[Table("camera_params")]
|
|
||||||
[Description("相机参数")]
|
|
||||||
public class CameraParams : Entity
|
|
||||||
{
|
|
||||||
[Column("camera_sn"), Description("相机序列号")]
|
|
||||||
public string CameraSn { get; set; }
|
|
||||||
|
|
||||||
[Column("sdk"), Description("SDK")] public string Sdk { get; set; }
|
|
||||||
|
|
||||||
[Column("dll"), Description("DLL")] public string Dll { get; set; }
|
|
||||||
|
|
||||||
[Column("scale_ratio"), Description("视频缩放比例")]
|
|
||||||
public double ScaleRatio { get; set; }
|
|
||||||
|
|
||||||
[Column("pixel_length"), Description("像素长度"), Property(Format = "0.########")]
|
|
||||||
public double PixelLength { get; set; }
|
|
||||||
|
|
||||||
[Column("deflect_angle"), Description("相机偏转角度"), Property(Format = "0.#####")]
|
|
||||||
public double DeflectAngle { get; set; }
|
|
||||||
|
|
||||||
[Column("camera_inner_param_template"), Description("相机内参模板")]
|
|
||||||
public string CameraInnerParamTemplate { get; set; }
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据库实体的父类
|
|
||||||
/// </summary>
|
|
||||||
public class Entity
|
|
||||||
{
|
|
||||||
[PrimaryKey] public string? Id { get; set; }
|
|
||||||
|
|
||||||
[Column("create_time")] public DateTime CreateTime { get; set; } = DateTime.Now;
|
|
||||||
|
|
||||||
[Column("update_time")] public DateTime UpdateTime { get; set; } = DateTime.Now;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日志参数
|
|
||||||
/// </summary>
|
|
||||||
[Table("log_params")]
|
|
||||||
[Description("日志参数")]
|
|
||||||
public class LogParams : Entity
|
|
||||||
{
|
|
||||||
[Column("level"), Description("日志级别")] public string? Level { get; set; }
|
|
||||||
|
|
||||||
[Column("path"), Description("日志存放路径")]
|
|
||||||
public string? Path { get; set; }
|
|
||||||
|
|
||||||
[Column("upload_corn"), Description("日志上传时间")]
|
|
||||||
public string? UploadCorn { get; set; }
|
|
||||||
|
|
||||||
[Column("upload_levels"), Description("日志上传级别")]
|
|
||||||
public string? UploadLevels { get; set; }
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
[Table("minio_params"), Description("MinIO参数")]
|
|
||||||
public class MinioParams : Entity
|
|
||||||
{
|
|
||||||
[Column("minio_access_key"), Description("Minio AccessKey")]
|
|
||||||
public string MinioAccessKey { get; set; }
|
|
||||||
|
|
||||||
[Column("minio_secret_key"), Description("Minio SecretKey")]
|
|
||||||
public string MinioSecretKey { get; set; }
|
|
||||||
|
|
||||||
[Column("minio_bucket"), Description("Minio Bucket")]
|
|
||||||
public string MinioBucket { get; set; }
|
|
||||||
|
|
||||||
[Column("minio_endpoint"), Description("Minio Endpoint")]
|
|
||||||
public string MinioEndpoint { get; set; }
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
[Table("mqtt_params"), Description("Mqtt连接参数")]
|
|
||||||
public class MqttParams : Entity
|
|
||||||
{
|
|
||||||
[Column("server_address"), Description("服务器地址")]
|
|
||||||
public string ServerAddress { get; set; }
|
|
||||||
|
|
||||||
[Column("port"), Description("端口")] public int Port { get; set; }
|
|
||||||
|
|
||||||
[Column("user_name"), Description("用户名")]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
|
|
||||||
[Column("password"), Description("密码"), Property(IsPassword = true)]
|
|
||||||
public string Password { get; set; }
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户操作日志
|
|
||||||
/// </summary>
|
|
||||||
[Table("operation_logs")]
|
|
||||||
public class OperationLog : Entity
|
|
||||||
{
|
|
||||||
[Column("user_id"), Description("用户ID"), Hide]
|
|
||||||
public string UserId { get; set; }
|
|
||||||
|
|
||||||
[Column("user_name"), Description("用户名")]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
|
|
||||||
[Column("action"), Description("操作")] public string Action { get; set; }
|
|
||||||
|
|
||||||
[Column("params"), Description("参数"), Hide]
|
|
||||||
public string? Params { get; set; }
|
|
||||||
|
|
||||||
[Column("exception"), Description("异常信息"), Hide]
|
|
||||||
public string? Exception { get; set; }
|
|
||||||
|
|
||||||
[Column("operate_time"), Description("操作时间")]
|
|
||||||
public DateTime OperateTime { get; set; }
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using DispenserCommon.Atrributes;
|
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 系统参数
|
|
||||||
/// </summary>
|
|
||||||
[Table("system_params")]
|
|
||||||
[Description("系统参数")]
|
|
||||||
public class SystemParams : Entity
|
|
||||||
{
|
|
||||||
[Column("device_type"), Description("设备类型")]
|
|
||||||
public string? DeviceType { get; set; }
|
|
||||||
|
|
||||||
[Column("version"), Description("版本号"), Property(IsReadOnly = true)]
|
|
||||||
public string? Version { get; set; }
|
|
||||||
|
|
||||||
[Column("name"), Description("名称")] public string? Name { get; set; }
|
|
||||||
|
|
||||||
[Column("acs_ip"), Description("ACS 控制器IP")]
|
|
||||||
public string AcsIp { get; set; }
|
|
||||||
|
|
||||||
[Column("image_storage_path"), Description("照片存储路径")]
|
|
||||||
public string? ImageStoragePath { get; set; }
|
|
||||||
|
|
||||||
[Column("camera_viewer_storage_path"), Description("相机预览控件图片存储路径")]
|
|
||||||
public string? CameraViewerStoragePath { get; set; }
|
|
||||||
|
|
||||||
[Column("enable_auto_clear_image"), Description("是否自动清除历史照片")]
|
|
||||||
public bool EnableAutoClearImage { get; set; }
|
|
||||||
|
|
||||||
[Column("retained_day"), Description("照片保留天数")]
|
|
||||||
public int RetainedDay { get; set; }
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using SQLite;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Entity;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户信息
|
|
||||||
/// </summary>
|
|
||||||
[Table("users")]
|
|
||||||
public class User : Entity
|
|
||||||
{
|
|
||||||
[Column("user_name")] public string UserName { get; set; }
|
|
||||||
|
|
||||||
[Column("nick_name")] public string NickName { get; set; }
|
|
||||||
|
|
||||||
[Column("password")] public string Password { get; set; }
|
|
||||||
|
|
||||||
[Column("role")] public int Role { get; set; }
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum ChipColorEnum
|
|
||||||
{
|
|
||||||
R = 1,
|
|
||||||
G = 2,
|
|
||||||
B = 3
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum DirectionEnum
|
|
||||||
{
|
|
||||||
[Description("行方向")] ROW = 1,
|
|
||||||
[Description("列方向")] COLUMN = 2,
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum GainAutoEnum
|
|
||||||
{
|
|
||||||
Off,
|
|
||||||
Once,
|
|
||||||
Continuous
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生产作业状态
|
|
||||||
/// </summary>
|
|
||||||
public enum JobStateEnum
|
|
||||||
{
|
|
||||||
[Description("待生产")] Waiting = 0,
|
|
||||||
|
|
||||||
[Description("生产中")] Producing = 1,
|
|
||||||
|
|
||||||
[Description("已完成")] Completed = 2,
|
|
||||||
|
|
||||||
[Description("已取消")] Canceled = 3,
|
|
||||||
|
|
||||||
[Description("生产异常")] Abnormal = 4,
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum LineModeEnum
|
|
||||||
{
|
|
||||||
Strobe
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum LineSelectorEnum
|
|
||||||
{
|
|
||||||
Line0,
|
|
||||||
Line1,
|
|
||||||
Line2,
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 动打策略
|
|
||||||
/// </summary>
|
|
||||||
public enum MixBinStrategyEnum
|
|
||||||
{
|
|
||||||
[Description("混Bin")] Mix = 1,
|
|
||||||
[Description("不混")] NotMix = 2
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum PcbDetectStrategyEnum
|
|
||||||
{
|
|
||||||
[Description("Mark点识别")]ByMark = 1,
|
|
||||||
[Description("焊点模板匹配")]TemplateMatch = 2,
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 扫码枪接口类型
|
|
||||||
/// </summary>
|
|
||||||
public enum ScannerInterfaceEnum
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 串口
|
|
||||||
/// </summary>
|
|
||||||
[Description("串口")] Serial,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TCP
|
|
||||||
/// </summary>
|
|
||||||
[Description("网口")] Tcp,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// USB
|
|
||||||
/// </summary>
|
|
||||||
[Description("USB")] Usb,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 蓝牙
|
|
||||||
/// </summary>
|
|
||||||
[Description("蓝牙")] Bluetooth,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 无线
|
|
||||||
/// </summary>
|
|
||||||
[Description("无线")] Wireless
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 基材类型
|
|
||||||
/// </summary>
|
|
||||||
public enum SubstrateTypeEnum
|
|
||||||
{
|
|
||||||
[Description("PCB")] PCB = 1,
|
|
||||||
[Description("玻璃")] Glass = 2
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum TlsProtocolsEnum
|
|
||||||
{
|
|
||||||
TLS_1_2,
|
|
||||||
TLS_1_3
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum TriggerActivationEnum
|
|
||||||
{
|
|
||||||
RisingEdge,
|
|
||||||
FallingEdge,
|
|
||||||
LevelHigh,
|
|
||||||
LevelLow,
|
|
||||||
AnyEdge
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum TriggerModeEnum
|
|
||||||
{
|
|
||||||
Off,
|
|
||||||
On
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum TriggerSourceEnum
|
|
||||||
{
|
|
||||||
Software,
|
|
||||||
Line0,
|
|
||||||
Line2,
|
|
||||||
Counter0,
|
|
||||||
Anyway
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace DispenserCore.Model.Enum;
|
|
||||||
|
|
||||||
public enum WaferScanStrategyEnum
|
|
||||||
{
|
|
||||||
[Description("快速二值化")]FastThreshold = 1,
|
|
||||||
[Description("模板匹配")]TemplateMatch = 2,
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue